自定义消费者的序列化

问题描述 投票:0回答:1

我正在为 Spigot 1.20.4 (Java) 开发一个雕像插件,用于创建 NPC 雕像。目前,当您创建雕像时,您可以使用消费者来定义右键单击该 NPC 时会发生什么。

Statue.StatueBuilder builder = new Statue.StatueBuilder(entityType)
.setName("Test")
.setOnClick(connectionPlayer -> System.out.println("TEST " + new Random().nextInt()));
 Statue statue = builder.build();

#setOnClick 接受 StatueAction,其定义为:

public interface StatueAction {
    void perform(ConnectionPlayer player);
}

我需要保存这些数据(yml、json 等),这样当服务器重新启动时,雕像将再次生成。但是,我无法序列化消费者。尝试使用 YML 和 JSON。我明白为什么,但不知道如何解决它。

关于如何将 onClick 操作保存到文件有什么想法吗?或者,如果这不是一个好方法,我可能会采取其他方法来实现类似的目标,有什么想法吗? 我确实研究了如何序列化 lambda?,但是似乎这些都不能正常工作(对我来说),这意味着我一定做错了一些事情。

这是我目前正在尝试序列化它的方式

StatueAction<ConnectionPlayer> r = (connectionPlayer) -> System.out.println("Hello");
Statue.StatueBuilder builder = new Statue.StatueBuilder(entityType).setName("Test").setOnClick(r);
Statue statue = builder.build();
statue.spawn(player.getLocation());
statue.createDefaultAttribs();
System.out.println(statue.serialize());

输出是

{"name":"Test","entityType":"ARMOR_STAND","entityUUID":"6c2a484c-3168-4fb8-a3ee-8c2d93bddf1d","textDisplaysID":[],"onClick":{}}

Statue序列化方法定义为

 public static class StatueSerializer implements JsonSerializer<Statue> {
        @Override
        public JsonElement serialize(Statue statue, Type type, JsonSerializationContext jsonSerializationContext) {
            JsonObject jsonObject = new JsonObject();
            jsonObject.addProperty("name", statue.name);
            jsonObject.addProperty("entityType", statue.entityType.name());
            jsonObject.addProperty("entityUUID", statue.getEntityUUID().toString());
            jsonObject.add("textDisplaysID", jsonSerializationContext.serialize(statue.getTextDisplaysID()));

            // Serialize the CustomAction using its own serialization logic
            jsonObject.add("onClick", jsonSerializationContext.serialize(statue.getOnClick()));

            return jsonObject;
        }
    }

public String serialize() {
    Gson gson = new GsonBuilder()
            .registerTypeAdapter(Statue.class, new Statue.StatueSerializer())
            .create();
    return gson.toJson(this);
}
java serialization gson spigot
1个回答
0
投票

如果您只有静态数量的可能操作,那么您可以使用一个枚举,其常量代表这些操作,而不是使用接口,然后仅序列化操作的名称/常量名称。
这类似于 Minecraft 本身如何序列化文本组件的

clickEvent
hoverEvent
操作。

另一种选择可能是向您的

serialize
接口添加
StatueAction
方法,以便实现可以序列化所有必要的数据。但是,您还必须包含一些标识符,并拥有一些“注册表”,在反序列化时,根据 JSON 数据中的标识符查找操作类。查看有关 Gson 和多态性的其他问题。
避免使用
Class.forName
进行反序列化,即使它看起来很方便,因为如果 JSON 数据可能以某种方式受到不受信任的用户的影响,那么他们将允许他们创建可能被利用的任意类的实例。

© www.soinside.com 2019 - 2024. All rights reserved.