feat: implemented SkinStorage

This commit is contained in:
Andrey Terentev 2025-03-10 21:22:31 +07:00
parent 9b184affe5
commit 8cc19c68c6
4 changed files with 108 additions and 0 deletions

View File

@ -14,8 +14,10 @@ import ru.dragonestia.msb3.api.player.MsbPlayer;
import ru.dragonestia.msb3.api.player.PlayerContextManager;
import ru.dragonestia.msb3.api.player.defaults.KeyedBossBarContext;
import ru.dragonestia.msb3.api.player.defaults.NavigatorContext;
import ru.dragonestia.msb3.api.player.defaults.TalksContext;
import ru.dragonestia.msb3.api.resource.DialogueResources;
import ru.dragonestia.msb3.api.resource.MonologueResources;
import ru.dragonestia.msb3.api.skin.SkinStorage;
import ru.dragonestia.msb3.api.ui.BlackScreen;
import ru.dragonestia.msb3.api.ui.bossbar.KeyedBossBars;
import ru.dragonestia.msb3.api.ui.navigator.Navigators;
@ -85,6 +87,8 @@ public final class ServerBootstrap {
initializer.onResourcePackCompiled(Resources.getResourcePack());
initPlayerContextManager();
initDefaultSkins();
}
private void initDefaultModules() {
@ -178,5 +182,10 @@ public final class ServerBootstrap {
// Default contexts
PlayerContextManager.registerContext(KeyedBossBarContext.class, KeyedBossBarContext::new);
PlayerContextManager.registerContext(NavigatorContext.class, NavigatorContext::new);
PlayerContextManager.registerContext(TalksContext.class, TalksContext::new);
}
private void initDefaultSkins() {
SkinStorage.loadSkin(SkinStorage.DEFAULT, ResourceFromJar.of("skins/default.msb3skin"));
}
}

View File

@ -0,0 +1,45 @@
package ru.dragonestia.msb3.api.skin;
import com.google.gson.Gson;
import lombok.Getter;
import net.minestom.server.entity.PlayerSkin;
import team.unnamed.creative.base.Writable;
public class SkinData {
private final static Gson gson = new Gson();
@Getter private final String texture;
@Getter private final String signature;
private transient PlayerSkin skin;
public SkinData(String texture, String signature) {
this.texture = texture;
this.signature = signature;
}
public synchronized PlayerSkin getSkin() {
if (skin == null) {
skin = new PlayerSkin(texture, signature);
}
return skin;
}
public String serialize() {
return gson.toJson(new Data(signature, texture));
}
public static SkinData fromSkin(PlayerSkin skin) {
return new SkinData(skin.textures(), skin.signature());
}
public static SkinData fromWriteable(Writable writable) {
try {
return gson.fromJson(writable.toUTF8String(), SkinData.class);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public record Data(String signature, String texture) {}
}

View File

@ -0,0 +1,53 @@
package ru.dragonestia.msb3.api.skin;
import lombok.experimental.UtilityClass;
import lombok.extern.log4j.Log4j2;
import net.kyori.adventure.key.Key;
import net.minestom.server.entity.PlayerSkin;
import team.unnamed.creative.base.Writable;
import java.io.File;
import java.io.FileWriter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Log4j2
@UtilityClass
public class SkinStorage {
public final static Key DEFAULT = Key.key("msb3", "default");
private final Map<Key, SkinData> skins = new ConcurrentHashMap<>();
public void saveSkinToFile(PlayerSkin skin, File file) {
try (var writer = new FileWriter(file)) {
writer.write(SkinData.fromSkin(skin).serialize());
} catch (Exception ex) {
throw new RuntimeException(ex);
}
log.info("Saved skin to {}", file.getAbsolutePath());
}
public void loadSkin(Key key, Writable writable) {
var prev = skins.put(key, SkinData.fromWriteable(writable));
if (prev != null) {
log.warn("Detected duplicate skin key: {}", key.asString());
}
}
public boolean existsSkin(Key key) {
return skins.containsKey(key);
}
public PlayerSkin getSkin(Key key) {
var skin = skins.get(key);
if (skin == null) {
log.warn("No skin for key '{}'. Using default", key.asString());
return skins.get(DEFAULT).getSkin();
}
return skin.getSkin();
}
}

View File

@ -0,0 +1 @@
{"signature":"nPVllmMmLrovNFJJDaQvbvukS0j1o0D98eYmEQ9jR514R4Xrk64Kc4+6CJQ/CNyGpkGdYQBGvH7Ki1HtKiF2s1wqKnQOKUiIHJFZr8ACkTnNWrwVMZZLFsjvZK9Q9t+xBcuTa9JCX9eumffwIxpJ6UYL496AZQUB9KqKEdgg9Iuz+fybsv+hVLwefvtGlg+OjHfT67NmFYqBt+jB/1JX29a1vS7nL/gqVn3BJvpb8Hj2ao6Lp/wqaLg9PRFEjvVUHWACSztQNGEAj1r3GX1BGzTdJ4xh3mEfoF0Q8KfzMMPKlJR3VG+ayDJnrMmZCqXLh0a4GrRC3Yu9IGS7U38JlDnCQIPj1Mj8K60yhr9qwz9QLRKdWeYOt62PiAG0i8Qo3qtS9chgjCBbgyQ2S73AsxSVgUBNRUvsAMf65ODfpKd90MIkjtNM3qdekeP90e6xQEYMWeyf7hAyoi5DFp0eF70WI8xU//VvlV4676MqJZ077Fhd9IbsSC/lFOCDbb6+5hEMDaJenFMlacPd4/HaGCgUNDaaVTl5wAHxjWRFvQQMQ4piobeHtRVtCLX02554HuCn7l6JmRj19Slel0Of4dACv/tMq1MzNzlaOT3tjmJQ5j6s1jPBWVc4cKvuHwhfod60JuvOtJK8kTbJn8IQvGE0pBVT8KJb/hd3qIVR2As\u003d","texture":"ewogICJ0aW1lc3RhbXAiIDogMTc0MTYxNTkyNTYyMSwKICAicHJvZmlsZUlkIiA6ICJiMTI4ZDVhOTA4MTE0ZDdmYmNjOTdlNGE4MDUwOTFlMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJ0ZXJlbnRldiIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS80ZWY1ZDBiMTkwMjU2ODlhZWRiNDcwZThiYmM2MmZmZTM0ZDEwZjEyMjhmZTg0ZTU2MjNkYTFmYjcxN2RhODg0IgogICAgfQogIH0KfQ\u003d\u003d"}