From 4316f47ef699e6ea62b5f5ecade9e4d71480653b Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 19 Jun 2026 21:11:44 +0200 Subject: [PATCH 01/26] [KillTheRNG] Improve squid rng --- .../java/com/minecrafttas/tasmod/TASmod.java | 4 ++++ .../tasmod/ktrng/builtin/SquidRNG.java | 16 ++++++++++++++++ .../mixin/killtherng/MixinEntitySquid.java | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 src/main/java/com/minecrafttas/tasmod/ktrng/builtin/SquidRNG.java diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 3f05ad30..a7ce4939 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -31,6 +31,7 @@ import com.minecrafttas.tasmod.handlers.PlayUntilHandler; import com.minecrafttas.tasmod.ktrng.GlobalRNG; import com.minecrafttas.tasmod.ktrng.builtin.MathRNG; +import com.minecrafttas.tasmod.ktrng.builtin.SquidRNG; import com.minecrafttas.tasmod.ktrng.builtin.WorldSeedRNG; import com.minecrafttas.tasmod.ktrng.events.KillTheRNGMonitor; import com.minecrafttas.tasmod.ktrng.handlers.UUIDHandler; @@ -110,6 +111,8 @@ public class TASmod implements ModInitializer, EventServerStart, EventServerInit public static WorldSeedRNG worldSeedRandomness = new WorldSeedRNG(0); + public static SquidRNG squidRNG = new SquidRNG(0L); + public static KillTheRNGMonitor debugRand = new KillTheRNGMonitor(); public static UUIDHandler uuidHandler = new UUIDHandler(); @@ -173,6 +176,7 @@ public void onServerStart(MinecraftServer server) { EventListenerRegistry.register(globalRandomness); } mathRandomness = new MathRNG(0); + squidRNG.setSeed(globalRandomness.getCurrentSeed() + 1000L); } @Override diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/SquidRNG.java b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/SquidRNG.java new file mode 100644 index 00000000..0eb6ba29 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/SquidRNG.java @@ -0,0 +1,16 @@ +package com.minecrafttas.tasmod.ktrng.builtin; + +import com.minecrafttas.tasmod.ktrng.RandomBase; + +public class SquidRNG extends RandomBase { + + public SquidRNG(long l) { + super(l); + } + + @Override + public String getExtensionName() { + return "SquidRNG"; + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntitySquid.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntitySquid.java index b719bd42..f0658676 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntitySquid.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntitySquid.java @@ -6,6 +6,7 @@ import org.spongepowered.asm.mixin.injection.At; import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import com.minecrafttas.tasmod.TASmod; import net.minecraft.entity.passive.EntitySquid; @@ -14,6 +15,9 @@ public class MixinEntitySquid { @WrapWithCondition(method = "", at = @At(value = "INVOKE", target = "Ljava/util/Random;setSeed(J)V")) public boolean remove_setSeed(Random rand, long seed) { + if (TASmod.squidRNG.nextInt(1000) == 0) { + TASmod.LOGGER.error("SQUIDS ARE EVIL!!"); + } return false; } } From 959c0fa482ef46e67eb724851a9845d5d681846e Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 19 Jun 2026 21:11:44 +0200 Subject: [PATCH 02/26] [Savestates] First look at storing entity AI in savestates --- build.gradle | 2 +- .../java/com/minecrafttas/tasmod/TASmod.java | 3 + .../SavestateStorageExtensionBase.java | 9 +- .../SavestateStorageExtensionRegistry.java | 4 +- .../storage/builtin/ClientMotionStorage.java | 4 +- .../storage/builtin/EntityAiTaskStorage.java | 161 ++++++++++++++++++ .../BlockPosTypeAdapterFactory.java | 41 +++++ .../EntityClassTypeAdapterFactory.java | 49 ++++++ .../EntityTypeAdapterFactory.java | 93 ++++++++++ .../typeadapters/ItemTypeAdapter.java | 25 +++ .../typeadapters/WorldTypeAdapterFactory.java | 72 ++++++++ .../minecrafttas/tasmod/util/JsonUtils.java | 14 +- src/main/resources/tasmod.accesswidener | 8 + 13 files changed, 471 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/BlockPosTypeAdapterFactory.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityTypeAdapterFactory.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/WorldTypeAdapterFactory.java diff --git a/build.gradle b/build.gradle index 9d749c73..150a6c9d 100644 --- a/build.gradle +++ b/build.gradle @@ -53,7 +53,7 @@ dependencies { // tasmod dependencies embed "com.dselent:bigarraylist:1.6" embed "com.github.KaptainWutax:SeedUtils:b6a383113c" - + // loom dependencies minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings ploceus.mcpMappings(project.mcp_channel, project.mcp_mcversion, project.mcp_build) diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index a7ce4939..d6ae3a97 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -43,6 +43,7 @@ import com.minecrafttas.tasmod.savestates.handlers.SavestateGuiHandlerServer; import com.minecrafttas.tasmod.savestates.handlers.SavestateResourcePackHandler; import com.minecrafttas.tasmod.savestates.storage.builtin.ClientMotionStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityAiTaskStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityBatSpawnPositionStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.EntitySquidRotationStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityTickTimersStorage; @@ -106,6 +107,7 @@ public class TASmod implements ModInitializer, EventServerStart, EventServerInit public static EntityTickTimersStorage entityTickTimers = new EntityTickTimersStorage(); public static EntityBatSpawnPositionStorage entityBatSpawnPositionStorage = new EntityBatSpawnPositionStorage(); public static EntitySquidRotationStorage entitySquidRotationStorage = new EntitySquidRotationStorage(); + public static EntityAiTaskStorage entityAiTaskStorage = new EntityAiTaskStorage(); public static MathRNG mathRandomness = new MathRNG(0); @@ -246,6 +248,7 @@ private void registerSavestateStorage() { TASmodAPIRegistry.SAVESTATE_STORAGE.register(entityTickTimers); TASmodAPIRegistry.SAVESTATE_STORAGE.register(entityBatSpawnPositionStorage); TASmodAPIRegistry.SAVESTATE_STORAGE.register(entitySquidRotationStorage); + TASmodAPIRegistry.SAVESTATE_STORAGE.register(entityAiTaskStorage); } public static MinecraftServer getServerInstance() { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionBase.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionBase.java index 3e1b5b3a..3c70ebee 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionBase.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionBase.java @@ -15,12 +15,17 @@ public abstract class SavestateStorageExtensionBase implements Registerable { protected final Logger logger = TASmod.LOGGER; - protected final Gson json = JsonUtils.getJsonInstance(); + protected final Gson gsonInstance; public final Path fileName; - public SavestateStorageExtensionBase(String fileName) { + public SavestateStorageExtensionBase(String filename) { + this(filename, JsonUtils.getGsonInstance()); + } + + public SavestateStorageExtensionBase(String fileName, Gson gson) { this.fileName = Paths.get(fileName); + this.gsonInstance = gson; } public abstract JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionRegistry.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionRegistry.java index cdab59a6..ead636c2 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionRegistry.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionRegistry.java @@ -43,7 +43,7 @@ public void onServerSavestate(MinecraftServer server, SavestatePaths paths) { JsonObject dataToSave = storage.onSavestate(server, new JsonObject()); try { - JsonUtils.saveJson(dataPath, dataToSave); + JsonUtils.saveJson(dataPath, dataToSave, storage.gsonInstance); } catch (IOException e) { throw new SavestateException(e, "Can't save %s from %s extension", storage.fileName, storage.getExtensionName()); } @@ -71,7 +71,7 @@ private void load(SavestatePaths paths) { JsonObject loadedData; try { - loadedData = JsonUtils.loadJson(dataPath); + loadedData = JsonUtils.loadJson(dataPath, storage.gsonInstance); } catch (IOException e) { throw new LoadstateException(e, "Can't load %s in %s extension", storage.fileName, storage.getExtensionName()); } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/ClientMotionStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/ClientMotionStorage.java index 81f89e55..a3938659 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/ClientMotionStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/ClientMotionStorage.java @@ -74,7 +74,7 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { if (player.getName().equals(server.getServerOwner())) { uuid = "singleplayer"; } - dataToSave.add(uuid, json.toJsonTree(data)); + dataToSave.add(uuid, gsonInstance.toJsonTree(data)); } catch (TimeoutException e) { throw new SavestateException(e, "Writing client motion for %s timed out!", player.getName()); @@ -92,7 +92,7 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { for (Entry motionDataJsonElement : loadedData.entrySet()) { String playerUUID = motionDataJsonElement.getKey(); - MotionData motionData = json.fromJson(motionDataJsonElement.getValue(), MotionData.class); + MotionData motionData = gsonInstance.fromJson(motionDataJsonElement.getValue(), MotionData.class); EntityPlayerMP player; if (playerUUID.equals("singleplayer")) { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java new file mode 100644 index 00000000..26283393 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -0,0 +1,161 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin; + +import java.util.LinkedHashSet; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; + +import org.spongepowered.asm.mixin.Unique; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; +import com.minecrafttas.tasmod.savestates.typeadapters.BlockPosTypeAdapterFactory; +import com.minecrafttas.tasmod.savestates.typeadapters.EntityClassTypeAdapterFactory; +import com.minecrafttas.tasmod.savestates.typeadapters.EntityTypeAdapterFactory; +import com.minecrafttas.tasmod.savestates.typeadapters.ItemTypeAdapter; +import com.minecrafttas.tasmod.savestates.typeadapters.WorldTypeAdapterFactory; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.entity.ai.EntityAITasks; +import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry; +import net.minecraft.item.Item; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.WorldServer; + +public class EntityAiTaskStorage extends SavestateStorageExtensionBase { + + public EntityAiTaskStorage() { + //@formatter:off + super("entityAi.json", + new GsonBuilder() + .setPrettyPrinting() + .registerTypeAdapterFactory( + new EntityTypeAdapterFactory() + ) + .registerTypeAdapterFactory( + new WorldTypeAdapterFactory() + ) + .registerTypeAdapterFactory( + new EntityClassTypeAdapterFactory() + ) + .registerTypeAdapterFactory( + new BlockPosTypeAdapterFactory() + ) + .registerTypeAdapter(Item.class, new ItemTypeAdapter()) + .setExclusionStrategies(new ExclusionStrategy() { + + @Override + public boolean shouldSkipField(FieldAttributes f) { + return f.getAnnotation(Unique.class) != null; + } + + @Override + public boolean shouldSkipClass(Class c) { + return false; + } + }) + .create()); + //@formatter:on + } + + @Override + public String getExtensionName() { + return "EntityAI"; + } + + @Override + public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { + for (WorldServer worldServer : server.worlds) { + for (Entity entity : worldServer.loadedEntityList) { + if (!(entity instanceof EntityLiving)) + continue; + + JsonObject mainObject = new JsonObject(); + EntityLiving entityLiving = (EntityLiving) entity; + + mainObject.addProperty("type", entity.getClass().getSimpleName()); + + EntityAITasks tasks = entityLiving.tasks; + mainObject.add("tasks", serialiseAITasks(tasks)); + + EntityAITasks targetTasks = entityLiving.targetTasks; + mainObject.add("targetTasks", serialiseAITasks(targetTasks)); + + dataToSave.add(entity.getUniqueID().toString(), mainObject); + } + } + return dataToSave; + } + + private JsonObject serialiseAITasks(EntityAITasks tasks) { + JsonObject out = new JsonObject(); + out.add("taskEntries", serialiseAIEntries(tasks.taskEntries)); + out.add("executingTaskEntries", serialiseAIEntries(tasks.executingTaskEntries)); + return out; + } + + private JsonArray serialiseAIEntries(Set taskEntries) { + JsonArray serialisedEntries = new JsonArray(); + for (EntityAITasks.EntityAITaskEntry entry : taskEntries) { + JsonObject jsonAiTaskEntry = new JsonObject(); + jsonAiTaskEntry.addProperty("priority", entry.priority); + jsonAiTaskEntry.addProperty("using", entry.using); + jsonAiTaskEntry.addProperty("class", entry.action.getClass().getName()); + jsonAiTaskEntry.add("action", gsonInstance.toJsonTree(entry.action)); + serialisedEntries.add(jsonAiTaskEntry); + } + return serialisedEntries; + } + + @Override + public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { + for (Entry elements : loadedData.entrySet()) { + for (WorldServer worldServer : server.worlds) { + EntityLiving entityLiving = (EntityLiving) worldServer.getEntityFromUuid(UUID.fromString(elements.getKey())); + if (entityLiving == null) + continue; + + JsonObject mainObject = elements.getValue().getAsJsonObject(); + deserialiseAITasks(entityLiving.tasks, mainObject.get("tasks").getAsJsonObject()); + deserialiseAITasks(entityLiving.targetTasks, mainObject.get("targetTasks").getAsJsonObject()); + } + } + } + + private void deserialiseAITasks(EntityAITasks tasks, JsonObject jsonTasks) { + tasks.taskEntries.clear(); + tasks.taskEntries.addAll(deserialiseAIEntries(tasks, jsonTasks.get("taskEntries").getAsJsonArray())); + tasks.executingTaskEntries.clear(); + tasks.executingTaskEntries.addAll(deserialiseAIEntries(tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray())); + } + + private Set deserialiseAIEntries(EntityAITasks tasks, JsonArray jsonEntries) { + Set out = new LinkedHashSet<>(); + for (JsonElement jsonEntryElement : jsonEntries) { + JsonObject jsonEntry = jsonEntryElement.getAsJsonObject(); + int priority = jsonEntry.get("priority").getAsInt(); + boolean using = jsonEntry.get("using").getAsBoolean(); + Class clazz; + try { + clazz = Class.forName(jsonEntry.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(EntityAIBase.class); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return out; + } + + EntityAIBase action = gsonInstance.fromJson(jsonEntry.get("action"), clazz); + + EntityAITaskEntry entry = tasks.new EntityAITaskEntry(priority, action); + entry.using = using; + out.add(entry); + } + return out; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/BlockPosTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/BlockPosTypeAdapterFactory.java new file mode 100644 index 00000000..28cd48a7 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/BlockPosTypeAdapterFactory.java @@ -0,0 +1,41 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import net.minecraft.util.math.BlockPos; + +public class BlockPosTypeAdapterFactory implements TypeAdapterFactory { + + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!BlockPos.class.isAssignableFrom(rawType)) + return null; + return new TypeAdapter() { + @Override + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + } + + BlockPos val = (BlockPos) value; + out.value(val.toLong()); + } + + @Override + public T read(JsonReader in) throws IOException { + if (!in.hasNext()) + return null; + return (T) BlockPos.fromLong(in.nextLong()); + } + }; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java new file mode 100644 index 00000000..bc3d10c8 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java @@ -0,0 +1,49 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.EntityAnimal; + +public class EntityClassTypeAdapterFactory implements TypeAdapterFactory { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!new TypeToken>() { + }.equals(type) && !new TypeToken>() { + }.equals(type)) { + return null; + } + + return new TypeAdapter() { + + @Override + public void write(JsonWriter out, T value) throws IOException { + Class clazz = (Class) value; + out.value(clazz.getTypeName()); + } + + @Override + public T read(JsonReader in) throws IOException { + if (!in.hasNext()) + return null; + String jsonString = in.nextString(); + Class out = null; + try { + out = Class.forName(jsonString, false, getClass().getClassLoader()).asSubclass(Entity.class); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return (T) out; + } + }; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityTypeAdapterFactory.java new file mode 100644 index 00000000..54139d4d --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityTypeAdapterFactory.java @@ -0,0 +1,93 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.WorldServer; + +public class EntityTypeAdapterFactory implements TypeAdapterFactory { + + @SuppressWarnings("unchecked") + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!Entity.class.isAssignableFrom(rawType)) + return null; + + return new TypeAdapter() { + + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + Entity entity = (Entity) rawType.cast(value); + + /* + * Instead of storing the players UUID, we will store the index of the playerlist. + * This is because when sharing savestates, the players UUID will be different and thus crash Minecraft. + * + * TODO Make an option to map "Player0, Player1" etc. to specific playernames, so that this will be deterministic + */ + if (entity instanceof EntityPlayer) { + MinecraftServer server = TASmod.getServerInstance(); + int counter = 0; + for (EntityPlayerMP player : server.getPlayerList().getPlayers()) { + if (player.getUniqueID().equals(entity.getUniqueID())) { + out.value("Player" + counter); + return; + } + } + } + + out.value(entity.getUniqueID().toString()); + } + } + + public T read(JsonReader reader) throws IOException { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull(); + return null; + } else { + if (TASmod.getServerInstance() == null) + return null; + MinecraftServer server = TASmod.getServerInstance(); + String entityString = reader.nextString(); + Entity entity = null; + + /* + * Instead of storing the players UUID, we will store the index of the playerlist. + * This is because when sharing savestates, the players UUID will be different and thus crash Minecraft. + */ + Matcher matcher = Pattern.compile("Player(\\d+)").matcher(entityString); + if (matcher.find()) { + int counter = Integer.parseInt(matcher.group(1)); + entity = server.getPlayerList().getPlayers().get(counter); + } else { + UUID uuid = UUID.fromString(entityString); + for (WorldServer world : server.worlds) { + entity = world.getEntityFromUuid(uuid); + if (entity != null) + break; + } + } + + return (T) entity; + } + } + }; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java new file mode 100644 index 00000000..0a4568cd --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java @@ -0,0 +1,25 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import net.minecraft.item.Item; + +public class ItemTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, Item value) throws IOException { + out.value(Item.getIdFromItem(value)); + } + + @Override + public Item read(JsonReader in) throws IOException { + if (!in.hasNext()) + return null; + return Item.getItemById(in.nextInt()); + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/WorldTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/WorldTypeAdapterFactory.java new file mode 100644 index 00000000..2ac5a503 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/WorldTypeAdapterFactory.java @@ -0,0 +1,72 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; + +public class WorldTypeAdapterFactory implements TypeAdapterFactory { + + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!World.class.isAssignableFrom(rawType)) + return null; + + return new TypeAdapter() { + + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + if (TASmod.getServerInstance() == null) + return; + MinecraftServer server = TASmod.getServerInstance(); + WorldServer world = (WorldServer) rawType.cast(value); + + Integer index = findIndex(server.worlds, world); + if (index == null) { + out.nullValue(); + return; + } + out.value(index); + } + } + + private Integer findIndex(WorldServer[] worlds, WorldServer world) { + int index = 0; + for (World otherWorld : worlds) { + if (otherWorld.equals(world)) + return index; + index++; + } + return null; + } + + public T read(JsonReader reader) throws IOException { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull(); + return null; + } else { + if (TASmod.getServerInstance() == null) + return null; + int worldId = Integer.parseInt(reader.nextString()); + MinecraftServer server = TASmod.getServerInstance(); + + return (T) server.worlds[worldId]; + } + } + }; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java b/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java index 33e5b22e..549ca1ce 100644 --- a/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java +++ b/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java @@ -10,24 +10,24 @@ public class JsonUtils { - public static Gson getJsonInstance() { + public static Gson getGsonInstance() { return new GsonBuilder().setPrettyPrinting().create(); } public static void saveJson(Path savePath, JsonObject data) throws IOException { - saveJson(savePath, data, getJsonInstance()); + saveJson(savePath, data, getGsonInstance()); } - public static void saveJson(Path savePath, JsonObject data, Gson jsonInstance) throws IOException { - String out = jsonInstance.toJson(data); + public static void saveJson(Path savePath, JsonObject data, Gson gsonInstance) throws IOException { + String out = gsonInstance.toJson(data); Files.write(savePath, out.getBytes()); } public static JsonObject loadJson(Path loadPath) throws IOException { - return loadJson(loadPath, getJsonInstance()); + return loadJson(loadPath, getGsonInstance()); } - public static JsonObject loadJson(Path loadPath, Gson jsonInstance) throws IOException { - return jsonInstance.fromJson(new String(Files.readAllBytes(loadPath)), JsonObject.class); + public static JsonObject loadJson(Path loadPath, Gson gsonInstance) throws IOException { + return gsonInstance.fromJson(new String(Files.readAllBytes(loadPath)), JsonObject.class); } } diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 47522fc7..62d1660d 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -35,3 +35,11 @@ accessible field net/minecraft/entity/passive/EntityBat spawnPosition Lnet/minec accessible field net/minecraft/entity/Entity nextEntityID I accessible field net/minecraft/entity/EntityLivingBase idleTime I +accessible class net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry + +accessible field net/minecraft/entity/ai/EntityAITasks taskEntries Ljava/util/Set; +mutable field net/minecraft/entity/ai/EntityAITasks taskEntries Ljava/util/Set; + +accessible field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; +mutable field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; + From 230600c48281351e18650e8bfe662b7b4513bd6b Mon Sep 17 00:00:00 2001 From: Scribble Date: Sun, 12 Jul 2026 21:55:58 +0200 Subject: [PATCH 03/26] [Savestates] Store revenge target and last attacked --- .../storage/builtin/EntityAiTaskStorage.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 26283393..1362ebf4 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -22,6 +22,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAITasks; import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry; @@ -82,6 +83,9 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { mainObject.addProperty("type", entity.getClass().getSimpleName()); + mainObject.add("revengeTarget", gsonInstance.toJsonTree(entityLiving.getRevengeTarget())); + mainObject.add("lastAttackedEntity", gsonInstance.toJsonTree(entityLiving.getLastAttackedEntity())); + EntityAITasks tasks = entityLiving.tasks; mainObject.add("tasks", serialiseAITasks(tasks)); @@ -123,6 +127,10 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { continue; JsonObject mainObject = elements.getValue().getAsJsonObject(); + + entityLiving.setRevengeTarget((EntityLivingBase) gsonInstance.fromJson(mainObject.get("revengeTarget"), Entity.class)); + entityLiving.setLastAttackedEntity((EntityLivingBase) gsonInstance.fromJson(mainObject.get("lastAttackedEntity"), Entity.class)); + deserialiseAITasks(entityLiving.tasks, mainObject.get("tasks").getAsJsonObject()); deserialiseAITasks(entityLiving.targetTasks, mainObject.get("targetTasks").getAsJsonObject()); } @@ -130,10 +138,8 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { } private void deserialiseAITasks(EntityAITasks tasks, JsonObject jsonTasks) { - tasks.taskEntries.clear(); - tasks.taskEntries.addAll(deserialiseAIEntries(tasks, jsonTasks.get("taskEntries").getAsJsonArray())); - tasks.executingTaskEntries.clear(); - tasks.executingTaskEntries.addAll(deserialiseAIEntries(tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray())); + tasks.taskEntries = deserialiseAIEntries(tasks, jsonTasks.get("taskEntries").getAsJsonArray()); + tasks.executingTaskEntries = deserialiseAIEntries(tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray()); } private Set deserialiseAIEntries(EntityAITasks tasks, JsonArray jsonEntries) { From 45a03b47ee5d1e4504d6d3b2cf5f7a1dc35d4263 Mon Sep 17 00:00:00 2001 From: Scribble Date: Tue, 28 Jul 2026 21:37:11 +0200 Subject: [PATCH 04/26] [Savestates] Trying to add EntityAiTaskStorage --- .../storage/builtin/EntityAiTaskStorage.java | 73 ++++++++++++++++- ...estAttackableTargetTypeAdapterFactory.java | 48 +++++++++++ .../EntityClassTypeAdapterFactory.java | 8 +- .../typeadapters/EntityLivingTypeAdapter.java | 82 +++++++++++++++++++ .../util/ClassExclusionStrategy.java | 34 ++++++++ .../util/StaggeredTypeAdapterFactory.java | 57 +++++++++++++ src/main/resources/tasmod.accesswidener | 13 +++ 7 files changed, 306 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityLivingTypeAdapter.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/ClassExclusionStrategy.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/StaggeredTypeAdapterFactory.java diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 1362ebf4..c9f1dfb2 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -7,26 +7,34 @@ import org.spongepowered.asm.mixin.Unique; +import com.google.common.base.Predicate; import com.google.gson.ExclusionStrategy; import com.google.gson.FieldAttributes; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; import com.minecrafttas.tasmod.savestates.typeadapters.BlockPosTypeAdapterFactory; +import com.minecrafttas.tasmod.savestates.typeadapters.EntityAINearestAttackableTargetTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.EntityClassTypeAdapterFactory; +import com.minecrafttas.tasmod.savestates.typeadapters.EntityLivingTypeAdapter; import com.minecrafttas.tasmod.savestates.typeadapters.EntityTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.ItemTypeAdapter; import com.minecrafttas.tasmod.savestates.typeadapters.WorldTypeAdapterFactory; +import com.minecrafttas.tasmod.savestates.typeadapters.util.ClassExclusionStrategy; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIAvoidEntity; import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAITasks; import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry; import net.minecraft.item.Item; +import net.minecraft.pathfinding.PathNavigate; import net.minecraft.server.MinecraftServer; import net.minecraft.world.WorldServer; @@ -46,10 +54,12 @@ public EntityAiTaskStorage() { .registerTypeAdapterFactory( new EntityClassTypeAdapterFactory() ) + .registerTypeAdapterFactory(new EntityAINearestAttackableTargetTypeAdapterFactory()) .registerTypeAdapterFactory( new BlockPosTypeAdapterFactory() ) .registerTypeAdapter(Item.class, new ItemTypeAdapter()) + .registerTypeAdapter(EntityLivingTypeAdapter.class, new EntityLivingTypeAdapter()) .setExclusionStrategies(new ExclusionStrategy() { @Override @@ -61,7 +71,11 @@ public boolean shouldSkipField(FieldAttributes f) { public boolean shouldSkipClass(Class c) { return false; } - }) + }, + new ClassExclusionStrategy(Predicate.class), + new ClassExclusionStrategy(PathNavigate.class), + new ClassExclusionStrategy(EntityLivingBase.class, EntityAINearestAttackableTarget.class) + ) .create()); //@formatter:on } @@ -112,7 +126,12 @@ private JsonArray serialiseAIEntries(Set taskEntries) { jsonAiTaskEntry.addProperty("priority", entry.priority); jsonAiTaskEntry.addProperty("using", entry.using); jsonAiTaskEntry.addProperty("class", entry.action.getClass().getName()); - jsonAiTaskEntry.add("action", gsonInstance.toJsonTree(entry.action)); + try { + System.out.println(entry.action.getClass().getName()); + jsonAiTaskEntry.add("action", gsonInstance.toJsonTree(entry.action)); + } catch (Exception e) { + throw new SavestateException(e, "Could not serialise AI Task %s", entry.action.getClass().getName()); + } serialisedEntries.add(jsonAiTaskEntry); } return serialisedEntries; @@ -138,8 +157,8 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { } private void deserialiseAITasks(EntityAITasks tasks, JsonObject jsonTasks) { - tasks.taskEntries = deserialiseAIEntries(tasks, jsonTasks.get("taskEntries").getAsJsonArray()); - tasks.executingTaskEntries = deserialiseAIEntries(tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray()); + mapDeserialisedEntries(tasks.taskEntries, deserialiseAIEntries(tasks, jsonTasks.get("taskEntries").getAsJsonArray())); + mapDeserialisedEntries(tasks.executingTaskEntries, deserialiseAIEntries(tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray())); } private Set deserialiseAIEntries(EntityAITasks tasks, JsonArray jsonEntries) { @@ -148,6 +167,7 @@ private Set deserialiseAIEntries(EntityAITasks tasks, JsonArr JsonObject jsonEntry = jsonEntryElement.getAsJsonObject(); int priority = jsonEntry.get("priority").getAsInt(); boolean using = jsonEntry.get("using").getAsBoolean(); + System.out.println(jsonEntry.get("class").getAsString()); Class clazz; try { clazz = Class.forName(jsonEntry.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(EntityAIBase.class); @@ -164,4 +184,49 @@ private Set deserialiseAIEntries(EntityAITasks tasks, JsonArr } return out; } + +// private EntityAIBase deserialiseAction(JsonElement json, Class clazz) { +// try { +// EntityAIBase base = clazz.newInstance(); +// } catch (InstantiationException | IllegalAccessException e) { +// e.printStackTrace(); +// } +// +// } + + private void mapDeserialisedEntries(Set tasks, Set deserialisedTasks) { + for (EntityAITaskEntry vanillaEntry : tasks) { + EntityAIBase vanillaAction = vanillaEntry.action; + for (EntityAITaskEntry deserialisedEntry : deserialisedTasks) { + if (vanillaAction.getClass().isInstance(deserialisedEntry.action)) { + EntityAIBase deserialisedAction = deserialisedEntry.action; + vanillaEntry.action = applyAction(vanillaAction, deserialisedAction); + break; + } + } + } + } + + @SuppressWarnings("unchecked") + private EntityAIBase applyAction(EntityAIBase vanillaAction, EntityAIBase deserialisedAction) { + if (vanillaAction instanceof EntityAIAvoidEntity) { + EntityAIAvoidEntity vanillaAIAvoidEntityAction = (EntityAIAvoidEntity) vanillaAction; + EntityAIAvoidEntity deserialisedAIAvoidEntityAction = (EntityAIAvoidEntity) deserialisedAction; + + deserialisedAIAvoidEntityAction.avoidTargetSelector = vanillaAIAvoidEntityAction.avoidTargetSelector; + deserialisedAIAvoidEntityAction.canBeSeenSelector = vanillaAIAvoidEntityAction.canBeSeenSelector; + return deserialisedAIAvoidEntityAction; + } + + if (vanillaAction instanceof EntityAINearestAttackableTarget) { + EntityAINearestAttackableTarget vanillaAINearestAttackableTarget = (EntityAINearestAttackableTarget) vanillaAction; + EntityAINearestAttackableTarget deserialisedAINearestAttackableTarget = (EntityAINearestAttackableTarget) deserialisedAction; + + deserialisedAINearestAttackableTarget.targetEntitySelector = vanillaAINearestAttackableTarget.targetEntitySelector; + + return deserialisedAINearestAttackableTarget; + } + + return deserialisedAction; + } } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java new file mode 100644 index 00000000..8904b729 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java @@ -0,0 +1,48 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; + +public class EntityAINearestAttackableTargetTypeAdapterFactory implements TypeAdapterFactory { + + @SuppressWarnings({ "unchecked" }) + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!EntityAINearestAttackableTarget.class.equals(rawType)) + return null; + + TypeAdapter adapter = gson.getDelegateAdapter(this, type); + + return new TypeAdapter() { + + @Override + public void write(JsonWriter out, T value) throws IOException { + adapter.write(out, value); + } + + @Override + public T read(JsonReader in) throws IOException { + in.beginObject(); + while (in.hasNext()) { + in.nextString(); + } + in.endObject(); + T value = adapter.read(in); + EntityAINearestAttackableTarget ai = (EntityAINearestAttackableTarget) value; + + return (T) ai; + } + }; + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java index bc3d10c8..70a59ceb 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityClassTypeAdapterFactory.java @@ -10,18 +10,16 @@ import com.google.gson.stream.JsonWriter; import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.EntityAnimal; public class EntityClassTypeAdapterFactory implements TypeAdapterFactory { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public TypeAdapter create(Gson gson, TypeToken type) { - if (!new TypeToken>() { - }.equals(type) && !new TypeToken>() { - }.equals(type)) { + + Class rawType = (Class) type.getRawType(); + if (!Class.class.equals(rawType)) return null; - } return new TypeAdapter() { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityLivingTypeAdapter.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityLivingTypeAdapter.java new file mode 100644 index 00000000..80eb3a77 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityLivingTypeAdapter.java @@ -0,0 +1,82 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.WorldServer; + +public class EntityLivingTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, EntityLivingBase entity) throws IOException { + if (entity == null) { + out.nullValue(); + } else { + + /* + * Instead of storing the players UUID, we will store the index of the playerlist. + * This is because when sharing savestates, the players UUID will be different and thus crash Minecraft. + * + * TODO Make an option to map "Player0, Player1" etc. to specific playernames, so that this will be deterministic + */ + if (entity instanceof EntityPlayer) { + MinecraftServer server = TASmod.getServerInstance(); + int counter = 0; + for (EntityPlayerMP player : server.getPlayerList().getPlayers()) { + if (player.getUniqueID().equals(entity.getUniqueID())) { + out.value("Player" + counter); + return; + } + } + } + + out.value(entity.getUniqueID().toString()); + } + } + + @Override + public EntityLivingBase read(JsonReader reader) throws IOException { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull(); + return null; + } else { + if (TASmod.getServerInstance() == null) + return null; + MinecraftServer server = TASmod.getServerInstance(); + String entityString = reader.nextString(); + Entity entity = null; + + /* + * Instead of storing the players UUID, we will store the index of the playerlist. + * This is because when sharing savestates, the players UUID will be different and thus crash Minecraft. + */ + Matcher matcher = Pattern.compile("Player(\\d+)").matcher(entityString); + if (matcher.find()) { + int counter = Integer.parseInt(matcher.group(1)); + entity = server.getPlayerList().getPlayers().get(counter); + } else { + UUID uuid = UUID.fromString(entityString); + for (WorldServer world : server.worlds) { + entity = world.getEntityFromUuid(uuid); + if (entity != null) + break; + } + } + + return (EntityLivingBase) entity; + } + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/ClassExclusionStrategy.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/ClassExclusionStrategy.java new file mode 100644 index 00000000..b5a08cd8 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/ClassExclusionStrategy.java @@ -0,0 +1,34 @@ +package com.minecrafttas.tasmod.savestates.typeadapters.util; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; + +public class ClassExclusionStrategy implements ExclusionStrategy { + + protected final Class clazz; + + protected final Class declaringClass; + + public ClassExclusionStrategy(Class clazz) { + this.clazz = clazz; + this.declaringClass = null; + } + + public ClassExclusionStrategy(Class clazz, Class declaringClass) { + this.clazz = clazz; + this.declaringClass = declaringClass; + } + + @Override + public boolean shouldSkipField(FieldAttributes f) { + if (declaringClass == null) + return false; + return declaringClass.equals(f.getDeclaringClass()); + } + + @Override + public boolean shouldSkipClass(Class clazz) { + return this.clazz.equals(clazz) || this.clazz.isAssignableFrom(clazz); + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/StaggeredTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/StaggeredTypeAdapterFactory.java new file mode 100644 index 00000000..f52bb721 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/StaggeredTypeAdapterFactory.java @@ -0,0 +1,57 @@ +package com.minecrafttas.tasmod.savestates.typeadapters.util; + +import java.io.IOException; +import java.lang.reflect.Field; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +public class StaggeredTypeAdapterFactory implements TypeAdapterFactory { + + Class clazz; + OnWrite writeBehaviour; + OnRead readBehaviour; + + public StaggeredTypeAdapterFactory(Class clazz, OnWrite writeBehaviour, OnRead readBehaviour) { + this.clazz = clazz; + this.writeBehaviour = writeBehaviour; + this.readBehaviour = readBehaviour; + } + + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!clazz.isAssignableFrom(rawType)) + return null; + return new TypeAdapter() { + + @Override + public void write(JsonWriter out, T value) throws IOException { + + } + + @Override + public T read(JsonReader in) throws IOException { + return null; + } + + }; + } + + @FunctionalInterface + public interface OnWrite { + + public void apply(JsonWriter out, Field value, Gson gson); + } + + @FunctionalInterface + public static interface OnRead { + + public T apply(JsonReader in, T value, Gson gson); + } +} diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 62d1660d..458f8e44 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -43,3 +43,16 @@ mutable field net/minecraft/entity/ai/EntityAITasks taskEntries Ljava/util/Set; accessible field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; mutable field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; +accessible field net/minecraft/entity/ai/EntityAIAvoidEntity canBeSeenSelector Lcom/google/common/base/Predicate; +mutable field net/minecraft/entity/ai/EntityAIAvoidEntity canBeSeenSelector Lcom/google/common/base/Predicate; + +accessible field net/minecraft/entity/ai/EntityAIAvoidEntity avoidTargetSelector Lcom/google/common/base/Predicate; +mutable field net/minecraft/entity/ai/EntityAIAvoidEntity avoidTargetSelector Lcom/google/common/base/Predicate; + +accessible field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; +mutable field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; +accessible field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntity Lnet/minecraft/entity/EntityLivingBase; + +accessible field net/minecraft/entity/ai/EntityAIAvoidEntity entity Lnet/minecraft/entity/EntityCreature; + +mutable field net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry action Lnet/minecraft/entity/ai/EntityAIBase; From ede97bff8fe9dad7911346964057ec7cfcd45725 Mon Sep 17 00:00:00 2001 From: Scribble Date: Tue, 28 Jul 2026 21:37:11 +0200 Subject: [PATCH 05/26] Trying to add gson again for readability --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 150a6c9d..bb9fa4de 100644 --- a/build.gradle +++ b/build.gradle @@ -53,6 +53,7 @@ dependencies { // tasmod dependencies embed "com.dselent:bigarraylist:1.6" embed "com.github.KaptainWutax:SeedUtils:b6a383113c" + implementation "com.google.code.gson:gson:2.14.0" // loom dependencies minecraft "com.mojang:minecraft:${project.minecraft_version}" From 2c0db85bb8b8907a5ffeab3008c07dab549626a5 Mon Sep 17 00:00:00 2001 From: Scribble Date: Sat, 22 Aug 2026 22:51:34 +0200 Subject: [PATCH 06/26] [Savestates] Update EntityAI deserialisation to merge with vanilla actions ...rather than create new action objects entirely. This has the benefit of circumnavigating unserializable fields such as Predicates and Lambdas. --- .../storage/builtin/EntityAiTaskStorage.java | 107 +++++++++--------- ...estAttackableTargetTypeAdapterFactory.java | 48 -------- src/main/resources/tasmod.accesswidener | 4 +- 3 files changed, 58 insertions(+), 101 deletions(-) delete mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index c9f1dfb2..08b60821 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -1,6 +1,9 @@ package com.minecrafttas.tasmod.savestates.storage.builtin; +import java.lang.reflect.Field; +import java.util.Arrays; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -17,7 +20,6 @@ import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; import com.minecrafttas.tasmod.savestates.typeadapters.BlockPosTypeAdapterFactory; -import com.minecrafttas.tasmod.savestates.typeadapters.EntityAINearestAttackableTargetTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.EntityClassTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.EntityLivingTypeAdapter; import com.minecrafttas.tasmod.savestates.typeadapters.EntityTypeAdapterFactory; @@ -28,9 +30,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.ai.EntityAIAvoidEntity; import net.minecraft.entity.ai.EntityAIBase; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAITasks; import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry; import net.minecraft.item.Item; @@ -54,7 +54,7 @@ public EntityAiTaskStorage() { .registerTypeAdapterFactory( new EntityClassTypeAdapterFactory() ) - .registerTypeAdapterFactory(new EntityAINearestAttackableTargetTypeAdapterFactory()) +// .registerTypeAdapter(EntityAINearestAttackableTarget.class, new EntityAINearestAttackableTargetTypeAdapter()) .registerTypeAdapterFactory( new BlockPosTypeAdapterFactory() ) @@ -73,8 +73,8 @@ public boolean shouldSkipClass(Class c) { } }, new ClassExclusionStrategy(Predicate.class), - new ClassExclusionStrategy(PathNavigate.class), - new ClassExclusionStrategy(EntityLivingBase.class, EntityAINearestAttackableTarget.class) + new ClassExclusionStrategy(PathNavigate.class) +// new ClassExclusionStrategy(EntityLivingBase.class, EntityAINearestAttackableTarget.class) ) .create()); //@formatter:on @@ -157,17 +157,18 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { } private void deserialiseAITasks(EntityAITasks tasks, JsonObject jsonTasks) { - mapDeserialisedEntries(tasks.taskEntries, deserialiseAIEntries(tasks, jsonTasks.get("taskEntries").getAsJsonArray())); - mapDeserialisedEntries(tasks.executingTaskEntries, deserialiseAIEntries(tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray())); + deserialiseAIEntries(tasks.taskEntries, tasks, jsonTasks.get("taskEntries").getAsJsonArray()); + deserialiseAIEntries(tasks.executingTaskEntries, tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray()); } - private Set deserialiseAIEntries(EntityAITasks tasks, JsonArray jsonEntries) { + private Set deserialiseAIEntries(Set taskEntries, EntityAITasks parent, JsonArray jsonEntries) { Set out = new LinkedHashSet<>(); + for (JsonElement jsonEntryElement : jsonEntries) { JsonObject jsonEntry = jsonEntryElement.getAsJsonObject(); - int priority = jsonEntry.get("priority").getAsInt(); - boolean using = jsonEntry.get("using").getAsBoolean(); - System.out.println(jsonEntry.get("class").getAsString()); + + // Deserialise the type of the AI action +// System.out.println(jsonEntry.get("class").getAsString()); Class clazz; try { clazz = Class.forName(jsonEntry.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(EntityAIBase.class); @@ -176,57 +177,61 @@ private Set deserialiseAIEntries(EntityAITasks tasks, JsonArr return out; } - EntityAIBase action = gsonInstance.fromJson(jsonEntry.get("action"), clazz); + boolean createNew = true; + for (EntityAITaskEntry vanillaEntry : taskEntries) { + EntityAIBase vanillaAction = vanillaEntry.action; + if (vanillaAction.getClass() != clazz) { + continue; + } - EntityAITaskEntry entry = tasks.new EntityAITaskEntry(priority, action); + createNew = false; + vanillaEntry.action = deserialiseAction(vanillaAction, jsonEntry.get("action"), clazz); + out.add(vanillaEntry); + break; + } + + if (!createNew) { + continue; + } + + int priority = jsonEntry.get("priority").getAsInt(); + boolean using = jsonEntry.get("using").getAsBoolean(); + EntityAIBase action = null; + try { + action = gsonInstance.fromJson(jsonEntry, clazz); + } catch (Exception e) { + e.printStackTrace(); + continue; + } + EntityAITaskEntry entry = parent.new EntityAITaskEntry(priority, action); entry.using = using; out.add(entry); } return out; } -// private EntityAIBase deserialiseAction(JsonElement json, Class clazz) { -// try { -// EntityAIBase base = clazz.newInstance(); -// } catch (InstantiationException | IllegalAccessException e) { -// e.printStackTrace(); -// } -// -// } - - private void mapDeserialisedEntries(Set tasks, Set deserialisedTasks) { - for (EntityAITaskEntry vanillaEntry : tasks) { - EntityAIBase vanillaAction = vanillaEntry.action; - for (EntityAITaskEntry deserialisedEntry : deserialisedTasks) { - if (vanillaAction.getClass().isInstance(deserialisedEntry.action)) { - EntityAIBase deserialisedAction = deserialisedEntry.action; - vanillaEntry.action = applyAction(vanillaAction, deserialisedAction); - break; - } - } - } - } - - @SuppressWarnings("unchecked") - private EntityAIBase applyAction(EntityAIBase vanillaAction, EntityAIBase deserialisedAction) { - if (vanillaAction instanceof EntityAIAvoidEntity) { - EntityAIAvoidEntity vanillaAIAvoidEntityAction = (EntityAIAvoidEntity) vanillaAction; - EntityAIAvoidEntity deserialisedAIAvoidEntityAction = (EntityAIAvoidEntity) deserialisedAction; + private EntityAIBase deserialiseAction(EntityAIBase vanillaAction, JsonElement json, Class clazz) { + JsonObject jsonObject = json.getAsJsonObject(); + List vanillaFields = Arrays.asList(vanillaAction.getClass().getDeclaredFields()); - deserialisedAIAvoidEntityAction.avoidTargetSelector = vanillaAIAvoidEntityAction.avoidTargetSelector; - deserialisedAIAvoidEntityAction.canBeSeenSelector = vanillaAIAvoidEntityAction.canBeSeenSelector; - return deserialisedAIAvoidEntityAction; - } + for (Field field : vanillaFields) { + field.setAccessible(true); + String fieldname = field.getName(); + Class fieldClass = field.getType(); - if (vanillaAction instanceof EntityAINearestAttackableTarget) { - EntityAINearestAttackableTarget vanillaAINearestAttackableTarget = (EntityAINearestAttackableTarget) vanillaAction; - EntityAINearestAttackableTarget deserialisedAINearestAttackableTarget = (EntityAINearestAttackableTarget) deserialisedAction; + JsonElement value = jsonObject.get(fieldname); - deserialisedAINearestAttackableTarget.targetEntitySelector = vanillaAINearestAttackableTarget.targetEntitySelector; + if (value == null) + continue; - return deserialisedAINearestAttackableTarget; + Object deserialised = gsonInstance.fromJson(value, fieldClass); + try { + field.set(vanillaAction, deserialised); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } } - return deserialisedAction; + return vanillaAction; } } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java deleted file mode 100644 index 8904b729..00000000 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapterFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.minecrafttas.tasmod.savestates.typeadapters; - -import java.io.IOException; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; - -public class EntityAINearestAttackableTargetTypeAdapterFactory implements TypeAdapterFactory { - - @SuppressWarnings({ "unchecked" }) - @Override - public TypeAdapter create(Gson gson, TypeToken type) { - Class rawType = (Class) type.getRawType(); - if (!EntityAINearestAttackableTarget.class.equals(rawType)) - return null; - - TypeAdapter adapter = gson.getDelegateAdapter(this, type); - - return new TypeAdapter() { - - @Override - public void write(JsonWriter out, T value) throws IOException { - adapter.write(out, value); - } - - @Override - public T read(JsonReader in) throws IOException { - in.beginObject(); - while (in.hasNext()) { - in.nextString(); - } - in.endObject(); - T value = adapter.read(in); - EntityAINearestAttackableTarget ai = (EntityAINearestAttackableTarget) value; - - return (T) ai; - } - }; - } - -} diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 458f8e44..18056f48 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -49,8 +49,8 @@ mutable field net/minecraft/entity/ai/EntityAIAvoidEntity canBeSeenSelector Lcom accessible field net/minecraft/entity/ai/EntityAIAvoidEntity avoidTargetSelector Lcom/google/common/base/Predicate; mutable field net/minecraft/entity/ai/EntityAIAvoidEntity avoidTargetSelector Lcom/google/common/base/Predicate; -accessible field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; -mutable field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; +#accessible field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; +#mutable field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; accessible field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntity Lnet/minecraft/entity/EntityLivingBase; accessible field net/minecraft/entity/ai/EntityAIAvoidEntity entity Lnet/minecraft/entity/EntityCreature; From 7a1d5f5b352cf4dfb210a23ffa61945e9603f62d Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 26 Aug 2026 23:25:01 +0200 Subject: [PATCH 07/26] [Savestates] Merge SquidRotation, BatSpawn and TickTimers json into Entity.json --- .../java/com/minecrafttas/tasmod/TASmod.java | 22 +++-- .../EntityBatSpawnPositionStorage.java | 61 ------------- .../builtin/EntitySquidRotationStorage.java | 65 ------------- .../storage/builtin/EntityStorage.java | 88 ++++++++++++++++++ .../builtin/EntityTickTimersStorage.java | 91 ------------------- .../BatSpawnPositionSubStorage.java | 46 ++++++++++ .../LivingTickTimersSubStorage.java | 72 +++++++++++++++ .../SquidRotationSubStorage.java | 48 ++++++++++ 8 files changed, 267 insertions(+), 226 deletions(-) delete mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityBatSpawnPositionStorage.java delete mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntitySquidRotationStorage.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java delete mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityTickTimersStorage.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/BatSpawnPositionSubStorage.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/LivingTickTimersSubStorage.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/SquidRotationSubStorage.java diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index d6ae3a97..16480d0d 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -44,10 +44,11 @@ import com.minecrafttas.tasmod.savestates.handlers.SavestateResourcePackHandler; import com.minecrafttas.tasmod.savestates.storage.builtin.ClientMotionStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityAiTaskStorage; -import com.minecrafttas.tasmod.savestates.storage.builtin.EntityBatSpawnPositionStorage; -import com.minecrafttas.tasmod.savestates.storage.builtin.EntitySquidRotationStorage; -import com.minecrafttas.tasmod.savestates.storage.builtin.EntityTickTimersStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.KTRNGSeedStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage.BatSpawnPositionSubStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage.LivingTickTimersSubStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage.SquidRotationSubStorage; import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer; import com.minecrafttas.tasmod.ticksync.TickSyncServer; import com.minecrafttas.tasmod.util.LoggerMarkers; @@ -104,9 +105,6 @@ public class TASmod implements ModInitializer, EventServerStart, EventServerInit public static GlobalRNG globalRandomness; public static KTRNGSeedStorage seedStorage = new KTRNGSeedStorage(); - public static EntityTickTimersStorage entityTickTimers = new EntityTickTimersStorage(); - public static EntityBatSpawnPositionStorage entityBatSpawnPositionStorage = new EntityBatSpawnPositionStorage(); - public static EntitySquidRotationStorage entitySquidRotationStorage = new EntitySquidRotationStorage(); public static EntityAiTaskStorage entityAiTaskStorage = new EntityAiTaskStorage(); public static MathRNG mathRandomness = new MathRNG(0); @@ -245,9 +243,15 @@ public void onServerStop(MinecraftServer mcserver) { private void registerSavestateStorage() { TASmodAPIRegistry.SAVESTATE_STORAGE.register(motionStorage); TASmodAPIRegistry.SAVESTATE_STORAGE.register(seedStorage); - TASmodAPIRegistry.SAVESTATE_STORAGE.register(entityTickTimers); - TASmodAPIRegistry.SAVESTATE_STORAGE.register(entityBatSpawnPositionStorage); - TASmodAPIRegistry.SAVESTATE_STORAGE.register(entitySquidRotationStorage); + //@formatter:off + TASmodAPIRegistry.SAVESTATE_STORAGE.register( + new EntityStorage( + new BatSpawnPositionSubStorage(), + new SquidRotationSubStorage(), + new LivingTickTimersSubStorage() + ) + ); + //@formatter:on TASmodAPIRegistry.SAVESTATE_STORAGE.register(entityAiTaskStorage); } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityBatSpawnPositionStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityBatSpawnPositionStorage.java deleted file mode 100644 index 307376ea..00000000 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityBatSpawnPositionStorage.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.minecrafttas.tasmod.savestates.storage.builtin; - -import java.util.UUID; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.EntityBat; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.WorldServer; - -public class EntityBatSpawnPositionStorage extends SavestateStorageExtensionBase { - - public EntityBatSpawnPositionStorage() { - super("entityBatSpawnPosition.json"); - } - - @Override - public String getExtensionName() { - return "EntityBatSpawnPosition"; - } - - @Override - public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { - for (WorldServer worldServer : server.worlds) { - for (Entity entity : worldServer.loadedEntityList) { - if (entity instanceof EntityBat) { - EntityBat bat = (EntityBat) entity; - BlockPos spawnPos = bat.spawnPosition; - if (spawnPos == null) - continue; - UUID entityUUID = entity.getUniqueID(); - dataToSave.addProperty(entityUUID.toString(), Long.toString(bat.spawnPosition.toLong())); - } - } - } - return dataToSave; - } - - @Override - public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { - if (loadedData == null) - return; - for (WorldServer worldServer : server.worlds) { - for (Entity entity : worldServer.loadedEntityList) { - if (entity instanceof EntityBat) { - EntityBat bat = (EntityBat) entity; - UUID entityUUID = entity.getUniqueID(); - JsonElement element = loadedData.get(entityUUID.toString()); - if (element == null) - continue; - BlockPos spawnPos = BlockPos.fromLong(element.getAsLong()); - bat.spawnPosition = spawnPos; - } - } - } - } -} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntitySquidRotationStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntitySquidRotationStorage.java deleted file mode 100644 index 0c9e7349..00000000 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntitySquidRotationStorage.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.minecrafttas.tasmod.savestates.storage.builtin; - -import java.util.UUID; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.EntitySquid; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.WorldServer; - -/** - *

Stores squid rotation in the savestates - *

Did you know that the rotation of the squid can trigger an RNG call? Did you know Minecraft does not save this by default?
- * Well now you know and it's annoying. - * - * @author Scribble - */ -public class EntitySquidRotationStorage extends SavestateStorageExtensionBase { - - public EntitySquidRotationStorage() { - super("entitySquidRotation.json"); - } - - @Override - public String getExtensionName() { - return "EntitySquidRotation"; - } - - @Override - public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { - for (WorldServer worldServer : server.worlds) { - for (Entity entity : worldServer.loadedEntityList) { - if (entity instanceof EntitySquid) { - EntitySquid squid = (EntitySquid) entity; - float rotation = squid.squidRotation; - UUID entityUUID = entity.getUniqueID(); - dataToSave.addProperty(entityUUID.toString(), Float.toString(rotation)); - } - } - } - return dataToSave; - } - - @Override - public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { - if (loadedData == null) - return; - for (WorldServer worldServer : server.worlds) { - for (Entity entity : worldServer.loadedEntityList) { - if (entity instanceof EntitySquid) { - EntitySquid squid = (EntitySquid) entity; - UUID entityUUID = entity.getUniqueID(); - JsonElement element = loadedData.get(entityUUID.toString()); - if (element == null) - continue; - float rotation = element.getAsFloat(); - squid.squidRotation = rotation; - } - } - } - } -} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java new file mode 100644 index 00000000..ff56024a --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java @@ -0,0 +1,88 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.TASmod; +import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; +import com.minecrafttas.tasmod.util.LoggerMarkers; + +import net.minecraft.entity.Entity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.WorldServer; + +public class EntityStorage extends SavestateStorageExtensionBase { + + private final List subStorages; + + public EntityStorage(EntitySubStorage... entitySubStorages) { + this(Arrays.asList(entitySubStorages)); + } + + public EntityStorage(List entitySubStorages) { + super("entity.json", new GsonBuilder().setPrettyPrinting().create()); + this.subStorages = entitySubStorages; + } + + @Override + public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { + for (WorldServer worldServer : server.worlds) { + for (Entity entity : worldServer.loadedEntityList) { + UUID uuid = entity.getUniqueID(); + for (EntitySubStorage subStorage : subStorages) { + JsonObject subDataObject = new JsonObject(); + if (subStorage.getEntityClass().isAssignableFrom(entity.getClass())) { + JsonObject subDataToSave = new JsonObject(); + subDataToSave = subStorage.onSavestate(server, entity, subDataToSave); + subDataObject.add(subStorage.getPropertyName(), subDataToSave); + } + dataToSave.add(uuid.toString(), subDataObject); + } + } + } + return dataToSave; + } + + @Override + public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { + if (loadedData == null) + return; + for (WorldServer worldServer : server.worlds) { + for (Entity entity : worldServer.loadedEntityList) { + UUID uuid = entity.getUniqueID(); + if (!loadedData.has(uuid.toString())) + continue; + + JsonObject subDataObject = loadedData.get(uuid.toString()).getAsJsonObject(); + for (EntitySubStorage subStorage : subStorages) { + if (!subDataObject.has(subStorage.getPropertyName())) { + TASmod.LOGGER.warn(LoggerMarkers.Savestate, "{} is not found in EntityStorage. Things might desync!", subStorage.getPropertyName()); + continue; + } + + if (subStorage.getEntityClass().isAssignableFrom(entity.getClass())) { + entity = subStorage.onLoadstatePost(server, entity, subDataObject.get(subStorage.getPropertyName()).getAsJsonObject()); + } + } + } + } + } + + @Override + public String getExtensionName() { + return "EntityAIStorage"; + } + + public static interface EntitySubStorage { + public String getPropertyName(); + + public Class getEntityClass(); + + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave); + + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityTickTimersStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityTickTimersStorage.java deleted file mode 100644 index 7d356430..00000000 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityTickTimersStorage.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.minecrafttas.tasmod.savestates.storage.builtin; - -import java.util.UUID; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.ai.EntityAITasks; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.WorldServer; - -/** - * Stores the {@link EntityAITasks#tickCount} in a savestate. - * - * AI tasks are only updated every third tick and the tickCount keeps track of that. - * - * @author Scribble - */ -public class EntityTickTimersStorage extends SavestateStorageExtensionBase { - - public EntityTickTimersStorage() { - super("entityTickTimers.json"); - } - - @Override - public String getExtensionName() { - return "EntityTickTimers"; - } - - @Override - public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { - for (WorldServer worldServer : server.worlds) { - for (Entity entity : worldServer.loadedEntityList) { - if (entity instanceof EntityLiving) { - UUID entityUUID = entity.getUniqueID(); - EntityLiving entityLiving = (EntityLiving) entity; - EntityLivingBase entityLivingBase = (EntityLivingBase) entity; - EntityAITasks tasks = entityLiving.tasks; - EntityAITasks targetTasks = entityLiving.targetTasks; - int tickCount = tasks.tickCount; - int tickCountTarget = targetTasks.tickCount; - int tickCountSound = entityLiving.livingSoundTime; - int tickIdle = entityLivingBase.idleTime; - JsonObject tickCountList = new JsonObject(); - tickCountList.addProperty("aitasks", tickCount); - tickCountList.addProperty("aitargetTasks", tickCountTarget); - tickCountList.addProperty("livingSoundTime", tickCountSound); - tickCountList.addProperty("idleTime", tickIdle); - dataToSave.add(entityUUID.toString(), tickCountList); - } - } - } - return dataToSave; - } - - @Override - public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { - if (loadedData == null) - return; - for (WorldServer worldServer : server.worlds) { - for (Entity entity : worldServer.loadedEntityList) { - UUID entityUUID = entity.getUniqueID(); - - JsonElement tickCountElement = loadedData.get(entityUUID.toString()); - if (tickCountElement == null) - continue; - JsonObject tickCountList = tickCountElement.getAsJsonObject(); - - int tickCount = tickCountList.get("aitasks").getAsInt(); - int tickCountTarget = tickCountList.get("aitargetTasks").getAsInt(); - int tickCountSound = tickCountList.get("livingSoundTime").getAsInt(); - int tickCountIdle = tickCountList.get("idleTime").getAsInt(); - - if (entity instanceof EntityLiving) { - EntityLiving entityLiving = (EntityLiving) entity; - EntityLivingBase entityLivingBase = (EntityLivingBase) entity; - EntityAITasks tasks = entityLiving.tasks; - EntityAITasks targetTasks = entityLiving.targetTasks; - tasks.tickCount = tickCount; - targetTasks.tickCount = tickCountTarget; - entityLiving.livingSoundTime = tickCountSound; - entityLivingBase.idleTime = tickCountIdle; - } - } - } - } -} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/BatSpawnPositionSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/BatSpawnPositionSubStorage.java new file mode 100644 index 00000000..22cbe1a0 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/BatSpawnPositionSubStorage.java @@ -0,0 +1,46 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.EntityBat; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; + +public class BatSpawnPositionSubStorage implements EntitySubStorage { + + @Override + public String getPropertyName() { + return "batSpawnPositionStorage"; + } + + @Override + public Class getEntityClass() { + return EntityBat.class; + } + + @Override + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + EntityBat bat = (EntityBat) entity; + BlockPos spawnPos = bat.spawnPosition; + if (spawnPos == null) + return dataToSave; + + dataToSave.addProperty("spawnPos", Long.toString(bat.spawnPosition.toLong())); + return dataToSave; + + } + + @Override + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + EntityBat bat = (EntityBat) entity; + JsonElement element = loadedData.get("spawnPos"); + if (element == null) + return bat; + BlockPos spawnPos = BlockPos.fromLong(element.getAsLong()); + bat.spawnPosition = spawnPos; + return bat; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/LivingTickTimersSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/LivingTickTimersSubStorage.java new file mode 100644 index 00000000..ad34d7eb --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/LivingTickTimersSubStorage.java @@ -0,0 +1,72 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAITasks; +import net.minecraft.server.MinecraftServer; + +/** + * Stores the {@link EntityAITasks#tickCount} in a savestate. + * + * AI tasks are only updated every third tick and the tickCount keeps track of that. + * + * @author Scribble + */ +public class LivingTickTimersSubStorage implements EntitySubStorage { + + @Override + public String getPropertyName() { + return "tickTimers"; + } + + @Override + public Class getEntityClass() { + return EntityLiving.class; + } + + @Override + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + EntityLiving entityLiving = (EntityLiving) entity; + EntityLivingBase entityLivingBase = (EntityLivingBase) entity; + EntityAITasks tasks = entityLiving.tasks; + EntityAITasks targetTasks = entityLiving.targetTasks; + int tickCount = tasks.tickCount; + int tickCountTarget = targetTasks.tickCount; + int tickCountSound = entityLiving.livingSoundTime; + int tickIdle = entityLivingBase.idleTime; + dataToSave.addProperty("aitasks", tickCount); + dataToSave.addProperty("aitargetTasks", tickCountTarget); + dataToSave.addProperty("livingSoundTime", tickCountSound); + dataToSave.addProperty("idleTime", tickIdle); + return dataToSave; + } + + @Override + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + + JsonElement tickCount = loadedData.get("aitasks"); + JsonElement tickCountTarget = loadedData.get("aitargetTasks"); + JsonElement tickCountSound = loadedData.get("livingSoundTime"); + JsonElement tickCountIdle = loadedData.get("idleTime"); + + EntityLiving entityLiving = (EntityLiving) entity; + EntityLivingBase entityLivingBase = (EntityLivingBase) entity; + EntityAITasks tasks = entityLiving.tasks; + EntityAITasks targetTasks = entityLiving.targetTasks; + if (tickCount != null) + tasks.tickCount = tickCount.getAsInt(); + if (tickCountTarget != null) + targetTasks.tickCount = tickCountTarget.getAsInt(); + if (tickCountSound != null) + entityLiving.livingSoundTime = tickCountSound.getAsInt(); + if (tickCountIdle != null) + entityLivingBase.idleTime = tickCountIdle.getAsInt(); + + return entityLiving; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/SquidRotationSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/SquidRotationSubStorage.java new file mode 100644 index 00000000..88adc54a --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/SquidRotationSubStorage.java @@ -0,0 +1,48 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.EntitySquid; +import net.minecraft.server.MinecraftServer; + +/** + *

Stores squid rotation in the savestates + *

Did you know that the rotation of the squid can trigger an RNG call? Did you know Minecraft does not save this by default?
+ * Well now you know and it's annoying. + * + * @author Scribble + */ +public class SquidRotationSubStorage implements EntitySubStorage { + + @Override + public String getPropertyName() { + return "squidRotationStorage"; + } + + @Override + public Class getEntityClass() { + return EntitySquid.class; + } + + @Override + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + EntitySquid squid = (EntitySquid) entity; + float rotation = squid.squidRotation; + dataToSave.addProperty("rotation", Float.toString(rotation)); + return dataToSave; + } + + @Override + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + EntitySquid squid = (EntitySquid) entity; + JsonElement rotElement = loadedData.get("rotation"); + if (rotElement == null) + return squid; + float rotation = rotElement.getAsFloat(); + squid.squidRotation = rotation; + return squid; + } +} From f8b1ee8751c0fba703bb8d159b50c05f461cd8d0 Mon Sep 17 00:00:00 2001 From: Scribble Date: Sat, 29 Aug 2026 11:26:39 +0200 Subject: [PATCH 08/26] [Savestates] Fix sub storage not working correctly - Rename package entitysubstorage to just entity - Remove unnecessary accesswideners --- .../java/com/minecrafttas/tasmod/TASmod.java | 8 +-- .../storage/builtin/EntityStorage.java | 4 +- .../BatSpawnPositionSubStorage.java | 3 +- .../entity/CreeperDetonateSubStorage.java | 51 +++++++++++++++++++ .../LivingTickTimersSubStorage.java | 2 +- .../SquidRotationSubStorage.java | 2 +- src/main/resources/tasmod.accesswidener | 25 ++++----- 7 files changed, 71 insertions(+), 24 deletions(-) rename src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/{entitysubstorage => entity}/BatSpawnPositionSubStorage.java (98%) create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java rename src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/{entitysubstorage => entity}/LivingTickTimersSubStorage.java (99%) rename src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/{entitysubstorage => entity}/SquidRotationSubStorage.java (99%) diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 16480d0d..eaa5c845 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -46,9 +46,10 @@ import com.minecrafttas.tasmod.savestates.storage.builtin.EntityAiTaskStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.KTRNGSeedStorage; -import com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage.BatSpawnPositionSubStorage; -import com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage.LivingTickTimersSubStorage; -import com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage.SquidRotationSubStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entity.BatSpawnPositionSubStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entity.CreeperDetonateSubStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entity.LivingTickTimersSubStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entity.SquidRotationSubStorage; import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer; import com.minecrafttas.tasmod.ticksync.TickSyncServer; import com.minecrafttas.tasmod.util.LoggerMarkers; @@ -247,6 +248,7 @@ private void registerSavestateStorage() { TASmodAPIRegistry.SAVESTATE_STORAGE.register( new EntityStorage( new BatSpawnPositionSubStorage(), + new CreeperDetonateSubStorage(), new SquidRotationSubStorage(), new LivingTickTimersSubStorage() ) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java index ff56024a..2aa4763c 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java @@ -32,15 +32,15 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { for (WorldServer worldServer : server.worlds) { for (Entity entity : worldServer.loadedEntityList) { UUID uuid = entity.getUniqueID(); + JsonObject subDataObject = new JsonObject(); for (EntitySubStorage subStorage : subStorages) { - JsonObject subDataObject = new JsonObject(); if (subStorage.getEntityClass().isAssignableFrom(entity.getClass())) { JsonObject subDataToSave = new JsonObject(); subDataToSave = subStorage.onSavestate(server, entity, subDataToSave); subDataObject.add(subStorage.getPropertyName(), subDataToSave); } - dataToSave.add(uuid.toString(), subDataObject); } + dataToSave.add(uuid.toString(), subDataObject); } } return dataToSave; diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/BatSpawnPositionSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/BatSpawnPositionSubStorage.java similarity index 98% rename from src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/BatSpawnPositionSubStorage.java rename to src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/BatSpawnPositionSubStorage.java index 22cbe1a0..0e668810 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/BatSpawnPositionSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/BatSpawnPositionSubStorage.java @@ -1,4 +1,4 @@ -package com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage; +package com.minecrafttas.tasmod.savestates.storage.builtin.entity; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -30,7 +30,6 @@ public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave.addProperty("spawnPos", Long.toString(bat.spawnPosition.toLong())); return dataToSave; - } @Override diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java new file mode 100644 index 00000000..a388a186 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java @@ -0,0 +1,51 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin.entity; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.monster.EntityCreeper; +import net.minecraft.server.MinecraftServer; + +public class CreeperDetonateSubStorage implements EntitySubStorage { + + @Override + public String getPropertyName() { + return "creeperDetonate"; + } + + @Override + public Class getEntityClass() { + return EntityCreeper.class; + } + + @Override + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + EntityCreeper creeper = (EntityCreeper) entity; + dataToSave.addProperty("timeSinceIgnited", creeper.timeSinceIgnited); + dataToSave.addProperty("droppedSkulls", creeper.droppedSkulls); + dataToSave.addProperty("exploding", creeper.getCreeperState()); + return dataToSave; + } + + @Override + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + EntityCreeper creeper = (EntityCreeper) entity; + JsonElement boomTime = loadedData.get("timeSinceIgnited"); + JsonElement dropped = loadedData.get("droppedSkulls"); + JsonElement exploding = loadedData.get("exploding"); + + if (boomTime != null) + creeper.timeSinceIgnited = boomTime.getAsInt(); + + if (dropped != null) + creeper.droppedSkulls = dropped.getAsInt(); + + if (exploding != null) + creeper.setCreeperState(exploding.getAsInt()); + + return entity; + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/LivingTickTimersSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingTickTimersSubStorage.java similarity index 99% rename from src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/LivingTickTimersSubStorage.java rename to src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingTickTimersSubStorage.java index ad34d7eb..bcc854fd 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/LivingTickTimersSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingTickTimersSubStorage.java @@ -1,4 +1,4 @@ -package com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage; +package com.minecrafttas.tasmod.savestates.storage.builtin.entity; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/SquidRotationSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/SquidRotationSubStorage.java similarity index 99% rename from src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/SquidRotationSubStorage.java rename to src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/SquidRotationSubStorage.java index 88adc54a..af36876c 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entitysubstorage/SquidRotationSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/SquidRotationSubStorage.java @@ -1,4 +1,4 @@ -package com.minecrafttas.tasmod.savestates.storage.builtin.entitysubstorage; +package com.minecrafttas.tasmod.savestates.storage.builtin.entity; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 18056f48..02166893 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -28,31 +28,26 @@ accessible field net/minecraft/client/settings/KeyBinding CATEGORY_ORDER Ljava/u accessible field net/minecraft/entity/Entity rand Ljava/util/Random; accessible field net/minecraft/world/World updateLCG I mutable field net/minecraft/world/World rand Ljava/util/Random; -accessible field net/minecraft/entity/EntityLiving tasks Lnet/minecraft/entity/ai/EntityAITasks; -accessible field net/minecraft/entity/EntityLiving targetTasks Lnet/minecraft/entity/ai/EntityAITasks; + +# EntityRNG accessible field net/minecraft/entity/ai/EntityAITasks tickCount I accessible field net/minecraft/entity/passive/EntityBat spawnPosition Lnet/minecraft/util/math/BlockPos; accessible field net/minecraft/entity/Entity nextEntityID I accessible field net/minecraft/entity/EntityLivingBase idleTime I +accessible field net/minecraft/entity/monster/EntityCreeper timeSinceIgnited I +accessible field net/minecraft/entity/monster/EntityCreeper droppedSkulls I + +# EntityAI +accessible field net/minecraft/entity/EntityLiving tasks Lnet/minecraft/entity/ai/EntityAITasks; +accessible field net/minecraft/entity/EntityLiving targetTasks Lnet/minecraft/entity/ai/EntityAITasks; accessible class net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry accessible field net/minecraft/entity/ai/EntityAITasks taskEntries Ljava/util/Set; mutable field net/minecraft/entity/ai/EntityAITasks taskEntries Ljava/util/Set; +mutable field net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry action Lnet/minecraft/entity/ai/EntityAIBase; + accessible field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; mutable field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; -accessible field net/minecraft/entity/ai/EntityAIAvoidEntity canBeSeenSelector Lcom/google/common/base/Predicate; -mutable field net/minecraft/entity/ai/EntityAIAvoidEntity canBeSeenSelector Lcom/google/common/base/Predicate; - -accessible field net/minecraft/entity/ai/EntityAIAvoidEntity avoidTargetSelector Lcom/google/common/base/Predicate; -mutable field net/minecraft/entity/ai/EntityAIAvoidEntity avoidTargetSelector Lcom/google/common/base/Predicate; - -#accessible field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; -#mutable field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntitySelector Lcom/google/common/base/Predicate; -accessible field net/minecraft/entity/ai/EntityAINearestAttackableTarget targetEntity Lnet/minecraft/entity/EntityLivingBase; - -accessible field net/minecraft/entity/ai/EntityAIAvoidEntity entity Lnet/minecraft/entity/EntityCreature; - -mutable field net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry action Lnet/minecraft/entity/ai/EntityAIBase; From fd144a8406acdd21466409e6675f3a3a00fc34f3 Mon Sep 17 00:00:00 2001 From: Scribble Date: Sat, 29 Aug 2026 11:26:39 +0200 Subject: [PATCH 09/26] [Savestates] Fix entity AI not being applied correctly --- .../savestates/storage/builtin/EntityAiTaskStorage.java | 7 ++++--- src/main/resources/tasmod.accesswidener | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 08b60821..37d27828 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -98,6 +98,7 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { mainObject.addProperty("type", entity.getClass().getSimpleName()); mainObject.add("revengeTarget", gsonInstance.toJsonTree(entityLiving.getRevengeTarget())); + mainObject.add("revengeTimer", gsonInstance.toJsonTree(entityLiving.revengeTimer)); mainObject.add("lastAttackedEntity", gsonInstance.toJsonTree(entityLiving.getLastAttackedEntity())); EntityAITasks tasks = entityLiving.tasks; @@ -157,8 +158,8 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { } private void deserialiseAITasks(EntityAITasks tasks, JsonObject jsonTasks) { - deserialiseAIEntries(tasks.taskEntries, tasks, jsonTasks.get("taskEntries").getAsJsonArray()); - deserialiseAIEntries(tasks.executingTaskEntries, tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray()); + tasks.taskEntries = deserialiseAIEntries(tasks.taskEntries, tasks, jsonTasks.get("taskEntries").getAsJsonArray()); + tasks.executingTaskEntries = deserialiseAIEntries(tasks.executingTaskEntries, tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray()); } private Set deserialiseAIEntries(Set taskEntries, EntityAITasks parent, JsonArray jsonEntries) { @@ -198,7 +199,7 @@ private Set deserialiseAIEntries(Set taskE boolean using = jsonEntry.get("using").getAsBoolean(); EntityAIBase action = null; try { - action = gsonInstance.fromJson(jsonEntry, clazz); + action = gsonInstance.fromJson(jsonEntry.get("action"), clazz); } catch (Exception e) { e.printStackTrace(); continue; diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 02166893..000ca1e2 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -33,6 +33,7 @@ mutable field net/minecraft/world/World rand Ljava/util/Random; accessible field net/minecraft/entity/ai/EntityAITasks tickCount I accessible field net/minecraft/entity/passive/EntityBat spawnPosition Lnet/minecraft/util/math/BlockPos; accessible field net/minecraft/entity/Entity nextEntityID I +accessible field net/minecraft/entity/EntityLivingBase revengeTimer I accessible field net/minecraft/entity/EntityLivingBase idleTime I accessible field net/minecraft/entity/monster/EntityCreeper timeSinceIgnited I accessible field net/minecraft/entity/monster/EntityCreeper droppedSkulls I From f25ab40a5cd0c6726710a5da8ff59225b73aec05 Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 31 Aug 2026 22:26:57 +0200 Subject: [PATCH 10/26] [Savestates] Add PathFinding to sub storage --- .../java/com/minecrafttas/tasmod/TASmod.java | 17 +++++-- .../com/minecrafttas/tasmod/TASmodClient.java | 2 +- .../storage/builtin/EntityAiTaskStorage.java | 5 +- .../storage/builtin/EntityStorage.java | 25 ++++++++-- .../entity/BatSpawnPositionSubStorage.java | 5 +- .../entity/CreeperDetonateSubStorage.java | 5 +- .../entity/LivingNavigatorSubStorage.java | 50 +++++++++++++++++++ .../entity/LivingTickTimersSubStorage.java | 5 +- .../entity/SquidRotationSubStorage.java | 5 +- src/main/resources/tasmod.accesswidener | 12 ++++- 10 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index eaa5c845..67665ed0 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -1,6 +1,7 @@ package com.minecrafttas.tasmod; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import org.apache.logging.log4j.LogManager; @@ -48,6 +49,7 @@ import com.minecrafttas.tasmod.savestates.storage.builtin.KTRNGSeedStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.BatSpawnPositionSubStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.CreeperDetonateSubStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.entity.LivingNavigatorSubStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.LivingTickTimersSubStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.SquidRotationSubStorage; import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer; @@ -250,7 +252,8 @@ private void registerSavestateStorage() { new BatSpawnPositionSubStorage(), new CreeperDetonateSubStorage(), new SquidRotationSubStorage(), - new LivingTickTimersSubStorage() + new LivingTickTimersSubStorage(), + new LivingNavigatorSubStorage() ) ); //@formatter:on @@ -262,11 +265,19 @@ public static MinecraftServer getServerInstance() { } private void loadConfig(MinecraftServer server) { - Path configDir = server.getDataDirectory().toPath(); + Path configDir = server.getDataDirectory().toPath().resolve("config"); + + if (!Files.exists(configDir)) { + try { + Files.createDirectory(configDir); + } catch (IOException e) { + LOGGER.catching(e); + } + } ConfigurationRegistry SERVER_CONFIG_REGISTRY = new ConfigurationRegistry(); SERVER_CONFIG_REGISTRY.register(TASmodServerConfig.values()); - config = new Configuration("TASmod Server Configuration", configDir.resolve("tasmod.cfg"), SERVER_CONFIG_REGISTRY); + config = new Configuration("TASmod Server Configuration", configDir.resolve("tasmod_server.cfg"), SERVER_CONFIG_REGISTRY); config.load(); config.save(); diff --git a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java index fca5e374..1d95a651 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java @@ -366,7 +366,7 @@ private void loadConfig(Minecraft mc) { LOGGER.catching(e); } } - config = new Configuration("TASmod configuration", configDir.resolve("tasmod.cfg"), CLIENT_CONFIG_REGISTRY); + config = new Configuration("TASmod configuration", configDir.resolve("tasmod_client.cfg"), CLIENT_CONFIG_REGISTRY); config.load(); config.save(); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 37d27828..24639101 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -169,7 +169,7 @@ private Set deserialiseAIEntries(Set taskE JsonObject jsonEntry = jsonEntryElement.getAsJsonObject(); // Deserialise the type of the AI action -// System.out.println(jsonEntry.get("class").getAsString()); + System.out.println(jsonEntry.get("class").getAsString()); Class clazz; try { clazz = Class.forName(jsonEntry.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(EntityAIBase.class); @@ -179,6 +179,7 @@ private Set deserialiseAIEntries(Set taskE } boolean createNew = true; + boolean using = jsonEntry.get("using").getAsBoolean(); for (EntityAITaskEntry vanillaEntry : taskEntries) { EntityAIBase vanillaAction = vanillaEntry.action; if (vanillaAction.getClass() != clazz) { @@ -187,6 +188,7 @@ private Set deserialiseAIEntries(Set taskE createNew = false; vanillaEntry.action = deserialiseAction(vanillaAction, jsonEntry.get("action"), clazz); + vanillaEntry.using = using; out.add(vanillaEntry); break; } @@ -196,7 +198,6 @@ private Set deserialiseAIEntries(Set taskE } int priority = jsonEntry.get("priority").getAsInt(); - boolean using = jsonEntry.get("using").getAsBoolean(); EntityAIBase action = null; try { action = gsonInstance.fromJson(jsonEntry.get("action"), clazz); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java index 2aa4763c..96f65c8b 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java @@ -4,14 +4,21 @@ import java.util.List; import java.util.UUID; +import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; +import com.minecrafttas.tasmod.savestates.typeadapters.util.ClassExclusionStrategy; import com.minecrafttas.tasmod.util.LoggerMarkers; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.ai.attributes.IAttributeInstance; +import net.minecraft.pathfinding.NodeProcessor; +import net.minecraft.pathfinding.PathFinder; import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; import net.minecraft.world.WorldServer; public class EntityStorage extends SavestateStorageExtensionBase { @@ -23,7 +30,15 @@ public EntityStorage(EntitySubStorage... entitySubStorages) { } public EntityStorage(List entitySubStorages) { - super("entity.json", new GsonBuilder().setPrettyPrinting().create()); + //@formatter:off + super("entity.json", new GsonBuilder().setPrettyPrinting().setExclusionStrategies( + new ClassExclusionStrategy(EntityLiving.class), + new ClassExclusionStrategy(World.class), + new ClassExclusionStrategy(NodeProcessor.class), + new ClassExclusionStrategy(PathFinder.class), + new ClassExclusionStrategy(IAttributeInstance.class) + ).create()); + //@formatter:on this.subStorages = entitySubStorages; } @@ -36,7 +51,7 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { for (EntitySubStorage subStorage : subStorages) { if (subStorage.getEntityClass().isAssignableFrom(entity.getClass())) { JsonObject subDataToSave = new JsonObject(); - subDataToSave = subStorage.onSavestate(server, entity, subDataToSave); + subDataToSave = subStorage.onSavestate(server, entity, subDataToSave, super.gsonInstance); subDataObject.add(subStorage.getPropertyName(), subDataToSave); } } @@ -64,7 +79,7 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { } if (subStorage.getEntityClass().isAssignableFrom(entity.getClass())) { - entity = subStorage.onLoadstatePost(server, entity, subDataObject.get(subStorage.getPropertyName()).getAsJsonObject()); + entity = subStorage.onLoadstatePost(server, entity, subDataObject.get(subStorage.getPropertyName()).getAsJsonObject(), super.gsonInstance); } } } @@ -81,8 +96,8 @@ public static interface EntitySubStorage { public Class getEntityClass(); - public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave); + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave, Gson gsonInstance); - public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData); + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData, Gson gsonInstance); } } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/BatSpawnPositionSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/BatSpawnPositionSubStorage.java index 0e668810..afe2073f 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/BatSpawnPositionSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/BatSpawnPositionSubStorage.java @@ -1,5 +1,6 @@ package com.minecrafttas.tasmod.savestates.storage.builtin.entity; +import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; @@ -22,7 +23,7 @@ public Class getEntityClass() { } @Override - public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave, Gson gsonInstance) { EntityBat bat = (EntityBat) entity; BlockPos spawnPos = bat.spawnPosition; if (spawnPos == null) @@ -33,7 +34,7 @@ public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject } @Override - public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData, Gson gsonInstance) { EntityBat bat = (EntityBat) entity; JsonElement element = loadedData.get("spawnPos"); if (element == null) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java index a388a186..7b9ae5a2 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/CreeperDetonateSubStorage.java @@ -1,5 +1,6 @@ package com.minecrafttas.tasmod.savestates.storage.builtin.entity; +import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; @@ -21,7 +22,7 @@ public Class getEntityClass() { } @Override - public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave, Gson gsonInstance) { EntityCreeper creeper = (EntityCreeper) entity; dataToSave.addProperty("timeSinceIgnited", creeper.timeSinceIgnited); dataToSave.addProperty("droppedSkulls", creeper.droppedSkulls); @@ -30,7 +31,7 @@ public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject } @Override - public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData, Gson gsonInstance) { EntityCreeper creeper = (EntityCreeper) entity; JsonElement boomTime = loadedData.get("timeSinceIgnited"); JsonElement dropped = loadedData.get("droppedSkulls"); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java new file mode 100644 index 00000000..cd70ca36 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java @@ -0,0 +1,50 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin.entity; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.pathfinding.PathNavigate; +import net.minecraft.server.MinecraftServer; + +public class LivingNavigatorSubStorage implements EntitySubStorage { + + @Override + public String getPropertyName() { + return "livingNavigator"; + } + + @Override + public Class getEntityClass() { + return EntityLiving.class; + } + + @Override + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave, Gson gsonInstance) { + EntityLiving entityLiving = (EntityLiving) entity; + dataToSave.add("navigator", gsonInstance.toJsonTree(entityLiving.navigator)); + return dataToSave; + } + + @Override + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData, Gson gsonInstance) { + EntityLiving entityLiving = (EntityLiving) entity; + JsonElement navigatorJson = loadedData.get("navigator"); + if (navigatorJson != null) { + PathNavigate dummyNavigator = entityLiving.createNavigator(entityLiving.world); + PathNavigate navigator = entityLiving.navigator; + navigator = gsonInstance.fromJson(navigatorJson, dummyNavigator.getClass()); + navigator.entity = dummyNavigator.entity; + navigator.world = dummyNavigator.world; + navigator.pathSearchRange = dummyNavigator.pathSearchRange; + navigator.nodeProcessor = dummyNavigator.nodeProcessor; + navigator.pathFinder = dummyNavigator.pathFinder; + } + + return entityLiving; + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingTickTimersSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingTickTimersSubStorage.java index bcc854fd..4f50b1af 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingTickTimersSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingTickTimersSubStorage.java @@ -1,5 +1,6 @@ package com.minecrafttas.tasmod.savestates.storage.builtin.entity; +import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; @@ -30,7 +31,7 @@ public Class getEntityClass() { } @Override - public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave, Gson gsonInstance) { EntityLiving entityLiving = (EntityLiving) entity; EntityLivingBase entityLivingBase = (EntityLivingBase) entity; EntityAITasks tasks = entityLiving.tasks; @@ -47,7 +48,7 @@ public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject } @Override - public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData, Gson gsonInstance) { JsonElement tickCount = loadedData.get("aitasks"); JsonElement tickCountTarget = loadedData.get("aitargetTasks"); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/SquidRotationSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/SquidRotationSubStorage.java index af36876c..0a768eec 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/SquidRotationSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/SquidRotationSubStorage.java @@ -1,5 +1,6 @@ package com.minecrafttas.tasmod.savestates.storage.builtin.entity; +import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.minecrafttas.tasmod.savestates.storage.builtin.EntityStorage.EntitySubStorage; @@ -28,7 +29,7 @@ public Class getEntityClass() { } @Override - public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave) { + public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject dataToSave, Gson gsonInstance) { EntitySquid squid = (EntitySquid) entity; float rotation = squid.squidRotation; dataToSave.addProperty("rotation", Float.toString(rotation)); @@ -36,7 +37,7 @@ public JsonObject onSavestate(MinecraftServer server, Entity entity, JsonObject } @Override - public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData) { + public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject loadedData, Gson gsonInstance) { EntitySquid squid = (EntitySquid) entity; JsonElement rotElement = loadedData.get("rotation"); if (rotElement == null) diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 000ca1e2..224b0f83 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -38,6 +38,17 @@ accessible field net/minecraft/entity/EntityLivingBase idleTime I accessible field net/minecraft/entity/monster/EntityCreeper timeSinceIgnited I accessible field net/minecraft/entity/monster/EntityCreeper droppedSkulls I +# EntityPathFinding +accessible method net/minecraft/entity/EntityLiving createNavigator (Lnet/minecraft/world/World;)Lnet/minecraft/pathfinding/PathNavigate; +accessible field net/minecraft/entity/EntityLiving navigator Lnet/minecraft/pathfinding/PathNavigate; +accessible field net/minecraft/pathfinding/PathNavigate entity Lnet/minecraft/entity/EntityLiving; +accessible field net/minecraft/pathfinding/PathNavigate world Lnet/minecraft/world/World; +accessible field net/minecraft/pathfinding/PathNavigate pathSearchRange Lnet/minecraft/entity/ai/attributes/IAttributeInstance; +mutable field net/minecraft/pathfinding/PathNavigate pathSearchRange Lnet/minecraft/entity/ai/attributes/IAttributeInstance; +accessible field net/minecraft/pathfinding/PathNavigate nodeProcessor Lnet/minecraft/pathfinding/NodeProcessor; +accessible field net/minecraft/pathfinding/PathNavigate pathFinder Lnet/minecraft/pathfinding/PathFinder; +mutable field net/minecraft/pathfinding/PathNavigate pathFinder Lnet/minecraft/pathfinding/PathFinder; + # EntityAI accessible field net/minecraft/entity/EntityLiving tasks Lnet/minecraft/entity/ai/EntityAITasks; accessible field net/minecraft/entity/EntityLiving targetTasks Lnet/minecraft/entity/ai/EntityAITasks; @@ -51,4 +62,3 @@ mutable field net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry action Lne accessible field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; mutable field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; - From 3fc91f9770db561a30ab793e48a7380db94ac8ab Mon Sep 17 00:00:00 2001 From: Scribble Date: Tue, 1 Sep 2026 12:11:18 +0200 Subject: [PATCH 11/26] [KillTheRNG] Add AI task changes to rng log --- .../mixin/savestates/MixinEntityAITasks.java | 25 +++++++++++++++++++ src/main/resources/tasmod.mixin.json | 1 + 2 files changed, 26 insertions(+) create mode 100644 src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java new file mode 100644 index 00000000..6d5280c0 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java @@ -0,0 +1,25 @@ +package com.minecrafttas.tasmod.mixin.savestates; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.llamalad7.mixinextras.sugar.Local; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.ai.EntityAITasks; + +@Mixin(EntityAITasks.class) +public class MixinEntityAITasks { + + @Inject(method = "onUpdateTasks", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/EntityAIBase;resetTask()V")) + public void inject_onUpdateTasks(CallbackInfo ci, @Local(ordinal = 0) EntityAITasks.EntityAITaskEntry entityAITaskEntry) { + TASmod.debugRand.writeDebug(String.format("Removed %s", entityAITaskEntry.action.getClass().getSimpleName())); + } + + @Inject(method = "onUpdateTasks", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/EntityAIBase;startExecuting()V")) + public void inject_onUpdateTasks2(CallbackInfo ci, @Local(ordinal = 0) EntityAITasks.EntityAITaskEntry entityAITaskEntry) { + TASmod.debugRand.writeDebug(String.format("Added %s", entityAITaskEntry.action.getClass().getSimpleName())); + } +} diff --git a/src/main/resources/tasmod.mixin.json b/src/main/resources/tasmod.mixin.json index 535688ab..48c072a2 100644 --- a/src/main/resources/tasmod.mixin.json +++ b/src/main/resources/tasmod.mixin.json @@ -16,6 +16,7 @@ "savestates.MixinChunkProviderServer", "savestates.MixinNetHandlerPlayServer", "savestates.MixinScoreboard", + "savestates.MixinEntityAITasks", // Events "events.MixinEntityPlayerMP", From 3d3e1e61eed64f08b1b57c7ff8021790cb281b0d Mon Sep 17 00:00:00 2001 From: Scribble Date: Tue, 1 Sep 2026 12:11:18 +0200 Subject: [PATCH 12/26] [Savestates] Actually apply the stored pathfinding to the entity --- .../tasmod/savestates/storage/builtin/EntityStorage.java | 4 ++-- .../storage/builtin/entity/LivingNavigatorSubStorage.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java index 96f65c8b..b37e5cf2 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java @@ -34,9 +34,9 @@ public EntityStorage(List entitySubStorages) { super("entity.json", new GsonBuilder().setPrettyPrinting().setExclusionStrategies( new ClassExclusionStrategy(EntityLiving.class), new ClassExclusionStrategy(World.class), + new ClassExclusionStrategy(IAttributeInstance.class), new ClassExclusionStrategy(NodeProcessor.class), - new ClassExclusionStrategy(PathFinder.class), - new ClassExclusionStrategy(IAttributeInstance.class) + new ClassExclusionStrategy(PathFinder.class) ).create()); //@formatter:on this.subStorages = entitySubStorages; diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java index cd70ca36..5b116a32 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/entity/LivingNavigatorSubStorage.java @@ -40,8 +40,10 @@ public Entity onLoadstatePost(MinecraftServer server, Entity entity, JsonObject navigator.entity = dummyNavigator.entity; navigator.world = dummyNavigator.world; navigator.pathSearchRange = dummyNavigator.pathSearchRange; - navigator.nodeProcessor = dummyNavigator.nodeProcessor; navigator.pathFinder = dummyNavigator.pathFinder; + navigator.nodeProcessor = dummyNavigator.nodeProcessor; + + entityLiving.navigator = navigator; } return entityLiving; From e3da8683d33810118648691aeb032aefb6121486 Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 2 Sep 2026 10:13:38 +0200 Subject: [PATCH 13/26] [Savestates] Fixed panic task lasting too long --- .../storage/builtin/EntityAiTaskStorage.java | 13 ++++++++----- src/main/resources/tasmod.accesswidener | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 24639101..73f79c94 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -97,9 +97,10 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { mainObject.addProperty("type", entity.getClass().getSimpleName()); - mainObject.add("revengeTarget", gsonInstance.toJsonTree(entityLiving.getRevengeTarget())); - mainObject.add("revengeTimer", gsonInstance.toJsonTree(entityLiving.revengeTimer)); - mainObject.add("lastAttackedEntity", gsonInstance.toJsonTree(entityLiving.getLastAttackedEntity())); + mainObject.addProperty("ticksExisted", entityLiving.ticksExisted); + mainObject.add("revengeTarget", gsonInstance.toJsonTree(entityLiving.revengeTarget)); + mainObject.addProperty("revengeTimer", entityLiving.revengeTimer); + mainObject.add("lastAttackedEntity", gsonInstance.toJsonTree(entityLiving.lastAttackedEntity)); EntityAITasks tasks = entityLiving.tasks; mainObject.add("tasks", serialiseAITasks(tasks)); @@ -148,8 +149,10 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { JsonObject mainObject = elements.getValue().getAsJsonObject(); - entityLiving.setRevengeTarget((EntityLivingBase) gsonInstance.fromJson(mainObject.get("revengeTarget"), Entity.class)); - entityLiving.setLastAttackedEntity((EntityLivingBase) gsonInstance.fromJson(mainObject.get("lastAttackedEntity"), Entity.class)); + entityLiving.ticksExisted = mainObject.get("ticksExisted").getAsInt(); + entityLiving.revengeTarget = (EntityLivingBase) gsonInstance.fromJson(mainObject.get("revengeTarget"), Entity.class); + entityLiving.revengeTimer = mainObject.get("revengeTimer").getAsInt(); + entityLiving.lastAttackedEntity = (EntityLivingBase) gsonInstance.fromJson(mainObject.get("lastAttackedEntity"), Entity.class); deserialiseAITasks(entityLiving.tasks, mainObject.get("tasks").getAsJsonObject()); deserialiseAITasks(entityLiving.targetTasks, mainObject.get("targetTasks").getAsJsonObject()); diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 224b0f83..36533063 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -33,7 +33,9 @@ mutable field net/minecraft/world/World rand Ljava/util/Random; accessible field net/minecraft/entity/ai/EntityAITasks tickCount I accessible field net/minecraft/entity/passive/EntityBat spawnPosition Lnet/minecraft/util/math/BlockPos; accessible field net/minecraft/entity/Entity nextEntityID I +accessible field net/minecraft/entity/EntityLivingBase revengeTarget Lnet/minecraft/entity/EntityLivingBase; accessible field net/minecraft/entity/EntityLivingBase revengeTimer I +accessible field net/minecraft/entity/EntityLivingBase lastAttackedEntity Lnet/minecraft/entity/EntityLivingBase; accessible field net/minecraft/entity/EntityLivingBase idleTime I accessible field net/minecraft/entity/monster/EntityCreeper timeSinceIgnited I accessible field net/minecraft/entity/monster/EntityCreeper droppedSkulls I From 1316b79cd6429363bc4e7e4fd7c56837a8729780 Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 2 Sep 2026 10:25:56 +0200 Subject: [PATCH 14/26] [Savestates] Remove debug mixin --- .../mixin/savestates/MixinEntityAITasks.java | 25 ------------------- src/main/resources/tasmod.mixin.json | 1 - 2 files changed, 26 deletions(-) delete mode 100644 src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java deleted file mode 100644 index 6d5280c0..00000000 --- a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityAITasks.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.minecrafttas.tasmod.mixin.savestates; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.llamalad7.mixinextras.sugar.Local; -import com.minecrafttas.tasmod.TASmod; - -import net.minecraft.entity.ai.EntityAITasks; - -@Mixin(EntityAITasks.class) -public class MixinEntityAITasks { - - @Inject(method = "onUpdateTasks", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/EntityAIBase;resetTask()V")) - public void inject_onUpdateTasks(CallbackInfo ci, @Local(ordinal = 0) EntityAITasks.EntityAITaskEntry entityAITaskEntry) { - TASmod.debugRand.writeDebug(String.format("Removed %s", entityAITaskEntry.action.getClass().getSimpleName())); - } - - @Inject(method = "onUpdateTasks", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/EntityAIBase;startExecuting()V")) - public void inject_onUpdateTasks2(CallbackInfo ci, @Local(ordinal = 0) EntityAITasks.EntityAITaskEntry entityAITaskEntry) { - TASmod.debugRand.writeDebug(String.format("Added %s", entityAITaskEntry.action.getClass().getSimpleName())); - } -} diff --git a/src/main/resources/tasmod.mixin.json b/src/main/resources/tasmod.mixin.json index 48c072a2..535688ab 100644 --- a/src/main/resources/tasmod.mixin.json +++ b/src/main/resources/tasmod.mixin.json @@ -16,7 +16,6 @@ "savestates.MixinChunkProviderServer", "savestates.MixinNetHandlerPlayServer", "savestates.MixinScoreboard", - "savestates.MixinEntityAITasks", // Events "events.MixinEntityPlayerMP", From 60c09883b1e79b4b38474c1d9d6a5adf553a6cc9 Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 2 Sep 2026 22:42:23 +0200 Subject: [PATCH 15/26] [Savestates] Add attackTarget to savestates --- .../tasmod/savestates/storage/builtin/EntityAiTaskStorage.java | 2 ++ src/main/resources/tasmod.accesswidener | 1 + 2 files changed, 3 insertions(+) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 73f79c94..b220fd5d 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -101,6 +101,7 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { mainObject.add("revengeTarget", gsonInstance.toJsonTree(entityLiving.revengeTarget)); mainObject.addProperty("revengeTimer", entityLiving.revengeTimer); mainObject.add("lastAttackedEntity", gsonInstance.toJsonTree(entityLiving.lastAttackedEntity)); + mainObject.add("attackTarget", gsonInstance.toJsonTree(entityLiving.attackTarget)); EntityAITasks tasks = entityLiving.tasks; mainObject.add("tasks", serialiseAITasks(tasks)); @@ -153,6 +154,7 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { entityLiving.revengeTarget = (EntityLivingBase) gsonInstance.fromJson(mainObject.get("revengeTarget"), Entity.class); entityLiving.revengeTimer = mainObject.get("revengeTimer").getAsInt(); entityLiving.lastAttackedEntity = (EntityLivingBase) gsonInstance.fromJson(mainObject.get("lastAttackedEntity"), Entity.class); + entityLiving.attackTarget = (EntityLivingBase) gsonInstance.fromJson(mainObject.get("attackTarget"), Entity.class); deserialiseAITasks(entityLiving.tasks, mainObject.get("tasks").getAsJsonObject()); deserialiseAITasks(entityLiving.targetTasks, mainObject.get("targetTasks").getAsJsonObject()); diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 36533063..82ee0dbb 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -37,6 +37,7 @@ accessible field net/minecraft/entity/EntityLivingBase revengeTarget Lnet/minecr accessible field net/minecraft/entity/EntityLivingBase revengeTimer I accessible field net/minecraft/entity/EntityLivingBase lastAttackedEntity Lnet/minecraft/entity/EntityLivingBase; accessible field net/minecraft/entity/EntityLivingBase idleTime I +accessible field net/minecraft/entity/EntityLiving attackTarget Lnet/minecraft/entity/EntityLivingBase; accessible field net/minecraft/entity/monster/EntityCreeper timeSinceIgnited I accessible field net/minecraft/entity/monster/EntityCreeper droppedSkulls I From 9184634f5814581bcd27c99a43b09b0afc9016c8 Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 2 Sep 2026 22:42:23 +0200 Subject: [PATCH 16/26] [Savestates] Store fields from super class in entityai --- .../storage/builtin/EntityAiTaskStorage.java | 59 +++++++++++++++---- .../minecrafttas/tasmod/util/JsonUtils.java | 10 ++++ 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index b220fd5d..9c71932c 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -1,7 +1,9 @@ package com.minecrafttas.tasmod.savestates.storage.builtin; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map.Entry; @@ -17,6 +19,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.internal.ConstructorConstructor; +import com.google.gson.reflect.TypeToken; import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; import com.minecrafttas.tasmod.savestates.typeadapters.BlockPosTypeAdapterFactory; @@ -26,6 +30,7 @@ import com.minecrafttas.tasmod.savestates.typeadapters.ItemTypeAdapter; import com.minecrafttas.tasmod.savestates.typeadapters.WorldTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.util.ClassExclusionStrategy; +import com.minecrafttas.tasmod.util.JsonUtils; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; @@ -126,20 +131,35 @@ private JsonArray serialiseAIEntries(Set taskEntries) { JsonArray serialisedEntries = new JsonArray(); for (EntityAITasks.EntityAITaskEntry entry : taskEntries) { JsonObject jsonAiTaskEntry = new JsonObject(); + Class clazz = entry.action.getClass(); jsonAiTaskEntry.addProperty("priority", entry.priority); jsonAiTaskEntry.addProperty("using", entry.using); - jsonAiTaskEntry.addProperty("class", entry.action.getClass().getName()); + jsonAiTaskEntry.addProperty("class", clazz.getName()); + try { - System.out.println(entry.action.getClass().getName()); - jsonAiTaskEntry.add("action", gsonInstance.toJsonTree(entry.action)); + System.out.println(clazz.getName()); + jsonAiTaskEntry.add("action", serializeAction(entry.action, clazz)); } catch (Exception e) { throw new SavestateException(e, "Could not serialise AI Task %s", entry.action.getClass().getName()); } + serialisedEntries.add(jsonAiTaskEntry); } return serialisedEntries; } + private JsonObject serializeAction(EntityAIBase action, Class clazz) { + @SuppressWarnings("unchecked") + Class superclazz = (Class) clazz.getSuperclass(); + + JsonObject out = new JsonObject(); + + if (superclazz != EntityAIBase.class) + out = serializeAction(action, superclazz); + + return JsonUtils.mergeJsonObjects(out, gsonInstance.toJsonTree(action, clazz).getAsJsonObject()); + } + @Override public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { for (Entry elements : loadedData.entrySet()) { @@ -192,7 +212,7 @@ private Set deserialiseAIEntries(Set taskE } createNew = false; - vanillaEntry.action = deserialiseAction(vanillaAction, jsonEntry.get("action"), clazz); + vanillaEntry.action = deserialiseAction(vanillaAction, jsonEntry.get("action")); vanillaEntry.using = using; out.add(vanillaEntry); break; @@ -201,11 +221,12 @@ private Set deserialiseAIEntries(Set taskE if (!createNew) { continue; } - int priority = jsonEntry.get("priority").getAsInt(); - EntityAIBase action = null; + ConstructorConstructor constructor = new ConstructorConstructor(Collections.emptyMap(), true, Collections.emptyList()); + TypeToken token = TypeToken.get(clazz); + EntityAIBase action = constructor.get(token, true).construct(); try { - action = gsonInstance.fromJson(jsonEntry.get("action"), clazz); + action = deserialiseAction(action, jsonEntry.get("action")); } catch (Exception e) { e.printStackTrace(); continue; @@ -217,11 +238,11 @@ private Set deserialiseAIEntries(Set taskE return out; } - private EntityAIBase deserialiseAction(EntityAIBase vanillaAction, JsonElement json, Class clazz) { + private EntityAIBase deserialiseAction(EntityAIBase action, JsonElement json) { JsonObject jsonObject = json.getAsJsonObject(); - List vanillaFields = Arrays.asList(vanillaAction.getClass().getDeclaredFields()); + List fields = getFieldList(action.getClass()); - for (Field field : vanillaFields) { + for (Field field : fields) { field.setAccessible(true); String fieldname = field.getName(); Class fieldClass = field.getType(); @@ -233,12 +254,26 @@ private EntityAIBase deserialiseAction(EntityAIBase vanillaAction, JsonElement j Object deserialised = gsonInstance.fromJson(value, fieldClass); try { - field.set(vanillaAction, deserialised); + field.set(action, deserialised); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } - return vanillaAction; + return action; + } + + private List getFieldList(Class clazz) { + @SuppressWarnings("unchecked") + Class superclazz = (Class) clazz.getSuperclass(); + List out = new ArrayList<>(); + + if (superclazz != EntityAIBase.class) { + out.addAll(getFieldList(superclazz)); + } + + out.addAll(Arrays.asList(clazz.getDeclaredFields())); + + return out; } } diff --git a/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java b/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java index 549ca1ce..7bea7360 100644 --- a/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java +++ b/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java @@ -30,4 +30,14 @@ public static JsonObject loadJson(Path loadPath) throws IOException { public static JsonObject loadJson(Path loadPath, Gson gsonInstance) throws IOException { return gsonInstance.fromJson(new String(Files.readAllBytes(loadPath)), JsonObject.class); } + + public static JsonObject mergeJsonObjects(JsonObject json1, JsonObject json2) { + JsonObject merged = json1; + json2.keySet().forEach(key -> { + if (!merged.has(key)) { + merged.add(key, json2.get(key)); + } + }); + return merged; + } } From 022bf428a6149a69c0c04556c38dc4e36e313926 Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 9 Sep 2026 09:50:29 +0200 Subject: [PATCH 17/26] [Savestates] Failing to add a type adapter for path navigate --- .../java/com/minecrafttas/tasmod/TASmod.java | 4 +- .../storage/builtin/EntityAiTaskStorage.java | 17 +- .../storage/builtin/EntityStorage.java | 5 +- .../PathNavigateTypeAdapterFactory.java | 155 ++++++++++++++++++ .../minecrafttas/tasmod/util/JsonUtils.java | 9 + 5 files changed, 180 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 67665ed0..f228985e 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -49,7 +49,6 @@ import com.minecrafttas.tasmod.savestates.storage.builtin.KTRNGSeedStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.BatSpawnPositionSubStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.CreeperDetonateSubStorage; -import com.minecrafttas.tasmod.savestates.storage.builtin.entity.LivingNavigatorSubStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.LivingTickTimersSubStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.entity.SquidRotationSubStorage; import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer; @@ -252,8 +251,7 @@ private void registerSavestateStorage() { new BatSpawnPositionSubStorage(), new CreeperDetonateSubStorage(), new SquidRotationSubStorage(), - new LivingTickTimersSubStorage(), - new LivingNavigatorSubStorage() + new LivingTickTimersSubStorage() ) ); //@formatter:on diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 9c71932c..8dd8da91 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -3,7 +3,6 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map.Entry; @@ -19,8 +18,6 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.internal.ConstructorConstructor; -import com.google.gson.reflect.TypeToken; import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; import com.minecrafttas.tasmod.savestates.typeadapters.BlockPosTypeAdapterFactory; @@ -28,6 +25,7 @@ import com.minecrafttas.tasmod.savestates.typeadapters.EntityLivingTypeAdapter; import com.minecrafttas.tasmod.savestates.typeadapters.EntityTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.ItemTypeAdapter; +import com.minecrafttas.tasmod.savestates.typeadapters.PathNavigateTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.WorldTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.util.ClassExclusionStrategy; import com.minecrafttas.tasmod.util.JsonUtils; @@ -40,6 +38,10 @@ import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry; import net.minecraft.item.Item; import net.minecraft.pathfinding.PathNavigate; +import net.minecraft.pathfinding.PathNavigateClimber; +import net.minecraft.pathfinding.PathNavigateFlying; +import net.minecraft.pathfinding.PathNavigateGround; +import net.minecraft.pathfinding.PathNavigateSwimmer; import net.minecraft.server.MinecraftServer; import net.minecraft.world.WorldServer; @@ -65,6 +67,10 @@ public EntityAiTaskStorage() { ) .registerTypeAdapter(Item.class, new ItemTypeAdapter()) .registerTypeAdapter(EntityLivingTypeAdapter.class, new EntityLivingTypeAdapter()) + .registerTypeAdapter(PathNavigateGround.class, new PathNavigateTypeAdapterFactory()) + .registerTypeAdapter(PathNavigateClimber.class, new PathNavigateTypeAdapterFactory()) + .registerTypeAdapter(PathNavigateFlying.class, new PathNavigateTypeAdapterFactory()) + .registerTypeAdapter(PathNavigateSwimmer.class, new PathNavigateTypeAdapterFactory()) .setExclusionStrategies(new ExclusionStrategy() { @Override @@ -222,9 +228,8 @@ private Set deserialiseAIEntries(Set taskE continue; } int priority = jsonEntry.get("priority").getAsInt(); - ConstructorConstructor constructor = new ConstructorConstructor(Collections.emptyMap(), true, Collections.emptyList()); - TypeToken token = TypeToken.get(clazz); - EntityAIBase action = constructor.get(token, true).construct(); + + EntityAIBase action = JsonUtils.constructNew(clazz); try { action = deserialiseAction(action, jsonEntry.get("action")); } catch (Exception e) { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java index b37e5cf2..6b4e1cbd 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java @@ -9,6 +9,7 @@ import com.google.gson.JsonObject; import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; +import com.minecrafttas.tasmod.savestates.typeadapters.PathNavigateTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.util.ClassExclusionStrategy; import com.minecrafttas.tasmod.util.LoggerMarkers; @@ -37,7 +38,9 @@ public EntityStorage(List entitySubStorages) { new ClassExclusionStrategy(IAttributeInstance.class), new ClassExclusionStrategy(NodeProcessor.class), new ClassExclusionStrategy(PathFinder.class) - ).create()); + ) + .registerTypeAdapterFactory(new PathNavigateTypeAdapterFactory()) + .create()); //@formatter:on this.subStorages = entitySubStorages; } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java new file mode 100644 index 00000000..b299aeb6 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java @@ -0,0 +1,155 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.ai.attributes.IAttributeInstance; +import net.minecraft.pathfinding.NodeProcessor; +import net.minecraft.pathfinding.PathFinder; +import net.minecraft.pathfinding.PathNavigate; +import net.minecraft.world.World; + +public class PathNavigateTypeAdapterFactory implements TypeAdapterFactory { + +// @Override +// public JsonElement serialize(PathNavigate src, Type typeOfSrc, JsonSerializationContext context) { +// JsonObject out = new JsonObject(); +// out.addProperty("class", src.getClass().getSimpleName()); +// +// List fields = Arrays.asList(src.getClass().getDeclaredFields()); +// fields.addAll(Arrays.asList(src.getClass().getSuperclass().getDeclaredFields())); +// for (Field field : fields) { +// field.setAccessible(true); +// if (field.getType() == IAttributeInstance.class || field.getType() == PathFinder.class || field.getType() == NodeProcessor.class) { +// continue; +// } +// if (field.getType() == EntityLiving.class) { +// out.add("entity", context.serialize(src.entity)); +// continue; +// } +// if (field.getType() == World.class) { +// out.add("world", context.serialize(src.world)); +// continue; +// } +// try { +// out.add(field.getName(), context.serialize(field.get(src))); +// } catch (IllegalArgumentException | IllegalAccessException e) { +// e.printStackTrace(); +// } +// } +// return out; +// } + + @Override + public PathNavigate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonObj = json.getAsJsonObject(); + + Class clazz; + try { + clazz = Class.forName(jsonObj.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(PathNavigate.class); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + + EntityLiving entity = context.deserialize(jsonObj.get("entity"), EntityLiving.class); + World world = context.deserialize(jsonObj.get("world"), World.class); + + PathNavigate navigator; + try { + navigator = clazz.getConstructor(EntityLiving.class, World.class).newInstance(entity, world); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + e.printStackTrace(); + return null; + } + + List fields = Arrays.asList(navigator.getClass().getDeclaredFields()); + fields.addAll(Arrays.asList(navigator.getClass().getSuperclass().getDeclaredFields())); + for (Field field : fields) { + field.setAccessible(true); + if (field.getType() == IAttributeInstance.class || field.getType() == PathFinder.class || field.getType() == NodeProcessor.class || field.getType() == EntityLiving.class || field.getType() == World.class) { + continue; + } + try { + field.set(navigator, context.deserialize(jsonObj.get(field.getName()), field.getType())); + } catch (IllegalArgumentException | IllegalAccessException | JsonParseException e) { + e.printStackTrace(); + continue; + } + } + + return navigator; + } + + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!World.class.isAssignableFrom(rawType)) + return null; + + @SuppressWarnings("unused") + final TypeAdapterFactory factory = this; + + return new TypeAdapter() { + + @Override + public void write(JsonWriter outWriter, T value) throws IOException { + JsonObject out = new JsonObject(); + PathNavigate src = (PathNavigate) value; + + List fields = Arrays.asList(src.getClass().getDeclaredFields()); + fields.addAll(Arrays.asList(src.getClass().getSuperclass().getDeclaredFields())); + for (Field field : fields) { + field.setAccessible(true); + Class fieldClass = field.getType(); + if (fieldClass == IAttributeInstance.class || fieldClass == PathFinder.class || fieldClass == NodeProcessor.class) { + continue; + } + if (field.getType() == EntityLiving.class) { + JsonElement tree = gson.getAdapter(new TypeToken() { + }).toJsonTree(src.entity); + out.add("entity", tree); + continue; + } + if (field.getType() == World.class) { + JsonElement tree = gson.getDelegateAdapter(factory, new TypeToken() { + }).toJsonTree(src.world); + out.add("world", tree); + continue; + } + try { + TypeAdapter adapter = gson.getDelegateAdapter(factory, TypeToken.get(fieldClass)); + out.add(field.getName(), adapter.toJsonTree(field.get(src))); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + @Override + public T read(JsonReader in) throws IOException { + // TODO Auto-generated method stub + return null; + } + + }; + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java b/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java index 7bea7360..f676bfb1 100644 --- a/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java +++ b/src/main/java/com/minecrafttas/tasmod/util/JsonUtils.java @@ -3,10 +3,13 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; +import com.google.gson.internal.ConstructorConstructor; +import com.google.gson.reflect.TypeToken; public class JsonUtils { @@ -40,4 +43,10 @@ public static JsonObject mergeJsonObjects(JsonObject json1, JsonObject json2) { }); return merged; } + + public static T constructNew(Class clazz) { + ConstructorConstructor constructor = new ConstructorConstructor(Collections.emptyMap(), true, Collections.emptyList()); + TypeToken token = TypeToken.get(clazz); + return constructor.get(token, true).construct(); + } } From d757f2d62f1e290693b0c3912b621e2f11ba01af Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 9 Sep 2026 09:50:29 +0200 Subject: [PATCH 18/26] [MCTCommon] Create Gson Wrapper --- .../mctcommon/json/FineField.java | 58 +++++ .../minecrafttas/mctcommon/json/FineGson.java | 49 ++++ .../mctcommon/json/FineTypeAdapter.java | 146 ++++++++++++ .../storage/builtin/EntityStorage.java | 3 +- .../PathNavigateTypeAdapterFactory.java | 221 ++++++++---------- .../java/mctcommon/json/FineGsonTest.java | 116 +++++++++ 6 files changed, 468 insertions(+), 125 deletions(-) create mode 100644 src/main/java/com/minecrafttas/mctcommon/json/FineField.java create mode 100644 src/main/java/com/minecrafttas/mctcommon/json/FineGson.java create mode 100644 src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java create mode 100644 src/test/java/mctcommon/json/FineGsonTest.java diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineField.java b/src/main/java/com/minecrafttas/mctcommon/json/FineField.java new file mode 100644 index 00000000..b606dc03 --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineField.java @@ -0,0 +1,58 @@ +package com.minecrafttas.mctcommon.json; + +import com.google.gson.JsonElement; + +public class FineField { + + private final String name; + private final FineMode mode; + private final FineSerializer serializer; + private final FineDeserializer deserializer; + + public FineField(String name, FineMode mode) { + this.name = name; + this.mode = mode; + this.serializer = null; + this.deserializer = null; + } + + public FineField(String name, FineSerializer serializer, FineDeserializer deserializer) { + this.name = name; + this.mode = FineMode.CUSTOM; + this.serializer = serializer; + this.deserializer = deserializer; + } + + public static enum FineMode { + FINE, + EXCLUDED, + GSON, + CUSTOM; + } + + public String getName() { + return name; + } + + public FineMode getMode() { + return mode; + } + + public JsonElement serialize(Object obj) { + return serializer.serialize(obj); + } + + public Object deserialize(JsonElement element) { + return deserializer.deserialize(element); + } + + @FunctionalInterface + public static interface FineSerializer { + public JsonElement serialize(Object obj); + } + + @FunctionalInterface + public static interface FineDeserializer { + public Object deserialize(JsonElement element); + } +} diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java new file mode 100644 index 00000000..b0a26328 --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java @@ -0,0 +1,49 @@ +package com.minecrafttas.mctcommon.json; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; + +/** + * A fine grained gson replacement + * + * @author Scribble + */ +public class FineGson { + + private Map, FineTypeAdapter> typeAdapters = new HashMap<>(); + + private final Gson gsonInstance; + + public FineGson(Gson gsonInstance) { + this.gsonInstance = gsonInstance; + } + + public void registerTypeAdapter(Class type, FineTypeAdapter adapter) { + typeAdapters.put(type, adapter); + } + + public JsonElement serialize(Object obj) { + Class type = obj.getClass(); + if (!typeAdapters.containsKey(type)) + return gsonInstance.toJsonTree(obj); + + FineTypeAdapter adapter = typeAdapters.get(type); + return adapter.serialize(obj, this); + } + + public Object deserialize(JsonElement element, Class type) { + if (!typeAdapters.containsKey(type)) + return gsonInstance.fromJson(element, type); + + FineTypeAdapter adapter = typeAdapters.get(type); + + return adapter.deserialize(element, type, this); + } + + public Gson getGsonInstance() { + return gsonInstance; + } +} diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java new file mode 100644 index 00000000..2063ff5c --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java @@ -0,0 +1,146 @@ +package com.minecrafttas.mctcommon.json; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.mctcommon.json.FineField.FineDeserializer; +import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineField.FineSerializer; +import com.minecrafttas.tasmod.util.JsonUtils; + +public abstract class FineTypeAdapter { + + private final List fineFields = new ArrayList<>(); + + private final List additionalFields = new ArrayList<>(); + + public void register(String name, FineMode mode) { + register(new FineField(name, mode)); + } + + public void register(String name, FineSerializer customSerializer, FineDeserializer customDeserializer) { + register(new FineField(name, customSerializer, customDeserializer)); + } + + public void register(FineField field) { + this.fineFields.add(field); + } + + public void registerAdditional(String name, FineSerializer customSerializer, FineDeserializer customDeserializer) { + this.additionalFields.add(new FineField(name, customSerializer, customDeserializer)); + } + + public JsonElement serialize(Object obj, FineGson fineJson) throws RuntimeException { + JsonObject out = new JsonObject(); + + Class clazz = obj.getClass(); + List clazzFields = getFieldList(clazz); + + if (clazzFields.size() != fineFields.size()) { + throw new RuntimeException(String.format("Can't serialize %s: The field count differs: %s!=%s", clazz.getSimpleName(), clazzFields.size(), fineFields.size())); + } + + for (int i = 0; i < clazzFields.size(); i++) { + Field field = clazzFields.get(i); + FineField fineField = fineFields.get(i); + + Object fieldValue = null; + try { + field.setAccessible(true); + fieldValue = field.get(obj); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + continue; + } + + String fieldName = fineField.getName(); + System.out.println(String.format("[%s] Serializing field %s (%s)", obj.getClass(), field.getName(), fieldName)); + switch (fineField.getMode()) { + case CUSTOM: + out.add(fieldName, fineField.serialize(fieldValue)); + break; + case FINE: + out.add(fieldName, fineJson.serialize(fieldValue)); + break; + case GSON: + out.add(fieldName, fineJson.getGsonInstance().toJsonTree(fieldValue)); + break; + + case EXCLUDED: + default: + break; + } + } + + for (FineField fineField : additionalFields) { + out.add(fineField.getName(), fineField.serialize(null)); + } + return out; + } + + public Object deserialize(JsonElement element, Class clazz, FineGson fineJson) { + List clazzFields = getFieldList(clazz); + + if (clazzFields.size() != fineFields.size()) { + throw new RuntimeException(String.format("Can't deserialize %s: The field count differs: %s!=%s", clazz.getSimpleName(), clazzFields.size(), fineFields.size())); + } + + JsonObject elementObj = element.getAsJsonObject(); + + Object out = constructNew(clazz); + + for (int i = 0; i < clazzFields.size(); i++) { + Field field = clazzFields.get(i); + field.setAccessible(true); + FineField fineField = fineFields.get(i); + String fieldName = fineField.getName(); + JsonElement fieldElement = elementObj.get(fieldName); + + Object fieldValue = null; + switch (fineField.getMode()) { + case CUSTOM: + fieldValue = fineField.deserialize(fieldElement); + break; + case FINE: + fieldValue = fineJson.deserialize(fieldElement, field.getType()); + break; + case GSON: + fieldValue = fineJson.getGsonInstance().fromJson(fieldElement, field.getType()); + break; + + case EXCLUDED: + default: + break; + } + if (fieldValue != null) { + try { + field.set(out, fieldValue); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + return out; + } + + protected Object constructNew(Class clazz) { + return JsonUtils.constructNew(clazz); + } + + public static List getFieldList(Class clazz) { + List fields = new ArrayList<>(); + for (Field field : clazz.getDeclaredFields()) { + if (!field.getName().startsWith("this")) + fields.add(field); + } + + Class superclazz = clazz.getSuperclass(); + if (superclazz != Object.class) + fields.addAll(getFieldList(superclazz)); + + return fields; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java index 6b4e1cbd..816a885a 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityStorage.java @@ -9,7 +9,6 @@ import com.google.gson.JsonObject; import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; -import com.minecrafttas.tasmod.savestates.typeadapters.PathNavigateTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.util.ClassExclusionStrategy; import com.minecrafttas.tasmod.util.LoggerMarkers; @@ -39,7 +38,7 @@ public EntityStorage(List entitySubStorages) { new ClassExclusionStrategy(NodeProcessor.class), new ClassExclusionStrategy(PathFinder.class) ) - .registerTypeAdapterFactory(new PathNavigateTypeAdapterFactory()) +// .registerTypeAdapterFactory(new PathNavigateTypeAdapterFactory()) .create()); //@formatter:on this.subStorages = entitySubStorages; diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java index b299aeb6..75911a6e 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapterFactory.java @@ -1,31 +1,6 @@ package com.minecrafttas.tasmod.savestates.typeadapters; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.List; - -import com.google.gson.Gson; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.ai.attributes.IAttributeInstance; -import net.minecraft.pathfinding.NodeProcessor; -import net.minecraft.pathfinding.PathFinder; -import net.minecraft.pathfinding.PathNavigate; -import net.minecraft.world.World; - -public class PathNavigateTypeAdapterFactory implements TypeAdapterFactory { +public class PathNavigateTypeAdapterFactory { // @Override // public JsonElement serialize(PathNavigate src, Type typeOfSrc, JsonSerializationContext context) { @@ -55,101 +30,101 @@ public class PathNavigateTypeAdapterFactory implements TypeAdapterFactory { // } // return out; // } - - @Override - public PathNavigate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - JsonObject jsonObj = json.getAsJsonObject(); - - Class clazz; - try { - clazz = Class.forName(jsonObj.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(PathNavigate.class); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - return null; - } - - EntityLiving entity = context.deserialize(jsonObj.get("entity"), EntityLiving.class); - World world = context.deserialize(jsonObj.get("world"), World.class); - - PathNavigate navigator; - try { - navigator = clazz.getConstructor(EntityLiving.class, World.class).newInstance(entity, world); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { - e.printStackTrace(); - return null; - } - - List fields = Arrays.asList(navigator.getClass().getDeclaredFields()); - fields.addAll(Arrays.asList(navigator.getClass().getSuperclass().getDeclaredFields())); - for (Field field : fields) { - field.setAccessible(true); - if (field.getType() == IAttributeInstance.class || field.getType() == PathFinder.class || field.getType() == NodeProcessor.class || field.getType() == EntityLiving.class || field.getType() == World.class) { - continue; - } - try { - field.set(navigator, context.deserialize(jsonObj.get(field.getName()), field.getType())); - } catch (IllegalArgumentException | IllegalAccessException | JsonParseException e) { - e.printStackTrace(); - continue; - } - } - - return navigator; - } - - @SuppressWarnings("unchecked") - @Override - public TypeAdapter create(Gson gson, TypeToken type) { - Class rawType = (Class) type.getRawType(); - if (!World.class.isAssignableFrom(rawType)) - return null; - - @SuppressWarnings("unused") - final TypeAdapterFactory factory = this; - - return new TypeAdapter() { - - @Override - public void write(JsonWriter outWriter, T value) throws IOException { - JsonObject out = new JsonObject(); - PathNavigate src = (PathNavigate) value; - - List fields = Arrays.asList(src.getClass().getDeclaredFields()); - fields.addAll(Arrays.asList(src.getClass().getSuperclass().getDeclaredFields())); - for (Field field : fields) { - field.setAccessible(true); - Class fieldClass = field.getType(); - if (fieldClass == IAttributeInstance.class || fieldClass == PathFinder.class || fieldClass == NodeProcessor.class) { - continue; - } - if (field.getType() == EntityLiving.class) { - JsonElement tree = gson.getAdapter(new TypeToken() { - }).toJsonTree(src.entity); - out.add("entity", tree); - continue; - } - if (field.getType() == World.class) { - JsonElement tree = gson.getDelegateAdapter(factory, new TypeToken() { - }).toJsonTree(src.world); - out.add("world", tree); - continue; - } - try { - TypeAdapter adapter = gson.getDelegateAdapter(factory, TypeToken.get(fieldClass)); - out.add(field.getName(), adapter.toJsonTree(field.get(src))); - } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - } - } - - @Override - public T read(JsonReader in) throws IOException { - // TODO Auto-generated method stub - return null; - } - - }; - } - +// +// @Override +// public PathNavigate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { +// JsonObject jsonObj = json.getAsJsonObject(); +// +// Class clazz; +// try { +// clazz = Class.forName(jsonObj.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(PathNavigate.class); +// } catch (ClassNotFoundException e) { +// e.printStackTrace(); +// return null; +// } +// +// EntityLiving entity = context.deserialize(jsonObj.get("entity"), EntityLiving.class); +// World world = context.deserialize(jsonObj.get("world"), World.class); +// +// PathNavigate navigator; +// try { +// navigator = clazz.getConstructor(EntityLiving.class, World.class).newInstance(entity, world); +// } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { +// e.printStackTrace(); +// return null; +// } +// +// List fields = Arrays.asList(navigator.getClass().getDeclaredFields()); +// fields.addAll(Arrays.asList(navigator.getClass().getSuperclass().getDeclaredFields())); +// for (Field field : fields) { +// field.setAccessible(true); +// if (field.getType() == IAttributeInstance.class || field.getType() == PathFinder.class || field.getType() == NodeProcessor.class || field.getType() == EntityLiving.class || field.getType() == World.class) { +// continue; +// } +// try { +// field.set(navigator, context.deserialize(jsonObj.get(field.getName()), field.getType())); +// } catch (IllegalArgumentException | IllegalAccessException | JsonParseException e) { +// e.printStackTrace(); +// continue; +// } +// } +// +// return navigator; +// } +// +// @SuppressWarnings("unchecked") +// @Override +// public TypeAdapter create(Gson gson, TypeToken type) { +// Class rawType = (Class) type.getRawType(); +// if (!World.class.isAssignableFrom(rawType)) +// return null; +// +// @SuppressWarnings("unused") +// final TypeAdapterFactory factory = this; +// +// return new TypeAdapter() { +// +// @Override +// public void write(JsonWriter outWriter, T value) throws IOException { +// JsonObject out = new JsonObject(); +// PathNavigate src = (PathNavigate) value; +// +// List fields = Arrays.asList(src.getClass().getDeclaredFields()); +// fields.addAll(Arrays.asList(src.getClass().getSuperclass().getDeclaredFields())); +// for (Field field : fields) { +// field.setAccessible(true); +// Class fieldClass = field.getType(); +// if (fieldClass == IAttributeInstance.class || fieldClass == PathFinder.class || fieldClass == NodeProcessor.class) { +// continue; +// } +// if (field.getType() == EntityLiving.class) { +// JsonElement tree = gson.getAdapter(new TypeToken() { +// }).toJsonTree(src.entity); +// out.add("entity", tree); +// continue; +// } +// if (field.getType() == World.class) { +// JsonElement tree = gson.getDelegateAdapter(factory, new TypeToken() { +// }).toJsonTree(src.world); +// out.add("world", tree); +// continue; +// } +// try { +// TypeAdapter adapter = gson.getDelegateAdapter(factory, TypeToken.get(fieldClass)); +// out.add(field.getName(), adapter.toJsonTree(field.get(src))); +// } catch (IllegalArgumentException | IllegalAccessException e) { +// e.printStackTrace(); +// } +// } +// } +// +// @Override +// public T read(JsonReader in) throws IOException { +// // TODO Auto-generated method stub +// return null; +// } +// +// }; +// } +// } diff --git a/src/test/java/mctcommon/json/FineGsonTest.java b/src/test/java/mctcommon/json/FineGsonTest.java new file mode 100644 index 00000000..599fc70f --- /dev/null +++ b/src/test/java/mctcommon/json/FineGsonTest.java @@ -0,0 +1,116 @@ +package mctcommon.json; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineGson; +import com.minecrafttas.mctcommon.json.FineTypeAdapter; + +class FineGsonTest { + + private class TestClass extends TestSuperClass { + private int index = 7; + private String lol = "Laughing out loud"; + private TestSubClass subClass = new TestSubClass(); + private boolean excluded = false; + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestClass) { + TestClass other = (TestClass) obj; + return index == other.index && lol.equals(other.lol) && subClass.equals(other.subClass) && excluded == other.excluded && bot == other.bot && evil.equals(evil); + } + return super.equals(obj); + } + } + + private class TestSubClass { + private boolean isWater = true; + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestSubClass) { + TestSubClass other = (TestSubClass) obj; + return isWater == other.isWater; + } + return super.equals(obj); + } + } + + private static class TestSuperClass { + protected long bot = 8999; + protected String evil = "Squids are evil!"; + } + + private static class TestClassTypeAdapter extends FineTypeAdapter { + public TestClassTypeAdapter() { + register("index", FineMode.FINE); + register("lol", FineMode.GSON); + register("subClass", FineMode.FINE); + register("excluded", FineMode.EXCLUDED); + register("bot", FineMode.FINE); + register("evil", obj -> new JsonPrimitive(((String) obj).toUpperCase()), element -> element.toString()); + } + } + + private static class TestSubClassAdapter extends FineTypeAdapter { + public TestSubClassAdapter() { + register("isWater", FineMode.FINE); + } + } + + static FineGson fgson; + + @BeforeAll + static void beforeAll() { + fgson = new FineGson(new GsonBuilder().setPrettyPrinting().create()); + fgson.registerTypeAdapter(TestClass.class, new TestClassTypeAdapter()); + fgson.registerTypeAdapter(TestSubClass.class, new TestSubClassAdapter()); + } + + @Test + void testSerialization() { + TestClass test = new TestClass(); + JsonObject actual = fgson.serialize(test).getAsJsonObject(); + + JsonObject expected = new JsonObject(); + expected.addProperty("index", 7); + expected.addProperty("lol", "Laughing out loud"); + JsonObject expectedSubClass = new JsonObject(); + expectedSubClass.addProperty("isWater", true); + expected.add("subClass", expectedSubClass); + expected.addProperty("bot", 8999); + expected.addProperty("evil", "SQUIDS ARE EVIL!"); + + assertEquals(expected, actual); + } + + @Test + void testDeserialization() { + JsonObject testObj = new JsonObject(); + testObj.addProperty("index", 5); + testObj.addProperty("lol", "Laughing quietly"); + JsonObject testObjSubClass = new JsonObject(); + testObjSubClass.addProperty("isWater", false); + testObj.add("subClass", testObjSubClass); + testObj.addProperty("bot", 9000); + testObj.addProperty("evil", "SQUIDS ARE STILL EVIL!"); + + TestClass actual = (TestClass) fgson.deserialize(testObj, TestClass.class); + + TestClass expected = new TestClass(); + expected.index = 5; + expected.lol = "Laughing quietly"; + expected.subClass.isWater = false; + expected.bot = 9000; + expected.evil = "SQUIDS ARE STILL EVIL!"; + + assertEquals(expected, actual); + } +} From 977853417554af00071204a7dd58840b2eec379a Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 11 Sep 2026 22:55:38 +0200 Subject: [PATCH 19/26] [MCTCommon] Add TypeAdapterGenerator --- .../mctcommon/json/FineTarget.java | 10 ++++ .../json/FineTypeAdapterGenerator.java | 59 +++++++++++++++++++ .../storage/builtin/EntityAiTaskStorage.java | 9 --- ...yAINearestAttackableTargetTypeAdapter.java | 28 +++++++++ .../json/FineTypeAdapterGeneratorTest.java | 19 ++++++ 5 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java create mode 100644 src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java create mode 100644 src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java new file mode 100644 index 00000000..e7cf654f --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java @@ -0,0 +1,10 @@ +package com.minecrafttas.mctcommon.json; + +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Target; + +@Target(TYPE) +public @interface FineTarget { + Class value(); +} diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java new file mode 100644 index 00000000..5c6ace2f --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java @@ -0,0 +1,59 @@ +package com.minecrafttas.mctcommon.json; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FineTypeAdapterGenerator { + + protected final String packagge; + + public FineTypeAdapterGenerator(Path out, String packagge) { + out = out.resolve("typeadapters2"); + try { + Files.createDirectories(out); + } catch (IOException e) { + e.printStackTrace(); + } + this.packagge = packagge; + } + + public void generate(T object) { + + Class clazz = object.getClass(); + List content = generateClass(clazz); + } + + public static List generateClass(Class clazz) { + List out = new ArrayList<>(); + String className = clazz.getSimpleName(); + List fields = FineTypeAdapter.getFieldList(clazz); + + out.addAll(Arrays.asList(String.format("package com.minecrafttas.tasmod.savestates.typeadapters;\n" + + "\n" + + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" + + "import com.minecrafttas.mctcommon.json.FineTarget;\n" + + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" + + "\n" + + "import %s;\n" + + "\n" + + "@FineTarget(%s.class)\n" + + "public class %sTypeAdapter extends FineTypeAdapter {\n" + + "\n" + + "\tpublic %sTypeAdapter() {", clazz.getName(), className, className, className).split("\n"))); + + for (Field field : fields) { + out.add(String.format("\t\tregister(\"%s\", FineMode.FINE);", field.getName())); + } + + out.addAll(Arrays.asList(String.format("\t}\n" + + "}\n" + + "\n").split("\n"))); + + return out; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 8dd8da91..78a76075 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -25,7 +25,6 @@ import com.minecrafttas.tasmod.savestates.typeadapters.EntityLivingTypeAdapter; import com.minecrafttas.tasmod.savestates.typeadapters.EntityTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.ItemTypeAdapter; -import com.minecrafttas.tasmod.savestates.typeadapters.PathNavigateTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.WorldTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.util.ClassExclusionStrategy; import com.minecrafttas.tasmod.util.JsonUtils; @@ -38,10 +37,6 @@ import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry; import net.minecraft.item.Item; import net.minecraft.pathfinding.PathNavigate; -import net.minecraft.pathfinding.PathNavigateClimber; -import net.minecraft.pathfinding.PathNavigateFlying; -import net.minecraft.pathfinding.PathNavigateGround; -import net.minecraft.pathfinding.PathNavigateSwimmer; import net.minecraft.server.MinecraftServer; import net.minecraft.world.WorldServer; @@ -67,10 +62,6 @@ public EntityAiTaskStorage() { ) .registerTypeAdapter(Item.class, new ItemTypeAdapter()) .registerTypeAdapter(EntityLivingTypeAdapter.class, new EntityLivingTypeAdapter()) - .registerTypeAdapter(PathNavigateGround.class, new PathNavigateTypeAdapterFactory()) - .registerTypeAdapter(PathNavigateClimber.class, new PathNavigateTypeAdapterFactory()) - .registerTypeAdapter(PathNavigateFlying.class, new PathNavigateTypeAdapterFactory()) - .registerTypeAdapter(PathNavigateSwimmer.class, new PathNavigateTypeAdapterFactory()) .setExclusionStrategies(new ExclusionStrategy() { @Override diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java new file mode 100644 index 00000000..bb17a056 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java @@ -0,0 +1,28 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineTarget; +import com.minecrafttas.mctcommon.json.FineTypeAdapter; + +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; + +@FineTarget(EntityAINearestAttackableTarget.class) +public class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { + + public EntityAINearestAttackableTargetTypeAdapter() { + register("targetClass", FineMode.FINE); + register("targetChance", FineMode.FINE); + register("sorter", FineMode.FINE); + register("targetEntitySelector", FineMode.FINE); + register("targetEntity", FineMode.FINE); + register("taskOwner", FineMode.FINE); + register("shouldCheckSight", FineMode.FINE); + register("nearbyOnly", FineMode.FINE); + register("targetSearchStatus", FineMode.FINE); + register("targetSearchDelay", FineMode.FINE); + register("targetUnseenTicks", FineMode.FINE); + register("target", FineMode.FINE); + register("unseenMemoryTicks", FineMode.FINE); + register("mutexBits", FineMode.FINE); + } +} diff --git a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java new file mode 100644 index 00000000..71deedba --- /dev/null +++ b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java @@ -0,0 +1,19 @@ +package mctcommon.json; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.minecrafttas.mctcommon.json.FineTypeAdapterGenerator; + +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; + +class FineTypeAdapterGeneratorTest { + + @Test + void testGenerate() { + List actual = FineTypeAdapterGenerator.generateClass(EntityAINearestAttackableTarget.class); + System.out.println(String.join("\n", actual)); + } + +} From c1680821ad1e585cf03be330b91afa38743b501b Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 21 Sep 2026 11:44:27 +0200 Subject: [PATCH 20/26] [MCTCommon] Continue typeadapter generator - Add ability to register type adapters with an annotation - Generate superclasses seperately - Add tests --- .../minecrafttas/mctcommon/json/FineGson.java | 56 +++++++++- .../mctcommon/json/FineMultiTarget.java | 13 +++ .../mctcommon/json/FineTarget.java | 5 +- .../mctcommon/json/FineTypeAdapter.java | 33 ++++-- .../json/FineTypeAdapterGenerator.java | 99 ++++++++++++----- ...yAINearestAttackableTargetTypeAdapter.java | 28 ----- .../typeadapters/EntityAITypeAdapters.java | 33 ++++++ .../java/mctcommon/json/FineGsonTest.java | 60 +++++++--- .../json/FineTypeAdapterGeneratorTest.java | 105 +++++++++++++++++- 9 files changed, 340 insertions(+), 92 deletions(-) create mode 100644 src/main/java/com/minecrafttas/mctcommon/json/FineMultiTarget.java delete mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java index b0a26328..b66a9cae 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java @@ -1,10 +1,14 @@ package com.minecrafttas.mctcommon.json; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import com.google.gson.Gson; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; /** * A fine grained gson replacement @@ -21,17 +25,55 @@ public FineGson(Gson gsonInstance) { this.gsonInstance = gsonInstance; } + public void registerTypeAdapter(Class type) { + if (type.isAnnotationPresent(FineMultiTarget.class)) { + List> classes = Arrays.asList(type.getDeclaredClasses()); + for (Class clazz : classes) { + registerTypeAdapter(clazz); + } + } + if (type.isAnnotationPresent(FineTarget.class)) { + if (!FineTypeAdapter.class.isAssignableFrom(type)) { + throw new RuntimeException(String.format("Trying to register type adapter %s, but it doesn't extend FineTypeAdapter", type.getName())); + } + Class targetType = type.getAnnotation(FineTarget.class).value(); + FineTypeAdapter adapter; + try { + adapter = (FineTypeAdapter) type.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(String.format("Failed to instantiate type adapter %s", type.getName()), e); + } + registerTypeAdapter(targetType, adapter); + } + } + public void registerTypeAdapter(Class type, FineTypeAdapter adapter) { typeAdapters.put(type, adapter); } public JsonElement serialize(Object obj) { Class type = obj.getClass(); + return serialize(obj, type); + } + + public JsonElement serialize(Object obj, Class type) { if (!typeAdapters.containsKey(type)) return gsonInstance.toJsonTree(obj); FineTypeAdapter adapter = typeAdapters.get(type); - return adapter.serialize(obj, this); + JsonElement out = adapter.serialize(obj, this, type).getAsJsonObject(); + + Class superclass = type.getSuperclass(); + if (superclass != Object.class) { + JsonObject superObject = serialize(obj, superclass).getAsJsonObject(); + JsonObject jsonObj = out.getAsJsonObject(); + for (Entry objects : superObject.entrySet()) { + jsonObj.add(objects.getKey(), objects.getValue()); + } + out = jsonObj; + } + + return out; } public Object deserialize(JsonElement element, Class type) { @@ -39,11 +81,21 @@ public Object deserialize(JsonElement element, Class type) { return gsonInstance.fromJson(element, type); FineTypeAdapter adapter = typeAdapters.get(type); + Object out = adapter.deserialize(element, type, this); - return adapter.deserialize(element, type, this); + Class superclass = type.getSuperclass(); + if (superclass != Object.class) { + FineTypeAdapter superadapter = typeAdapters.get(superclass); + out = superadapter.deserialize(element, superclass, this, out); + } + return out; } public Gson getGsonInstance() { return gsonInstance; } + + public Map, FineTypeAdapter> getTypeAdapters() { + return typeAdapters; + } } diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineMultiTarget.java b/src/main/java/com/minecrafttas/mctcommon/json/FineMultiTarget.java new file mode 100644 index 00000000..2743de3d --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineMultiTarget.java @@ -0,0 +1,13 @@ +package com.minecrafttas.mctcommon.json; + +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface FineMultiTarget { + +} diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java index e7cf654f..13916c07 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java @@ -2,9 +2,12 @@ import static java.lang.annotation.ElementType.TYPE; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(TYPE) +@Retention(RetentionPolicy.RUNTIME) public @interface FineTarget { Class value(); -} +} \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java index 2063ff5c..f509df60 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java @@ -34,9 +34,13 @@ public void registerAdditional(String name, FineSerializer customSerializer, Fin } public JsonElement serialize(Object obj, FineGson fineJson) throws RuntimeException { + Class clazz = obj.getClass(); + return serialize(obj, fineJson, clazz); + } + + public JsonElement serialize(Object obj, FineGson fineJson, Class clazz) throws RuntimeException { JsonObject out = new JsonObject(); - Class clazz = obj.getClass(); List clazzFields = getFieldList(clazz); if (clazzFields.size() != fineFields.size()) { @@ -57,7 +61,7 @@ public JsonElement serialize(Object obj, FineGson fineJson) throws RuntimeExcept } String fieldName = fineField.getName(); - System.out.println(String.format("[%s] Serializing field %s (%s)", obj.getClass(), field.getName(), fieldName)); + System.out.println(String.format("[%s|%s] Serializing field %s (%s)", obj.getClass(), clazz, field.getName(), fieldName)); switch (fineField.getMode()) { case CUSTOM: out.add(fieldName, fineField.serialize(fieldValue)); @@ -82,6 +86,11 @@ public JsonElement serialize(Object obj, FineGson fineJson) throws RuntimeExcept } public Object deserialize(JsonElement element, Class clazz, FineGson fineJson) { + Object obj = constructNew(clazz); + return deserialize(element, clazz, fineJson, obj); + } + + public Object deserialize(JsonElement element, Class clazz, FineGson fineJson, Object obj) { List clazzFields = getFieldList(clazz); if (clazzFields.size() != fineFields.size()) { @@ -90,8 +99,6 @@ public Object deserialize(JsonElement element, Class clazz, FineGson fineJson JsonObject elementObj = element.getAsJsonObject(); - Object out = constructNew(clazz); - for (int i = 0; i < clazzFields.size(); i++) { Field field = clazzFields.get(i); field.setAccessible(true); @@ -117,30 +124,34 @@ public Object deserialize(JsonElement element, Class clazz, FineGson fineJson } if (fieldValue != null) { try { - field.set(out, fieldValue); + field.set(obj, fieldValue); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } } - return out; + return obj; } protected Object constructNew(Class clazz) { return JsonUtils.constructNew(clazz); } + public static List getFieldListWithSuperclass(Class clazz) { + List fields = getFieldList(clazz); + Class superclazz = clazz.getSuperclass(); + if (superclazz != Object.class) + fields.addAll(getFieldListWithSuperclass(superclazz)); + + return fields; + } + public static List getFieldList(Class clazz) { List fields = new ArrayList<>(); for (Field field : clazz.getDeclaredFields()) { if (!field.getName().startsWith("this")) fields.add(field); } - - Class superclazz = clazz.getSuperclass(); - if (superclazz != Object.class) - fields.addAll(getFieldList(superclazz)); - return fields; } } diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java index 5c6ace2f..32a9cd3c 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java @@ -1,59 +1,100 @@ package com.minecrafttas.mctcommon.json; -import java.io.IOException; import java.lang.reflect.Field; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; public class FineTypeAdapterGenerator { + protected final String className; + protected final String packagge; - public FineTypeAdapterGenerator(Path out, String packagge) { - out = out.resolve("typeadapters2"); - try { - Files.createDirectories(out); - } catch (IOException e) { - e.printStackTrace(); - } + protected final List importLines = new ArrayList<>(); + protected final Map, List> classLines = new LinkedHashMap<>(); + + public FineTypeAdapterGenerator(String className, String packagge) { + this.className = className; this.packagge = packagge; + fillDefaultImports(); } - public void generate(T object) { + protected void fillDefaultImports() { + importLines.add("import com.minecrafttas.mctcommon.json.FineField.FineMode;"); + importLines.add("import com.minecrafttas.mctcommon.json.FineTarget;"); + importLines.add("import com.minecrafttas.mctcommon.json.FineTypeAdapter;"); + importLines.add(""); + } - Class clazz = object.getClass(); - List content = generateClass(clazz); + public List generate() { + List out = new ArrayList<>(); + out.add(String.format("package %s;", packagge)); + out.add(""); + out.addAll(importLines); + out.add(""); + Collection> classLines = this.classLines.values(); + classLines.forEach(e -> e.forEach(e1 -> out.add(e1))); + return out; } - public static List generateClass(Class clazz) { + public List generateMulti() { List out = new ArrayList<>(); - String className = clazz.getSimpleName(); + out.add(String.format("package %s;", packagge)); + out.add(""); + out.addAll(importLines); + out.add(""); + out.add("@FineMultiTarget"); + out.add(String.format("public class %s {", className)); + out.add(""); + Collection> classLines = this.classLines.values(); + classLines.forEach(e -> e.forEach(e1 -> out.add("\t" + e1))); + out.add("}"); + return out; + } + + public void addClass(Class... classes) { + for (Class clazz : classes) { + addClass(clazz); + } + } + + public void addClass(T object) { + Class clazz = object.getClass(); + addClass(clazz); + } + + public void addClass(Class clazz) { + if (classLines.containsKey(clazz)) + return; + + Class superclazz = clazz.getSuperclass(); + if (superclazz != Object.class) + addClass(superclazz); + + String clazzName = clazz.getSimpleName(); List fields = FineTypeAdapter.getFieldList(clazz); - out.addAll(Arrays.asList(String.format("package com.minecrafttas.tasmod.savestates.typeadapters;\n" - + "\n" - + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" - + "import com.minecrafttas.mctcommon.json.FineTarget;\n" - + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" - + "\n" - + "import %s;\n" - + "\n" + importLines.add(String.format("import %s;", clazz.getName())); + classLines.put(clazz, splitNewLine(String.format("" + "@FineTarget(%s.class)\n" + "public class %sTypeAdapter extends FineTypeAdapter {\n" + "\n" - + "\tpublic %sTypeAdapter() {", clazz.getName(), className, className, className).split("\n"))); + + "\tpublic %sTypeAdapter() {", clazzName, clazzName, clazzName))); for (Field field : fields) { - out.add(String.format("\t\tregister(\"%s\", FineMode.FINE);", field.getName())); + classLines.get(clazz).add(String.format("\t\tregister(\"%s\", FineMode.FINE);", field.getName())); } - out.addAll(Arrays.asList(String.format("\t}\n" - + "}\n" - + "\n").split("\n"))); + classLines.get(clazz).add("\t}"); + classLines.get(clazz).add("}"); + classLines.get(clazz).add(""); + } - return out; + protected List splitNewLine(String text) { + return new ArrayList<>(Arrays.asList(text.split("\n"))); } } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java deleted file mode 100644 index bb17a056..00000000 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAINearestAttackableTargetTypeAdapter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.minecrafttas.tasmod.savestates.typeadapters; - -import com.minecrafttas.mctcommon.json.FineField.FineMode; -import com.minecrafttas.mctcommon.json.FineTarget; -import com.minecrafttas.mctcommon.json.FineTypeAdapter; - -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; - -@FineTarget(EntityAINearestAttackableTarget.class) -public class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { - - public EntityAINearestAttackableTargetTypeAdapter() { - register("targetClass", FineMode.FINE); - register("targetChance", FineMode.FINE); - register("sorter", FineMode.FINE); - register("targetEntitySelector", FineMode.FINE); - register("targetEntity", FineMode.FINE); - register("taskOwner", FineMode.FINE); - register("shouldCheckSight", FineMode.FINE); - register("nearbyOnly", FineMode.FINE); - register("targetSearchStatus", FineMode.FINE); - register("targetSearchDelay", FineMode.FINE); - register("targetUnseenTicks", FineMode.FINE); - register("target", FineMode.FINE); - register("unseenMemoryTicks", FineMode.FINE); - register("mutexBits", FineMode.FINE); - } -} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java new file mode 100644 index 00000000..7a4c21e7 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java @@ -0,0 +1,33 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineMultiTarget; +import com.minecrafttas.mctcommon.json.FineTarget; +import com.minecrafttas.mctcommon.json.FineTypeAdapter; + +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; + +@FineMultiTarget +public class EntityAITypeAdapters { + + @FineTarget(EntityAINearestAttackableTarget.class) + public static class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { + + public EntityAINearestAttackableTargetTypeAdapter() { + register("targetClass", FineMode.FINE); + register("targetChance", FineMode.FINE); + register("sorter", FineMode.FINE); + register("targetEntitySelector", FineMode.FINE); + register("targetEntity", FineMode.FINE); + register("taskOwner", FineMode.FINE); + register("shouldCheckSight", FineMode.FINE); + register("nearbyOnly", FineMode.FINE); + register("targetSearchStatus", FineMode.FINE); + register("targetSearchDelay", FineMode.FINE); + register("targetUnseenTicks", FineMode.FINE); + register("target", FineMode.FINE); + register("unseenMemoryTicks", FineMode.FINE); + register("mutexBits", FineMode.FINE); + } + } +} diff --git a/src/test/java/mctcommon/json/FineGsonTest.java b/src/test/java/mctcommon/json/FineGsonTest.java index 599fc70f..7335b00e 100644 --- a/src/test/java/mctcommon/json/FineGsonTest.java +++ b/src/test/java/mctcommon/json/FineGsonTest.java @@ -2,7 +2,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.BeforeAll; +import java.util.HashSet; +import java.util.Set; + import org.junit.jupiter.api.Test; import com.google.gson.GsonBuilder; @@ -10,6 +12,8 @@ import com.google.gson.JsonPrimitive; import com.minecrafttas.mctcommon.json.FineField.FineMode; import com.minecrafttas.mctcommon.json.FineGson; +import com.minecrafttas.mctcommon.json.FineMultiTarget; +import com.minecrafttas.mctcommon.json.FineTarget; import com.minecrafttas.mctcommon.json.FineTypeAdapter; class FineGsonTest { @@ -48,35 +52,41 @@ private static class TestSuperClass { protected String evil = "Squids are evil!"; } - private static class TestClassTypeAdapter extends FineTypeAdapter { + @FineMultiTarget + @FineTarget(TestClass.class) + public static class TestClassTypeAdapter extends FineTypeAdapter { public TestClassTypeAdapter() { register("index", FineMode.FINE); register("lol", FineMode.GSON); register("subClass", FineMode.FINE); register("excluded", FineMode.EXCLUDED); - register("bot", FineMode.FINE); - register("evil", obj -> new JsonPrimitive(((String) obj).toUpperCase()), element -> element.toString()); } - } - private static class TestSubClassAdapter extends FineTypeAdapter { - public TestSubClassAdapter() { - register("isWater", FineMode.FINE); + @FineTarget(TestSuperClass.class) + public static class TestSuperClassAdapter extends FineTypeAdapter { + public TestSuperClassAdapter() { + register("bot", FineMode.FINE); + register("evil", obj -> new JsonPrimitive(((String) obj).toUpperCase()), element -> element.toString()); + } } - } - - static FineGson fgson; - @BeforeAll - static void beforeAll() { - fgson = new FineGson(new GsonBuilder().setPrettyPrinting().create()); - fgson.registerTypeAdapter(TestClass.class, new TestClassTypeAdapter()); - fgson.registerTypeAdapter(TestSubClass.class, new TestSubClassAdapter()); + @FineTarget(TestSubClass.class) + public static class TestSubClassAdapter extends FineTypeAdapter { + public TestSubClassAdapter() { + register("isWater", FineMode.FINE); + } + } } @Test void testSerialization() { TestClass test = new TestClass(); + + FineGson fgson = new FineGson(new GsonBuilder().setPrettyPrinting().create()); + fgson.registerTypeAdapter(TestClass.class, new TestClassTypeAdapter()); + fgson.registerTypeAdapter(TestSubClass.class, new mctcommon.json.FineGsonTest.TestClassTypeAdapter.TestSubClassAdapter()); + fgson.registerTypeAdapter(TestSuperClass.class, new mctcommon.json.FineGsonTest.TestClassTypeAdapter.TestSuperClassAdapter()); + JsonObject actual = fgson.serialize(test).getAsJsonObject(); JsonObject expected = new JsonObject(); @@ -102,6 +112,10 @@ void testDeserialization() { testObj.addProperty("bot", 9000); testObj.addProperty("evil", "SQUIDS ARE STILL EVIL!"); + FineGson fgson = new FineGson(new GsonBuilder().setPrettyPrinting().create()); + fgson.registerTypeAdapter(TestClass.class, new TestClassTypeAdapter()); + fgson.registerTypeAdapter(TestSubClass.class, new mctcommon.json.FineGsonTest.TestClassTypeAdapter.TestSubClassAdapter()); + fgson.registerTypeAdapter(TestSuperClass.class, new mctcommon.json.FineGsonTest.TestClassTypeAdapter.TestSuperClassAdapter()); TestClass actual = (TestClass) fgson.deserialize(testObj, TestClass.class); TestClass expected = new TestClass(); @@ -113,4 +127,18 @@ void testDeserialization() { assertEquals(expected, actual); } + + @Test + void testAnnotationRegistration() { + FineGson fgson = new FineGson(new GsonBuilder().setPrettyPrinting().create()); + fgson.registerTypeAdapter(TestClassTypeAdapter.class); + Set> actual = fgson.getTypeAdapters().keySet(); + + Set> expected = new HashSet<>(); + expected.add(TestClass.class); + expected.add(TestSubClass.class); + expected.add(TestSuperClass.class); + + assertEquals(expected, actual); + } } diff --git a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java index 71deedba..978a33cd 100644 --- a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java +++ b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java @@ -1,19 +1,114 @@ package mctcommon.json; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; import com.minecrafttas.mctcommon.json.FineTypeAdapterGenerator; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; - class FineTypeAdapterGeneratorTest { + private class TestClass extends TestSuperClass { + private int index = 7; + private String lol = "Laughing out loud"; + private TestSubClass subClass = new TestSubClass(); + private boolean excluded = false; + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestClass) { + TestClass other = (TestClass) obj; + return index == other.index && lol.equals(other.lol) && subClass.equals(other.subClass) && excluded == other.excluded && bot == other.bot && evil.equals(evil); + } + return super.equals(obj); + } + } + + private class TestSubClass { + private boolean isWater = true; + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestSubClass) { + TestSubClass other = (TestSubClass) obj; + return isWater == other.isWater; + } + return super.equals(obj); + } + } + + private static class TestSuperClass { + protected long bot = 8999; + protected String evil = "Squids are evil!"; + } + @Test - void testGenerate() { - List actual = FineTypeAdapterGenerator.generateClass(EntityAINearestAttackableTarget.class); - System.out.println(String.join("\n", actual)); + void testGenerateMulti() { + FineTypeAdapterGenerator generator = new FineTypeAdapterGenerator("GeneratedTypeAdapterTest", "typeadapter"); + generator.addClass(TestClass.class); + List actual = generator.generateMulti(); + List expected = Arrays.asList(String.format("package typeadapter;\n" + + "\n" + + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" + + "import com.minecrafttas.mctcommon.json.FineTarget;\n" + + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" + + "\n" + + "import mctcommon.json.FineTypeAdapterGeneratorTest$TestSuperClass;\n" + + "import mctcommon.json.FineTypeAdapterGeneratorTest$TestClass;\n" + + "\n" + + "@FineMultiTarget\n" + + "public class GeneratedTypeAdapterTest {\n" + + "\n" + + " @FineTarget(TestSuperClass.class)\n" + + " public class TestSuperClassTypeAdapter extends FineTypeAdapter {\n" + + " \n" + + " public TestSuperClassTypeAdapter() {\n" + + " register(\"bot\", FineMode.FINE);\n" + + " register(\"evil\", FineMode.FINE);\n" + + " }\n" + + " }\n" + + " \n" + + " @FineTarget(TestClass.class)\n" + + " public class TestClassTypeAdapter extends FineTypeAdapter {\n" + + " \n" + + " public TestClassTypeAdapter() {\n" + + " register(\"index\", FineMode.FINE);\n" + + " register(\"lol\", FineMode.FINE);\n" + + " register(\"subClass\", FineMode.FINE);\n" + + " register(\"excluded\", FineMode.FINE);\n" + + " }\n" + + " }\n" + + " \n" + + "}").split("\n")); + assertIterableEquals(expected, actual); } + @Test + void testGenerateSingle() { + FineTypeAdapterGenerator generator = new FineTypeAdapterGenerator("GeneratedTypeAdapterTest", "typeadapter"); + generator.addClass(TestSubClass.class); + List actual = generator.generate(); + List expected = new ArrayList<>(Arrays.asList(String.format("package typeadapter;\n" + + "\n" + + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" + + "import com.minecrafttas.mctcommon.json.FineTarget;\n" + + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" + + "\n" + + "import mctcommon.json.FineTypeAdapterGeneratorTest$TestSubClass;\n" + + "\n" + + "@FineTarget(TestSubClass.class)\n" + + "public class TestSubClassTypeAdapter extends FineTypeAdapter {\n" + + "\n" + + " public TestSubClassTypeAdapter() {\n" + + " register(\"isWater\", FineMode.FINE);\n" + + " }\n" + + "}\n" + + "\n").split("\n"))); + expected.add(""); + assertIterableEquals(expected, actual); + } } From d78bb2611034f4edc09f279961273f171c4ee38e Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 21 Sep 2026 13:21:11 +0200 Subject: [PATCH 21/26] [Savestates] Generate EntityAI typeadapters --- .../json/FineTypeAdapterGenerator.java | 5 +- .../java/com/minecrafttas/tasmod/TASmod.java | 3 + .../savestates/TypeAdapterGenerator.java | 20 + .../tasmod/registries/TASmodKeybinds.java | 14 +- .../typeadapters/EntityAITypeAdapters.java | 1000 ++++++++++++++++- src/main/resources/tasmod.accesswidener | 44 + src/main/resources/tasmod.mixin.json | 1 + .../json/FineTypeAdapterGeneratorTest.java | 2 + 8 files changed, 1074 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java index 32a9cd3c..8a8f3acf 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java @@ -25,6 +25,7 @@ public FineTypeAdapterGenerator(String className, String packagge) { protected void fillDefaultImports() { importLines.add("import com.minecrafttas.mctcommon.json.FineField.FineMode;"); + importLines.add("import com.minecrafttas.mctcommon.json.FineMultiTarget;"); importLines.add("import com.minecrafttas.mctcommon.json.FineTarget;"); importLines.add("import com.minecrafttas.mctcommon.json.FineTypeAdapter;"); importLines.add(""); @@ -78,12 +79,12 @@ public void addClass(Class clazz) { String clazzName = clazz.getSimpleName(); List fields = FineTypeAdapter.getFieldList(clazz); - importLines.add(String.format("import %s;", clazz.getName())); +// importLines.add(String.format("import %s;", clazz.getName())); classLines.put(clazz, splitNewLine(String.format("" + "@FineTarget(%s.class)\n" + "public class %sTypeAdapter extends FineTypeAdapter {\n" + "\n" - + "\tpublic %sTypeAdapter() {", clazzName, clazzName, clazzName))); + + "\tpublic %sTypeAdapter() {", clazz.getName().replace("$", "."), clazzName, clazzName))); for (Field field : fields) { classLines.get(clazz).add(String.format("\t\tregister(\"%s\", FineMode.FINE);", field.getName())); diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index f228985e..5f947540 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -14,6 +14,7 @@ import com.minecrafttas.mctcommon.events.EventServer.EventServerInit; import com.minecrafttas.mctcommon.events.EventServer.EventServerStart; import com.minecrafttas.mctcommon.events.EventServer.EventServerStop; +import com.minecrafttas.mctcommon.json.FineTypeAdapterGenerator; import com.minecrafttas.mctcommon.networking.PacketHandlerRegistry; import com.minecrafttas.mctcommon.networking.Server; import com.minecrafttas.tasmod.commands.CommandClearInputs; @@ -121,6 +122,8 @@ public class TASmod implements ModInitializer, EventServerStart, EventServerInit public static Configuration config; + public static FineTypeAdapterGenerator generator = new FineTypeAdapterGenerator("EntityAITypeAdapters", "com.minecrafttas.tasmod.savestates.typeadapters"); + @Override public void onInitialize() { diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java new file mode 100644 index 00000000..ef493b8a --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java @@ -0,0 +1,20 @@ +package com.minecrafttas.tasmod.mixin.savestates; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.ai.EntityAIBase; + +@Mixin(EntityAIBase.class) +public class TypeAdapterGenerator { + @Inject(method = "", at = @At("RETURN")) + public void inject_aiBase(CallbackInfo ci) { + EntityAIBase thisObj = (EntityAIBase) (Object) this; + System.out.println(thisObj); + TASmod.generator.addClass(thisObj.getClass()); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java index d0a5c4a4..8454fb1f 100644 --- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java +++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java @@ -1,10 +1,16 @@ package com.minecrafttas.tasmod.registries; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + import org.lwjgl.input.Keyboard; import com.minecrafttas.mctcommon.KeybindManager.IsKeyDownFunc; import com.minecrafttas.mctcommon.KeybindManager.Keybind; import com.minecrafttas.mctcommon.KeybindManager.KeybindID; +import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.networking.TASmodBufferBuilder; import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate; @@ -46,9 +52,13 @@ public enum TASmodKeybinds implements KeybindID { TASmodClient.virtual.CAMERA_ANGLE.updateNextCameraAngle(0, 45); }), TEST1("Various Testing", "TASmod", Keyboard.KEY_F12, () -> { + /* + * Yes, I am really generating TypeAdapter code here and replacing the class file. + * This is how we did it before AI kids. + */ try { - TASmodClient.client.send(new TASmodBufferBuilder(TASmodPackets.PLAYBACK_STATE_TEMP_SAVESTATE).writeEnum(TASstate.RECORDING)); - } catch (Exception e) { + Files.write(Paths.get("../src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java"), TASmod.generator.generateMulti(), StandardOpenOption.CREATE); + } catch (IOException e) { e.printStackTrace(); } }, VirtualKeybindings::isKeyDown), diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java index 7a4c21e7..afbd2fc9 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java @@ -5,20 +5,89 @@ import com.minecrafttas.mctcommon.json.FineTarget; import com.minecrafttas.mctcommon.json.FineTypeAdapter; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; - @FineMultiTarget public class EntityAITypeAdapters { - @FineTarget(EntityAINearestAttackableTarget.class) - public static class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { + @FineTarget(net.minecraft.entity.ai.EntityAIBase.class) + public class EntityAIBaseTypeAdapter extends FineTypeAdapter { - public EntityAINearestAttackableTargetTypeAdapter() { - register("targetClass", FineMode.FINE); - register("targetChance", FineMode.FINE); - register("sorter", FineMode.FINE); - register("targetEntitySelector", FineMode.FINE); - register("targetEntity", FineMode.FINE); + public EntityAIBaseTypeAdapter() { + register("mutexBits", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityBlaze.AIFireballAttack.class) + public class AIFireballAttackTypeAdapter extends FineTypeAdapter { + + public AIFireballAttackTypeAdapter() { + register("blaze", FineMode.FINE); + register("attackStep", FineMode.FINE); + register("attackTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsRestriction.class) + public class EntityAIMoveTowardsRestrictionTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveTowardsRestrictionTypeAdapter() { + register("creature", FineMode.FINE); + register("movePosX", FineMode.FINE); + register("movePosY", FineMode.FINE); + register("movePosZ", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWander.class) + public class EntityAIWanderTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderTypeAdapter() { + register("entity", FineMode.FINE); + register("x", FineMode.FINE); + register("y", FineMode.FINE); + register("z", FineMode.FINE); + register("speed", FineMode.FINE); + register("executionChance", FineMode.FINE); + register("mustUpdate", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWater.class) + public class EntityAIWanderAvoidWaterTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderAvoidWaterTypeAdapter() { + register("probability", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest.class) + public class EntityAIWatchClosestTypeAdapter extends FineTypeAdapter { + + public EntityAIWatchClosestTypeAdapter() { + register("entity", FineMode.FINE); + register("closestEntity", FineMode.FINE); + register("maxDistance", FineMode.FINE); + register("lookTime", FineMode.FINE); + register("chance", FineMode.FINE); + register("watchedClass", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookIdle.class) + public class EntityAILookIdleTypeAdapter extends FineTypeAdapter { + + public EntityAILookIdleTypeAdapter() { + register("idleEntity", FineMode.FINE); + register("lookX", FineMode.FINE); + register("lookZ", FineMode.FINE); + register("idleTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITarget.class) + public class EntityAITargetTypeAdapter extends FineTypeAdapter { + + public EntityAITargetTypeAdapter() { register("taskOwner", FineMode.FINE); register("shouldCheckSight", FineMode.FINE); register("nearbyOnly", FineMode.FINE); @@ -27,7 +96,916 @@ public EntityAINearestAttackableTargetTypeAdapter() { register("targetUnseenTicks", FineMode.FINE); register("target", FineMode.FINE); register("unseenMemoryTicks", FineMode.FINE); - register("mutexBits", FineMode.FINE); } } + + @FineTarget(net.minecraft.entity.ai.EntityAIHurtByTarget.class) + public class EntityAIHurtByTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIHurtByTargetTypeAdapter() { + register("entityCallsForHelp", FineMode.FINE); + register("revengeTimerOld", FineMode.FINE); + register("excludedReinforcementTypes", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAINearestAttackableTarget.class) + public class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { + + public EntityAINearestAttackableTargetTypeAdapter() { + register("targetClass", FineMode.FINE); + register("targetChance", FineMode.FINE); + register("sorter", FineMode.FINE); + register("targetEntitySelector", FineMode.FINE); + register("targetEntity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISit.class) + public class EntityAISitTypeAdapter extends FineTypeAdapter { + + public EntityAISitTypeAdapter() { + register("tameable", FineMode.FINE); + register("isSitting", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITempt.class) + public class EntityAITemptTypeAdapter extends FineTypeAdapter { + + public EntityAITemptTypeAdapter() { + register("temptedEntity", FineMode.FINE); + register("speed", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + register("pitch", FineMode.FINE); + register("yaw", FineMode.FINE); + register("temptingPlayer", FineMode.FINE); + register("delayTemptCounter", FineMode.FINE); + register("isRunning", FineMode.FINE); + register("temptItem", FineMode.FINE); + register("scaredByPlayerMovement", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISwimming.class) + public class EntityAISwimmingTypeAdapter extends FineTypeAdapter { + + public EntityAISwimmingTypeAdapter() { + register("entity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwner.class) + public class EntityAIFollowOwnerTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowOwnerTypeAdapter() { + register("tameable", FineMode.FINE); + register("owner", FineMode.FINE); + register("world", FineMode.FINE); + register("followSpeed", FineMode.FINE); + register("petPathfinder", FineMode.FINE); + register("timeToRecalcPath", FineMode.FINE); + register("maxDist", FineMode.FINE); + register("minDist", FineMode.FINE); + register("oldWaterCost", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveToBlock.class) + public class EntityAIMoveToBlockTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveToBlockTypeAdapter() { + register("creature", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("runDelay", FineMode.FINE); + register("timeoutCounter", FineMode.FINE); + register("maxStayTicks", FineMode.FINE); + register("destinationBlock", FineMode.FINE); + register("isAboveDestination", FineMode.FINE); + register("searchLength", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOcelotSit.class) + public class EntityAIOcelotSitTypeAdapter extends FineTypeAdapter { + + public EntityAIOcelotSitTypeAdapter() { + register("ocelot", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILeapAtTarget.class) + public class EntityAILeapAtTargetTypeAdapter extends FineTypeAdapter { + + public EntityAILeapAtTargetTypeAdapter() { + register("leaper", FineMode.FINE); + register("leapTarget", FineMode.FINE); + register("leapMotionY", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOcelotAttack.class) + public class EntityAIOcelotAttackTypeAdapter extends FineTypeAdapter { + + public EntityAIOcelotAttackTypeAdapter() { + register("world", FineMode.FINE); + register("entity", FineMode.FINE); + register("target", FineMode.FINE); + register("attackCountdown", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMate.class) + public class EntityAIMateTypeAdapter extends FineTypeAdapter { + + public EntityAIMateTypeAdapter() { + register("animal", FineMode.FINE); + register("mateClass", FineMode.FINE); + register("world", FineMode.FINE); + register("targetMate", FineMode.FINE); + register("spawnBabyDelay", FineMode.FINE); + register("moveSpeed", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITargetNonTamed.class) + public class EntityAITargetNonTamedTypeAdapter extends FineTypeAdapter { + + public EntityAITargetNonTamedTypeAdapter() { + register("tameable", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAvoidEntity.class) + public class EntityAIAvoidEntityTypeAdapter extends FineTypeAdapter { + + public EntityAIAvoidEntityTypeAdapter() { + register("canBeSeenSelector", FineMode.FINE); + register("entity", FineMode.FINE); + register("farSpeed", FineMode.FINE); + register("nearSpeed", FineMode.FINE); + register("closestLivingEntity", FineMode.FINE); + register("avoidDistance", FineMode.FINE); + register("path", FineMode.FINE); + register("navigation", FineMode.FINE); + register("classToAvoid", FineMode.FINE); + register("avoidTargetSelector", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackMelee.class) + public class EntityAIAttackMeleeTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackMeleeTypeAdapter() { + register("world", FineMode.FINE); + register("attacker", FineMode.FINE); + register("attackTick", FineMode.FINE); + register("speedTowardsTarget", FineMode.FINE); + register("longMemory", FineMode.FINE); + register("path", FineMode.FINE); + register("delayCounter", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + register("attackInterval", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySpider.AISpiderAttack.class) + public class AISpiderAttackTypeAdapter extends FineTypeAdapter { + + public AISpiderAttackTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySpider.AISpiderTarget.class) + public class AISpiderTargetTypeAdapter extends FineTypeAdapter { + + public AISpiderTargetTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAICreeperSwell.class) + public class EntityAICreeperSwellTypeAdapter extends FineTypeAdapter { + + public EntityAICreeperSwellTypeAdapter() { + register("swellingCreeper", FineMode.FINE); + register("creeperAttackTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIPanic.class) + public class EntityAIPanicTypeAdapter extends FineTypeAdapter { + + public EntityAIPanicTypeAdapter() { + register("creature", FineMode.FINE); + register("speed", FineMode.FINE); + register("randPosX", FineMode.FINE); + register("randPosY", FineMode.FINE); + register("randPosZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowParent.class) + public class EntityAIFollowParentTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowParentTypeAdapter() { + register("childAnimal", FineMode.FINE); + register("parentAnimal", FineMode.FINE); + register("moveSpeed", FineMode.FINE); + register("delayCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRunAroundLikeCrazy.class) + public class EntityAIRunAroundLikeCrazyTypeAdapter extends FineTypeAdapter { + + public EntityAIRunAroundLikeCrazyTypeAdapter() { + register("horseHost", FineMode.FINE); + register("speed", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityGuardian.AIGuardianAttack.class) + public class AIGuardianAttackTypeAdapter extends FineTypeAdapter { + + public AIGuardianAttackTypeAdapter() { + register("guardian", FineMode.FINE); + register("tickCounter", FineMode.FINE); + register("isElder", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityEnderman.AIPlaceBlock.class) + public class AIPlaceBlockTypeAdapter extends FineTypeAdapter { + + public AIPlaceBlockTypeAdapter() { + register("enderman", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityEnderman.AITakeBlock.class) + public class AITakeBlockTypeAdapter extends FineTypeAdapter { + + public AITakeBlockTypeAdapter() { + register("enderman", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityEnderman.AIFindPlayer.class) + public class AIFindPlayerTypeAdapter extends FineTypeAdapter { + + public AIFindPlayerTypeAdapter() { + register("enderman", FineMode.FINE); + register("player", FineMode.FINE); + register("aggroTime", FineMode.FINE); + register("teleportTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityGhast.AIRandomFly.class) + public class AIRandomFlyTypeAdapter extends FineTypeAdapter { + + public AIRandomFlyTypeAdapter() { + register("parentEntity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityGhast.AILookAround.class) + public class AILookAroundTypeAdapter extends FineTypeAdapter { + + public AILookAroundTypeAdapter() { + register("parentEntity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityGhast.AIFireballAttack.class) + public class AIFireballAttackTypeAdapter2 extends FineTypeAdapter { + + public AIFireballAttackTypeAdapter2() { + register("parentEntity", FineMode.FINE); + register("attackTimer", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearestPlayer.class) + public class EntityAIFindEntityNearestPlayerTypeAdapter extends FineTypeAdapter { + + public EntityAIFindEntityNearestPlayerTypeAdapter() { + register("LOGGER", FineMode.FINE); + register("entityLiving", FineMode.FINE); + register("predicate", FineMode.FINE); + register("sorter", FineMode.FINE); + register("entityTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIZombieAttack.class) + public class EntityAIZombieAttackTypeAdapter extends FineTypeAdapter { + + public EntityAIZombieAttackTypeAdapter() { + register("zombie", FineMode.FINE); + register("raiseArmTicks", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveThroughVillage.class) + public class EntityAIMoveThroughVillageTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveThroughVillageTypeAdapter() { + register("entity", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("path", FineMode.FINE); + register("doorInfo", FineMode.FINE); + register("isNocturnal", FineMode.FINE); + register("doorList", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIDoorInteract.class) + public class EntityAIDoorInteractTypeAdapter extends FineTypeAdapter { + + public EntityAIDoorInteractTypeAdapter() { + register("entity", FineMode.FINE); + register("doorPosition", FineMode.FINE); + register("doorBlock", FineMode.FINE); + register("hasStoppedDoorInteraction", FineMode.FINE); + register("entityPositionX", FineMode.FINE); + register("entityPositionZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIBreakDoor.class) + public class EntityAIBreakDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIBreakDoorTypeAdapter() { + register("breakingTime", FineMode.FINE); + register("previousBreakProgress", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsTarget.class) + public class EntityAIMoveTowardsTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveTowardsTargetTypeAdapter() { + register("creature", FineMode.FINE); + register("targetEntity", FineMode.FINE); + register("movePosX", FineMode.FINE); + register("movePosY", FineMode.FINE); + register("movePosZ", FineMode.FINE); + register("speed", FineMode.FINE); + register("maxTargetDistance", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookAtVillager.class) + public class EntityAILookAtVillagerTypeAdapter extends FineTypeAdapter { + + public EntityAILookAtVillagerTypeAdapter() { + register("ironGolem", FineMode.FINE); + register("villager", FineMode.FINE); + register("lookTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIDefendVillage.class) + public class EntityAIDefendVillageTypeAdapter extends FineTypeAdapter { + + public EntityAIDefendVillageTypeAdapter() { + register("irongolem", FineMode.FINE); + register("villageAgressorTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILlamaFollowCaravan.class) + public class EntityAILlamaFollowCaravanTypeAdapter extends FineTypeAdapter { + + public EntityAILlamaFollowCaravanTypeAdapter() { + register("llama", FineMode.FINE); + register("speedModifier", FineMode.FINE); + register("distCheckCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackRanged.class) + public class EntityAIAttackRangedTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackRangedTypeAdapter() { + register("entityHost", FineMode.FINE); + register("rangedAttackEntityHost", FineMode.FINE); + register("attackTarget", FineMode.FINE); + register("rangedAttackTime", FineMode.FINE); + register("entityMoveSpeed", FineMode.FINE); + register("seeTime", FineMode.FINE); + register("attackIntervalMin", FineMode.FINE); + register("maxRangedAttackTime", FineMode.FINE); + register("attackRadius", FineMode.FINE); + register("maxAttackDistance", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.passive.EntityLlama.AIHurtByTarget.class) + public class AIHurtByTargetTypeAdapter extends FineTypeAdapter { + + public AIHurtByTargetTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.passive.EntityLlama.AIDefendTarget.class) + public class AIDefendTargetTypeAdapter extends FineTypeAdapter { + + public AIDefendTargetTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeFloat.class) + public class AISlimeFloatTypeAdapter extends FineTypeAdapter { + + public AISlimeFloatTypeAdapter() { + register("slime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeAttack.class) + public class AISlimeAttackTypeAdapter extends FineTypeAdapter { + + public AISlimeAttackTypeAdapter() { + register("slime", FineMode.FINE); + register("growTieredTimer", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeFaceRandom.class) + public class AISlimeFaceRandomTypeAdapter extends FineTypeAdapter { + + public AISlimeFaceRandomTypeAdapter() { + register("slime", FineMode.FINE); + register("chosenDegrees", FineMode.FINE); + register("nextRandomizeTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeHop.class) + public class AISlimeHopTypeAdapter extends FineTypeAdapter { + + public AISlimeHopTypeAdapter() { + register("slime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearest.class) + public class EntityAIFindEntityNearestTypeAdapter extends FineTypeAdapter { + + public EntityAIFindEntityNearestTypeAdapter() { + register("LOGGER", FineMode.FINE); + register("mob", FineMode.FINE); + register("predicate", FineMode.FINE); + register("sorter", FineMode.FINE); + register("target", FineMode.FINE); + register("classToCheck", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwnerFlying.class) + public class EntityAIFollowOwnerFlyingTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowOwnerFlyingTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWaterFlying.class) + public class EntityAIWanderAvoidWaterFlyingTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderAvoidWaterFlyingTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILandOnOwnersShoulder.class) + public class EntityAILandOnOwnersShoulderTypeAdapter extends FineTypeAdapter { + + public EntityAILandOnOwnersShoulderTypeAdapter() { + register("entity", FineMode.FINE); + register("owner", FineMode.FINE); + register("isSittingOnShoulder", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollow.class) + public class EntityAIFollowTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowTypeAdapter() { + register("entity", FineMode.FINE); + register("followPredicate", FineMode.FINE); + register("followingEntity", FineMode.FINE); + register("speedModifier", FineMode.FINE); + register("navigation", FineMode.FINE); + register("timeToRecalcPath", FineMode.FINE); + register("stopDistance", FineMode.FINE); + register("oldWaterCost", FineMode.FINE); + register("areaSize", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIMeleeAttack.class) + public class AIMeleeAttackTypeAdapter extends FineTypeAdapter { + + public AIMeleeAttackTypeAdapter() { + register("f_1682088", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIPanic.class) + public class AIPanicTypeAdapter extends FineTypeAdapter { + + public AIPanicTypeAdapter() { + register("f_1588945", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIHurtByTarget.class) + public class AIHurtByTargetTypeAdapter2 extends FineTypeAdapter { + + public AIHurtByTargetTypeAdapter2() { + register("f_4352699", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIAttackPlayer.class) + public class AIAttackPlayerTypeAdapter extends FineTypeAdapter { + + public AIAttackPlayerTypeAdapter() { + register("f_4967813", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.passive.EntityRabbit.AIPanic.class) + public class AIPanicTypeAdapter2 extends FineTypeAdapter { + + public AIPanicTypeAdapter2() { + register("rabbit", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.passive.EntityRabbit.AIAvoidEntity.class) + public class AIAvoidEntityTypeAdapter extends FineTypeAdapter { + + public AIAvoidEntityTypeAdapter() { + register("rabbit", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.passive.EntityRabbit.AIRaidFarm.class) + public class AIRaidFarmTypeAdapter extends FineTypeAdapter { + + public AIRaidFarmTypeAdapter() { + register("rabbit", FineMode.FINE); + register("wantsToRaid", FineMode.FINE); + register("canRaid", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIEatGrass.class) + public class EntityAIEatGrassTypeAdapter extends FineTypeAdapter { + + public EntityAIEatGrassTypeAdapter() { + register("IS_TALL_GRASS", FineMode.FINE); + register("grassEaterEntity", FineMode.FINE); + register("entityWorld", FineMode.FINE); + register("eatingGrassTimer", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityShulker.AIAttack.class) + public class AIAttackTypeAdapter extends FineTypeAdapter { + + public AIAttackTypeAdapter() { + register("attackTime", FineMode.FINE); + register("f_0549306", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityShulker.AIPeek.class) + public class AIPeekTypeAdapter extends FineTypeAdapter { + + public AIPeekTypeAdapter() { + register("peekTime", FineMode.FINE); + register("f_7126754", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityShulker.AIAttackNearest.class) + public class AIAttackNearestTypeAdapter extends FineTypeAdapter { + + public AIAttackNearestTypeAdapter() { + register("f_8711122", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityShulker.AIDefenseAttack.class) + public class AIDefenseAttackTypeAdapter extends FineTypeAdapter { + + public AIDefenseAttackTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySilverfish.AISummonSilverfish.class) + public class AISummonSilverfishTypeAdapter extends FineTypeAdapter { + + public AISummonSilverfishTypeAdapter() { + register("silverfish", FineMode.FINE); + register("lookForFriends", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySilverfish.AIHideInStone.class) + public class AIHideInStoneTypeAdapter extends FineTypeAdapter { + + public AIHideInStoneTypeAdapter() { + register("facing", FineMode.FINE); + register("doMerge", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRestrictSun.class) + public class EntityAIRestrictSunTypeAdapter extends FineTypeAdapter { + + public EntityAIRestrictSunTypeAdapter() { + register("entity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFleeSun.class) + public class EntityAIFleeSunTypeAdapter extends FineTypeAdapter { + + public EntityAIFleeSunTypeAdapter() { + register("creature", FineMode.FINE); + register("shelterX", FineMode.FINE); + register("shelterY", FineMode.FINE); + register("shelterZ", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("world", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackRangedBow.class) + public class EntityAIAttackRangedBowTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackRangedBowTypeAdapter() { + register("entity", FineMode.FINE); + register("moveSpeedAmp", FineMode.FINE); + register("attackCooldown", FineMode.FINE); + register("maxAttackDistance", FineMode.FINE); + register("attackTime", FineMode.FINE); + register("seeTime", FineMode.FINE); + register("strafingClockwise", FineMode.FINE); + register("strafingBackwards", FineMode.FINE); + register("strafingTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISkeletonRiders.class) + public class EntityAISkeletonRidersTypeAdapter extends FineTypeAdapter { + + public EntityAISkeletonRidersTypeAdapter() { + register("horse", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.passive.EntitySquid.AIMoveRandom.class) + public class AIMoveRandomTypeAdapter extends FineTypeAdapter { + + public AIMoveRandomTypeAdapter() { + register("squid", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityVex.AIChargeAttack.class) + public class AIChargeAttackTypeAdapter extends FineTypeAdapter { + + public AIChargeAttackTypeAdapter() { + register("f_5200292", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityVex.AIMoveRandom.class) + public class AIMoveRandomTypeAdapter2 extends FineTypeAdapter { + + public AIMoveRandomTypeAdapter2() { + register("f_3949223", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityVex.AICopyOwnerTarget.class) + public class AICopyOwnerTargetTypeAdapter extends FineTypeAdapter { + + public AICopyOwnerTargetTypeAdapter() { + register("f_7758303", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITradePlayer.class) + public class EntityAITradePlayerTypeAdapter extends FineTypeAdapter { + + public EntityAITradePlayerTypeAdapter() { + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookAtTradePlayer.class) + public class EntityAILookAtTradePlayerTypeAdapter extends FineTypeAdapter { + + public EntityAILookAtTradePlayerTypeAdapter() { + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveIndoors.class) + public class EntityAIMoveIndoorsTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveIndoorsTypeAdapter() { + register("entity", FineMode.FINE); + register("doorInfo", FineMode.FINE); + register("insidePosX", FineMode.FINE); + register("insidePosZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRestrictOpenDoor.class) + public class EntityAIRestrictOpenDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIRestrictOpenDoorTypeAdapter() { + register("entity", FineMode.FINE); + register("frontDoor", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOpenDoor.class) + public class EntityAIOpenDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIOpenDoorTypeAdapter() { + register("closeDoor", FineMode.FINE); + register("closeDoorTemporisation", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIVillagerMate.class) + public class EntityAIVillagerMateTypeAdapter extends FineTypeAdapter { + + public EntityAIVillagerMateTypeAdapter() { + register("villager", FineMode.FINE); + register("mate", FineMode.FINE); + register("world", FineMode.FINE); + register("matingTimeout", FineMode.FINE); + register("village", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowGolem.class) + public class EntityAIFollowGolemTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowGolemTypeAdapter() { + register("villager", FineMode.FINE); + register("ironGolem", FineMode.FINE); + register("takeGolemRoseTick", FineMode.FINE); + register("tookGolemRose", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest2.class) + public class EntityAIWatchClosest2TypeAdapter extends FineTypeAdapter { + + public EntityAIWatchClosest2TypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIVillagerInteract.class) + public class EntityAIVillagerInteractTypeAdapter extends FineTypeAdapter { + + public EntityAIVillagerInteractTypeAdapter() { + register("interactionDelay", FineMode.FINE); + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIHarvestFarmland.class) + public class EntityAIHarvestFarmlandTypeAdapter extends FineTypeAdapter { + + public EntityAIHarvestFarmlandTypeAdapter() { + register("villager", FineMode.FINE); + register("hasFarmItem", FineMode.FINE); + register("wantsToReapStuff", FineMode.FINE); + register("currentTask", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityVindicator.AIJohnnyAttack.class) + public class AIJohnnyAttackTypeAdapter extends FineTypeAdapter { + + public AIJohnnyAttackTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySpellcasterIllager.AICastingApell.class) + public class AICastingApellTypeAdapter extends FineTypeAdapter { + + public AICastingApellTypeAdapter() { + register("f_1024672", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntitySpellcasterIllager.AIUseSpell.class) + public class AIUseSpellTypeAdapter extends FineTypeAdapter { + + public AIUseSpellTypeAdapter() { + register("spellWarmup", FineMode.FINE); + register("spellCooldown", FineMode.FINE); + register("f_4432138", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityIllusionIllager.AIMirriorSpell.class) + public class AIMirriorSpellTypeAdapter extends FineTypeAdapter { + + public AIMirriorSpellTypeAdapter() { + register("f_4096963", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityIllusionIllager.AIBlindnessSpell.class) + public class AIBlindnessSpellTypeAdapter extends FineTypeAdapter { + + public AIBlindnessSpellTypeAdapter() { + register("lastTargetId", FineMode.FINE); + register("f_2457942", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.passive.EntityWolf.AIAvoidEntity.class) + public class AIAvoidEntityTypeAdapter2 extends FineTypeAdapter { + + public AIAvoidEntityTypeAdapter2() { + register("wolf", FineMode.FINE); + register("f_5613973", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIBeg.class) + public class EntityAIBegTypeAdapter extends FineTypeAdapter { + + public EntityAIBegTypeAdapter() { + register("wolf", FineMode.FINE); + register("player", FineMode.FINE); + register("world", FineMode.FINE); + register("minPlayerDistance", FineMode.FINE); + register("timeoutCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtByTarget.class) + public class EntityAIOwnerHurtByTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIOwnerHurtByTargetTypeAdapter() { + register("tameable", FineMode.FINE); + register("attacker", FineMode.FINE); + register("timestamp", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtTarget.class) + public class EntityAIOwnerHurtTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIOwnerHurtTargetTypeAdapter() { + register("tameable", FineMode.FINE); + register("attacker", FineMode.FINE); + register("timestamp", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.boss.EntityWither.AIDoNothing.class) + public class AIDoNothingTypeAdapter extends FineTypeAdapter { + + public AIDoNothingTypeAdapter() { + register("f_4462935", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.monster.EntityPigZombie.AIHurtByAggressor.class) + public class AIHurtByAggressorTypeAdapter extends FineTypeAdapter { + + public AIHurtByAggressorTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.monster.EntityPigZombie.AITargetAggressor.class) + public class AITargetAggressorTypeAdapter extends FineTypeAdapter { + + public AITargetAggressorTypeAdapter() { + } + } + } diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 82ee0dbb..41a51b3b 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -65,3 +65,47 @@ mutable field net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry action Lne accessible field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; mutable field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; + +accessible class net/minecraft/entity/monster/EntityBlaze$AIFireballAttack +accessible class net/minecraft/entity/monster/EntitySpider$AISpiderAttack +accessible class net/minecraft/entity/monster/EntitySpider$AISpiderTarget +accessible class net/minecraft/entity/monster/EntityGuardian$AIGuardianAttack +accessible class net/minecraft/entity/monster/EntityEnderman$AIPlaceBlock +accessible class net/minecraft/entity/monster/EntityEnderman$AITakeBlock +accessible class net/minecraft/entity/monster/EntityEnderman$AIFindPlayer +accessible class net/minecraft/entity/monster/EntityGhast$AIRandomFly +accessible class net/minecraft/entity/monster/EntityGhast$AILookAround +accessible class net/minecraft/entity/monster/EntityGhast$AIFireballAttack +accessible class net/minecraft/entity/passive/EntityLlama$AIHurtByTarget +accessible class net/minecraft/entity/passive/EntityLlama$AIDefendTarget +accessible class net/minecraft/entity/monster/EntitySlime$AISlimeFloat +accessible class net/minecraft/entity/monster/EntitySlime$AISlimeAttack +accessible class net/minecraft/entity/monster/EntitySlime$AISlimeFaceRandom +accessible class net/minecraft/entity/monster/EntitySlime$AISlimeHop +accessible class net/minecraft/entity/monster/EntityPolarBear$AIMeleeAttack +accessible class net/minecraft/entity/monster/EntityPolarBear$AIPanic +accessible class net/minecraft/entity/monster/EntityPolarBear$AIHurtByTarget +accessible class net/minecraft/entity/monster/EntityPolarBear$AIAttackPlayer +accessible class net/minecraft/entity/passive/EntityRabbit$AIPanic +accessible class net/minecraft/entity/passive/EntityRabbit$AIAvoidEntity +accessible class net/minecraft/entity/passive/EntityRabbit$AIRaidFarm +accessible class net/minecraft/entity/monster/EntityShulker$AIAttack +accessible class net/minecraft/entity/monster/EntityShulker$AIPeek +accessible class net/minecraft/entity/monster/EntityShulker$AIAttackNearest +accessible class net/minecraft/entity/monster/EntityShulker$AIDefenseAttack +accessible class net/minecraft/entity/monster/EntitySilverfish$AISummonSilverfish +accessible class net/minecraft/entity/monster/EntitySilverfish$AIHideInStone +accessible class net/minecraft/entity/monster/AbstractSkeleton$1 +accessible class net/minecraft/entity/passive/EntitySquid$AIMoveRandom +accessible class net/minecraft/entity/monster/EntityVex$AIChargeAttack +accessible class net/minecraft/entity/monster/EntityVex$AIMoveRandom +accessible class net/minecraft/entity/monster/EntityVex$AICopyOwnerTarget +accessible class net/minecraft/entity/monster/EntityVindicator$AIJohnnyAttack +accessible class net/minecraft/entity/monster/EntitySpellcasterIllager$AICastingApell +accessible class net/minecraft/entity/monster/EntitySpellcasterIllager$AIUseSpell +accessible class net/minecraft/entity/monster/EntityIllusionIllager$AIMirriorSpell +accessible class net/minecraft/entity/monster/EntityIllusionIllager$AIBlindnessSpell +accessible class net/minecraft/entity/passive/EntityWolf$AIAvoidEntity +accessible class net/minecraft/entity/boss/EntityWither$AIDoNothing +accessible class net/minecraft/entity/monster/EntityPigZombie$AIHurtByAggressor +accessible class net/minecraft/entity/monster/EntityPigZombie$AITargetAggressor \ No newline at end of file diff --git a/src/main/resources/tasmod.mixin.json b/src/main/resources/tasmod.mixin.json index 535688ab..a0b58261 100644 --- a/src/main/resources/tasmod.mixin.json +++ b/src/main/resources/tasmod.mixin.json @@ -16,6 +16,7 @@ "savestates.MixinChunkProviderServer", "savestates.MixinNetHandlerPlayServer", "savestates.MixinScoreboard", + "savestates.TypeAdapterGenerator", // Events "events.MixinEntityPlayerMP", diff --git a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java index 978a33cd..9c70675d 100644 --- a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java +++ b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java @@ -54,6 +54,7 @@ void testGenerateMulti() { List expected = Arrays.asList(String.format("package typeadapter;\n" + "\n" + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" + + "import com.minecrafttas.mctcommon.json.FineMultiTarget;\n" + "import com.minecrafttas.mctcommon.json.FineTarget;\n" + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" + "\n" @@ -95,6 +96,7 @@ void testGenerateSingle() { List expected = new ArrayList<>(Arrays.asList(String.format("package typeadapter;\n" + "\n" + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" + + "import com.minecrafttas.mctcommon.json.FineMultiTarget;\n" + "import com.minecrafttas.mctcommon.json.FineTarget;\n" + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" + "\n" From 33d6140aff710062bd412ae8ea0f8cb6712bcadd Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 21 Sep 2026 15:22:05 +0200 Subject: [PATCH 22/26] [Savestates] Add improved serialisation --- .../mctcommon/json/FineField.java | 12 +- .../minecrafttas/mctcommon/json/FineGson.java | 5 +- .../mctcommon/json/FineTypeAdapter.java | 9 +- .../json/FineTypeAdapterGenerator.java | 6 +- .../savestates/TypeAdapterGenerator.java | 8 +- .../tasmod/registries/TASmodKeybinds.java | 3 +- .../storage/builtin/EntityAiTaskStorage.java | 30 +- .../typeadapters/EntityAITypeAdapters.java | 1695 +++++++---------- .../typeadapters/ItemTypeAdapter.java | 24 +- src/main/resources/tasmod.accesswidener | 46 +- .../java/mctcommon/json/FineGsonTest.java | 2 +- .../json/FineTypeAdapterGeneratorTest.java | 4 +- 12 files changed, 744 insertions(+), 1100 deletions(-) diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineField.java b/src/main/java/com/minecrafttas/mctcommon/json/FineField.java index b606dc03..ceaf20f2 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineField.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineField.java @@ -38,21 +38,21 @@ public FineMode getMode() { return mode; } - public JsonElement serialize(Object obj) { - return serializer.serialize(obj); + public JsonElement serialize(Object obj, FineGson fgson) { + return serializer.serialize(obj, fgson); } - public Object deserialize(JsonElement element) { - return deserializer.deserialize(element); + public Object deserialize(JsonElement element, FineGson fgson) { + return deserializer.deserialize(element, fgson); } @FunctionalInterface public static interface FineSerializer { - public JsonElement serialize(Object obj); + public JsonElement serialize(Object obj, FineGson fgson); } @FunctionalInterface public static interface FineDeserializer { - public Object deserialize(JsonElement element); + public Object deserialize(JsonElement element, FineGson fgson); } } diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java index b66a9cae..30f7f11a 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java @@ -8,6 +8,7 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; +import com.google.gson.JsonNull; import com.google.gson.JsonObject; /** @@ -52,6 +53,8 @@ public void registerTypeAdapter(Class type, FineTypeAdapter adapter) { } public JsonElement serialize(Object obj) { + if (obj == null) + return JsonNull.INSTANCE; Class type = obj.getClass(); return serialize(obj, type); } @@ -61,7 +64,7 @@ public JsonElement serialize(Object obj, Class type) { return gsonInstance.toJsonTree(obj); FineTypeAdapter adapter = typeAdapters.get(type); - JsonElement out = adapter.serialize(obj, this, type).getAsJsonObject(); + JsonElement out = adapter.serialize(obj, this, type); Class superclass = type.getSuperclass(); if (superclass != Object.class) { diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java index f509df60..9a4c9785 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java @@ -61,10 +61,10 @@ public JsonElement serialize(Object obj, FineGson fineJson, Class clazz) thro } String fieldName = fineField.getName(); - System.out.println(String.format("[%s|%s] Serializing field %s (%s)", obj.getClass(), clazz, field.getName(), fieldName)); + System.out.println(String.format("[%s|%s] Serializing field %s (%s)", obj.getClass().getSimpleName(), clazz.getSimpleName(), field.getName(), fieldName)); switch (fineField.getMode()) { case CUSTOM: - out.add(fieldName, fineField.serialize(fieldValue)); + out.add(fieldName, fineField.serialize(fieldValue, fineJson)); break; case FINE: out.add(fieldName, fineJson.serialize(fieldValue)); @@ -80,7 +80,7 @@ public JsonElement serialize(Object obj, FineGson fineJson, Class clazz) thro } for (FineField fineField : additionalFields) { - out.add(fineField.getName(), fineField.serialize(null)); + out.add(fineField.getName(), fineField.serialize(null, fineJson)); } return out; } @@ -106,10 +106,11 @@ public Object deserialize(JsonElement element, Class clazz, FineGson fineJson String fieldName = fineField.getName(); JsonElement fieldElement = elementObj.get(fieldName); + System.out.println(String.format("[%s|%s] Deserializing field %s (%s)", obj.getClass().getSimpleName(), clazz.getSimpleName(), field.getName(), fieldName)); Object fieldValue = null; switch (fineField.getMode()) { case CUSTOM: - fieldValue = fineField.deserialize(fieldElement); + fieldValue = fineField.deserialize(fieldElement, fineJson); break; case FINE: fieldValue = fineJson.deserialize(fieldElement, field.getType()); diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java index 8a8f3acf..f8e7f429 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java @@ -72,6 +72,10 @@ public void addClass(Class clazz) { if (classLines.containsKey(clazz)) return; +// if (clazz.getName().contains("$")) { +// return; +// } + Class superclazz = clazz.getSuperclass(); if (superclazz != Object.class) addClass(superclazz); @@ -82,7 +86,7 @@ public void addClass(Class clazz) { // importLines.add(String.format("import %s;", clazz.getName())); classLines.put(clazz, splitNewLine(String.format("" + "@FineTarget(%s.class)\n" - + "public class %sTypeAdapter extends FineTypeAdapter {\n" + + "public static class %sTypeAdapter extends FineTypeAdapter {\n" + "\n" + "\tpublic %sTypeAdapter() {", clazz.getName().replace("$", "."), clazzName, clazzName))); diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java index ef493b8a..b7700e8b 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/TypeAdapterGenerator.java @@ -5,16 +5,14 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.minecrafttas.tasmod.TASmod; - import net.minecraft.entity.ai.EntityAIBase; @Mixin(EntityAIBase.class) public class TypeAdapterGenerator { @Inject(method = "", at = @At("RETURN")) public void inject_aiBase(CallbackInfo ci) { - EntityAIBase thisObj = (EntityAIBase) (Object) this; - System.out.println(thisObj); - TASmod.generator.addClass(thisObj.getClass()); +// EntityAIBase thisObj = (EntityAIBase) (Object) this; +// System.out.println(thisObj); +// TASmod.generator.addClass(thisObj.getClass()); } } diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java index 8454fb1f..42f306c5 100644 --- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java +++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java @@ -56,8 +56,9 @@ public enum TASmodKeybinds implements KeybindID { * Yes, I am really generating TypeAdapter code here and replacing the class file. * This is how we did it before AI kids. */ + try { - Files.write(Paths.get("../src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java"), TASmod.generator.generateMulti(), StandardOpenOption.CREATE); + Files.write(Paths.get("../src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java"), TASmod.generator.generateMulti(), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 78a76075..9dbde3bc 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -18,9 +18,11 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.minecrafttas.mctcommon.json.FineGson; import com.minecrafttas.tasmod.savestates.exceptions.SavestateException; import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; import com.minecrafttas.tasmod.savestates.typeadapters.BlockPosTypeAdapterFactory; +import com.minecrafttas.tasmod.savestates.typeadapters.EntityAITypeAdapters; import com.minecrafttas.tasmod.savestates.typeadapters.EntityClassTypeAdapterFactory; import com.minecrafttas.tasmod.savestates.typeadapters.EntityLivingTypeAdapter; import com.minecrafttas.tasmod.savestates.typeadapters.EntityTypeAdapterFactory; @@ -42,6 +44,8 @@ public class EntityAiTaskStorage extends SavestateStorageExtensionBase { + private final FineGson fgson; + public EntityAiTaskStorage() { //@formatter:off super("entityAi.json", @@ -60,7 +64,6 @@ public EntityAiTaskStorage() { .registerTypeAdapterFactory( new BlockPosTypeAdapterFactory() ) - .registerTypeAdapter(Item.class, new ItemTypeAdapter()) .registerTypeAdapter(EntityLivingTypeAdapter.class, new EntityLivingTypeAdapter()) .setExclusionStrategies(new ExclusionStrategy() { @@ -80,6 +83,10 @@ public boolean shouldSkipClass(Class c) { ) .create()); //@formatter:on + + fgson = new FineGson(gsonInstance); + fgson.registerTypeAdapter(EntityAITypeAdapters.class); + fgson.registerTypeAdapter(Item.class, new ItemTypeAdapter()); } @Override @@ -145,16 +152,17 @@ private JsonArray serialiseAIEntries(Set taskEntries) { return serialisedEntries; } - private JsonObject serializeAction(EntityAIBase action, Class clazz) { - @SuppressWarnings("unchecked") - Class superclazz = (Class) clazz.getSuperclass(); - - JsonObject out = new JsonObject(); - - if (superclazz != EntityAIBase.class) - out = serializeAction(action, superclazz); - - return JsonUtils.mergeJsonObjects(out, gsonInstance.toJsonTree(action, clazz).getAsJsonObject()); + private JsonElement serializeAction(EntityAIBase action, Class clazz) { +// @SuppressWarnings("unchecked") +// Class superclazz = (Class) clazz.getSuperclass(); +// +// JsonObject out = new JsonObject(); +// +// if (superclazz != EntityAIBase.class) +// out = serializeAction(action, superclazz); +// +// return JsonUtils.mergeJsonObjects(out, gsonInstance.toJsonTree(action, clazz).getAsJsonObject()); + return fgson.serialize(action); } @Override diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java index afbd2fc9..e73eeec6 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java @@ -1,1011 +1,684 @@ -package com.minecrafttas.tasmod.savestates.typeadapters; - -import com.minecrafttas.mctcommon.json.FineField.FineMode; -import com.minecrafttas.mctcommon.json.FineMultiTarget; -import com.minecrafttas.mctcommon.json.FineTarget; -import com.minecrafttas.mctcommon.json.FineTypeAdapter; - -@FineMultiTarget -public class EntityAITypeAdapters { - - @FineTarget(net.minecraft.entity.ai.EntityAIBase.class) - public class EntityAIBaseTypeAdapter extends FineTypeAdapter { - - public EntityAIBaseTypeAdapter() { - register("mutexBits", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityBlaze.AIFireballAttack.class) - public class AIFireballAttackTypeAdapter extends FineTypeAdapter { - - public AIFireballAttackTypeAdapter() { - register("blaze", FineMode.FINE); - register("attackStep", FineMode.FINE); - register("attackTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsRestriction.class) - public class EntityAIMoveTowardsRestrictionTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveTowardsRestrictionTypeAdapter() { - register("creature", FineMode.FINE); - register("movePosX", FineMode.FINE); - register("movePosY", FineMode.FINE); - register("movePosZ", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWander.class) - public class EntityAIWanderTypeAdapter extends FineTypeAdapter { - - public EntityAIWanderTypeAdapter() { - register("entity", FineMode.FINE); - register("x", FineMode.FINE); - register("y", FineMode.FINE); - register("z", FineMode.FINE); - register("speed", FineMode.FINE); - register("executionChance", FineMode.FINE); - register("mustUpdate", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWater.class) - public class EntityAIWanderAvoidWaterTypeAdapter extends FineTypeAdapter { - - public EntityAIWanderAvoidWaterTypeAdapter() { - register("probability", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest.class) - public class EntityAIWatchClosestTypeAdapter extends FineTypeAdapter { - - public EntityAIWatchClosestTypeAdapter() { - register("entity", FineMode.FINE); - register("closestEntity", FineMode.FINE); - register("maxDistance", FineMode.FINE); - register("lookTime", FineMode.FINE); - register("chance", FineMode.FINE); - register("watchedClass", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILookIdle.class) - public class EntityAILookIdleTypeAdapter extends FineTypeAdapter { - - public EntityAILookIdleTypeAdapter() { - register("idleEntity", FineMode.FINE); - register("lookX", FineMode.FINE); - register("lookZ", FineMode.FINE); - register("idleTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITarget.class) - public class EntityAITargetTypeAdapter extends FineTypeAdapter { - - public EntityAITargetTypeAdapter() { - register("taskOwner", FineMode.FINE); - register("shouldCheckSight", FineMode.FINE); - register("nearbyOnly", FineMode.FINE); - register("targetSearchStatus", FineMode.FINE); - register("targetSearchDelay", FineMode.FINE); - register("targetUnseenTicks", FineMode.FINE); - register("target", FineMode.FINE); - register("unseenMemoryTicks", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIHurtByTarget.class) - public class EntityAIHurtByTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIHurtByTargetTypeAdapter() { - register("entityCallsForHelp", FineMode.FINE); - register("revengeTimerOld", FineMode.FINE); - register("excludedReinforcementTypes", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAINearestAttackableTarget.class) - public class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { - - public EntityAINearestAttackableTargetTypeAdapter() { - register("targetClass", FineMode.FINE); - register("targetChance", FineMode.FINE); - register("sorter", FineMode.FINE); - register("targetEntitySelector", FineMode.FINE); - register("targetEntity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAISit.class) - public class EntityAISitTypeAdapter extends FineTypeAdapter { - - public EntityAISitTypeAdapter() { - register("tameable", FineMode.FINE); - register("isSitting", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITempt.class) - public class EntityAITemptTypeAdapter extends FineTypeAdapter { - - public EntityAITemptTypeAdapter() { - register("temptedEntity", FineMode.FINE); - register("speed", FineMode.FINE); - register("targetX", FineMode.FINE); - register("targetY", FineMode.FINE); - register("targetZ", FineMode.FINE); - register("pitch", FineMode.FINE); - register("yaw", FineMode.FINE); - register("temptingPlayer", FineMode.FINE); - register("delayTemptCounter", FineMode.FINE); - register("isRunning", FineMode.FINE); - register("temptItem", FineMode.FINE); - register("scaredByPlayerMovement", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAISwimming.class) - public class EntityAISwimmingTypeAdapter extends FineTypeAdapter { - - public EntityAISwimmingTypeAdapter() { - register("entity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwner.class) - public class EntityAIFollowOwnerTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowOwnerTypeAdapter() { - register("tameable", FineMode.FINE); - register("owner", FineMode.FINE); - register("world", FineMode.FINE); - register("followSpeed", FineMode.FINE); - register("petPathfinder", FineMode.FINE); - register("timeToRecalcPath", FineMode.FINE); - register("maxDist", FineMode.FINE); - register("minDist", FineMode.FINE); - register("oldWaterCost", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveToBlock.class) - public class EntityAIMoveToBlockTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveToBlockTypeAdapter() { - register("creature", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - register("runDelay", FineMode.FINE); - register("timeoutCounter", FineMode.FINE); - register("maxStayTicks", FineMode.FINE); - register("destinationBlock", FineMode.FINE); - register("isAboveDestination", FineMode.FINE); - register("searchLength", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOcelotSit.class) - public class EntityAIOcelotSitTypeAdapter extends FineTypeAdapter { - - public EntityAIOcelotSitTypeAdapter() { - register("ocelot", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILeapAtTarget.class) - public class EntityAILeapAtTargetTypeAdapter extends FineTypeAdapter { - - public EntityAILeapAtTargetTypeAdapter() { - register("leaper", FineMode.FINE); - register("leapTarget", FineMode.FINE); - register("leapMotionY", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOcelotAttack.class) - public class EntityAIOcelotAttackTypeAdapter extends FineTypeAdapter { - - public EntityAIOcelotAttackTypeAdapter() { - register("world", FineMode.FINE); - register("entity", FineMode.FINE); - register("target", FineMode.FINE); - register("attackCountdown", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMate.class) - public class EntityAIMateTypeAdapter extends FineTypeAdapter { - - public EntityAIMateTypeAdapter() { - register("animal", FineMode.FINE); - register("mateClass", FineMode.FINE); - register("world", FineMode.FINE); - register("targetMate", FineMode.FINE); - register("spawnBabyDelay", FineMode.FINE); - register("moveSpeed", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITargetNonTamed.class) - public class EntityAITargetNonTamedTypeAdapter extends FineTypeAdapter { - - public EntityAITargetNonTamedTypeAdapter() { - register("tameable", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAvoidEntity.class) - public class EntityAIAvoidEntityTypeAdapter extends FineTypeAdapter { - - public EntityAIAvoidEntityTypeAdapter() { - register("canBeSeenSelector", FineMode.FINE); - register("entity", FineMode.FINE); - register("farSpeed", FineMode.FINE); - register("nearSpeed", FineMode.FINE); - register("closestLivingEntity", FineMode.FINE); - register("avoidDistance", FineMode.FINE); - register("path", FineMode.FINE); - register("navigation", FineMode.FINE); - register("classToAvoid", FineMode.FINE); - register("avoidTargetSelector", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAttackMelee.class) - public class EntityAIAttackMeleeTypeAdapter extends FineTypeAdapter { - - public EntityAIAttackMeleeTypeAdapter() { - register("world", FineMode.FINE); - register("attacker", FineMode.FINE); - register("attackTick", FineMode.FINE); - register("speedTowardsTarget", FineMode.FINE); - register("longMemory", FineMode.FINE); - register("path", FineMode.FINE); - register("delayCounter", FineMode.FINE); - register("targetX", FineMode.FINE); - register("targetY", FineMode.FINE); - register("targetZ", FineMode.FINE); - register("attackInterval", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySpider.AISpiderAttack.class) - public class AISpiderAttackTypeAdapter extends FineTypeAdapter { - - public AISpiderAttackTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySpider.AISpiderTarget.class) - public class AISpiderTargetTypeAdapter extends FineTypeAdapter { - - public AISpiderTargetTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAICreeperSwell.class) - public class EntityAICreeperSwellTypeAdapter extends FineTypeAdapter { - - public EntityAICreeperSwellTypeAdapter() { - register("swellingCreeper", FineMode.FINE); - register("creeperAttackTarget", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIPanic.class) - public class EntityAIPanicTypeAdapter extends FineTypeAdapter { - - public EntityAIPanicTypeAdapter() { - register("creature", FineMode.FINE); - register("speed", FineMode.FINE); - register("randPosX", FineMode.FINE); - register("randPosY", FineMode.FINE); - register("randPosZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowParent.class) - public class EntityAIFollowParentTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowParentTypeAdapter() { - register("childAnimal", FineMode.FINE); - register("parentAnimal", FineMode.FINE); - register("moveSpeed", FineMode.FINE); - register("delayCounter", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIRunAroundLikeCrazy.class) - public class EntityAIRunAroundLikeCrazyTypeAdapter extends FineTypeAdapter { - - public EntityAIRunAroundLikeCrazyTypeAdapter() { - register("horseHost", FineMode.FINE); - register("speed", FineMode.FINE); - register("targetX", FineMode.FINE); - register("targetY", FineMode.FINE); - register("targetZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityGuardian.AIGuardianAttack.class) - public class AIGuardianAttackTypeAdapter extends FineTypeAdapter { - - public AIGuardianAttackTypeAdapter() { - register("guardian", FineMode.FINE); - register("tickCounter", FineMode.FINE); - register("isElder", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityEnderman.AIPlaceBlock.class) - public class AIPlaceBlockTypeAdapter extends FineTypeAdapter { - - public AIPlaceBlockTypeAdapter() { - register("enderman", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityEnderman.AITakeBlock.class) - public class AITakeBlockTypeAdapter extends FineTypeAdapter { - - public AITakeBlockTypeAdapter() { - register("enderman", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityEnderman.AIFindPlayer.class) - public class AIFindPlayerTypeAdapter extends FineTypeAdapter { - - public AIFindPlayerTypeAdapter() { - register("enderman", FineMode.FINE); - register("player", FineMode.FINE); - register("aggroTime", FineMode.FINE); - register("teleportTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityGhast.AIRandomFly.class) - public class AIRandomFlyTypeAdapter extends FineTypeAdapter { - - public AIRandomFlyTypeAdapter() { - register("parentEntity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityGhast.AILookAround.class) - public class AILookAroundTypeAdapter extends FineTypeAdapter { - - public AILookAroundTypeAdapter() { - register("parentEntity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityGhast.AIFireballAttack.class) - public class AIFireballAttackTypeAdapter2 extends FineTypeAdapter { - - public AIFireballAttackTypeAdapter2() { - register("parentEntity", FineMode.FINE); - register("attackTimer", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearestPlayer.class) - public class EntityAIFindEntityNearestPlayerTypeAdapter extends FineTypeAdapter { - - public EntityAIFindEntityNearestPlayerTypeAdapter() { - register("LOGGER", FineMode.FINE); - register("entityLiving", FineMode.FINE); - register("predicate", FineMode.FINE); - register("sorter", FineMode.FINE); - register("entityTarget", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIZombieAttack.class) - public class EntityAIZombieAttackTypeAdapter extends FineTypeAdapter { - - public EntityAIZombieAttackTypeAdapter() { - register("zombie", FineMode.FINE); - register("raiseArmTicks", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveThroughVillage.class) - public class EntityAIMoveThroughVillageTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveThroughVillageTypeAdapter() { - register("entity", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - register("path", FineMode.FINE); - register("doorInfo", FineMode.FINE); - register("isNocturnal", FineMode.FINE); - register("doorList", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIDoorInteract.class) - public class EntityAIDoorInteractTypeAdapter extends FineTypeAdapter { - - public EntityAIDoorInteractTypeAdapter() { - register("entity", FineMode.FINE); - register("doorPosition", FineMode.FINE); - register("doorBlock", FineMode.FINE); - register("hasStoppedDoorInteraction", FineMode.FINE); - register("entityPositionX", FineMode.FINE); - register("entityPositionZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIBreakDoor.class) - public class EntityAIBreakDoorTypeAdapter extends FineTypeAdapter { - - public EntityAIBreakDoorTypeAdapter() { - register("breakingTime", FineMode.FINE); - register("previousBreakProgress", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsTarget.class) - public class EntityAIMoveTowardsTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveTowardsTargetTypeAdapter() { - register("creature", FineMode.FINE); - register("targetEntity", FineMode.FINE); - register("movePosX", FineMode.FINE); - register("movePosY", FineMode.FINE); - register("movePosZ", FineMode.FINE); - register("speed", FineMode.FINE); - register("maxTargetDistance", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILookAtVillager.class) - public class EntityAILookAtVillagerTypeAdapter extends FineTypeAdapter { - - public EntityAILookAtVillagerTypeAdapter() { - register("ironGolem", FineMode.FINE); - register("villager", FineMode.FINE); - register("lookTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIDefendVillage.class) - public class EntityAIDefendVillageTypeAdapter extends FineTypeAdapter { - - public EntityAIDefendVillageTypeAdapter() { - register("irongolem", FineMode.FINE); - register("villageAgressorTarget", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILlamaFollowCaravan.class) - public class EntityAILlamaFollowCaravanTypeAdapter extends FineTypeAdapter { - - public EntityAILlamaFollowCaravanTypeAdapter() { - register("llama", FineMode.FINE); - register("speedModifier", FineMode.FINE); - register("distCheckCounter", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAttackRanged.class) - public class EntityAIAttackRangedTypeAdapter extends FineTypeAdapter { - - public EntityAIAttackRangedTypeAdapter() { - register("entityHost", FineMode.FINE); - register("rangedAttackEntityHost", FineMode.FINE); - register("attackTarget", FineMode.FINE); - register("rangedAttackTime", FineMode.FINE); - register("entityMoveSpeed", FineMode.FINE); - register("seeTime", FineMode.FINE); - register("attackIntervalMin", FineMode.FINE); - register("maxRangedAttackTime", FineMode.FINE); - register("attackRadius", FineMode.FINE); - register("maxAttackDistance", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.passive.EntityLlama.AIHurtByTarget.class) - public class AIHurtByTargetTypeAdapter extends FineTypeAdapter { - - public AIHurtByTargetTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.passive.EntityLlama.AIDefendTarget.class) - public class AIDefendTargetTypeAdapter extends FineTypeAdapter { - - public AIDefendTargetTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeFloat.class) - public class AISlimeFloatTypeAdapter extends FineTypeAdapter { - - public AISlimeFloatTypeAdapter() { - register("slime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeAttack.class) - public class AISlimeAttackTypeAdapter extends FineTypeAdapter { - - public AISlimeAttackTypeAdapter() { - register("slime", FineMode.FINE); - register("growTieredTimer", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeFaceRandom.class) - public class AISlimeFaceRandomTypeAdapter extends FineTypeAdapter { - - public AISlimeFaceRandomTypeAdapter() { - register("slime", FineMode.FINE); - register("chosenDegrees", FineMode.FINE); - register("nextRandomizeTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySlime.AISlimeHop.class) - public class AISlimeHopTypeAdapter extends FineTypeAdapter { - - public AISlimeHopTypeAdapter() { - register("slime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearest.class) - public class EntityAIFindEntityNearestTypeAdapter extends FineTypeAdapter { - - public EntityAIFindEntityNearestTypeAdapter() { - register("LOGGER", FineMode.FINE); - register("mob", FineMode.FINE); - register("predicate", FineMode.FINE); - register("sorter", FineMode.FINE); - register("target", FineMode.FINE); - register("classToCheck", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwnerFlying.class) - public class EntityAIFollowOwnerFlyingTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowOwnerFlyingTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWaterFlying.class) - public class EntityAIWanderAvoidWaterFlyingTypeAdapter extends FineTypeAdapter { - - public EntityAIWanderAvoidWaterFlyingTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILandOnOwnersShoulder.class) - public class EntityAILandOnOwnersShoulderTypeAdapter extends FineTypeAdapter { - - public EntityAILandOnOwnersShoulderTypeAdapter() { - register("entity", FineMode.FINE); - register("owner", FineMode.FINE); - register("isSittingOnShoulder", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollow.class) - public class EntityAIFollowTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowTypeAdapter() { - register("entity", FineMode.FINE); - register("followPredicate", FineMode.FINE); - register("followingEntity", FineMode.FINE); - register("speedModifier", FineMode.FINE); - register("navigation", FineMode.FINE); - register("timeToRecalcPath", FineMode.FINE); - register("stopDistance", FineMode.FINE); - register("oldWaterCost", FineMode.FINE); - register("areaSize", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIMeleeAttack.class) - public class AIMeleeAttackTypeAdapter extends FineTypeAdapter { - - public AIMeleeAttackTypeAdapter() { - register("f_1682088", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIPanic.class) - public class AIPanicTypeAdapter extends FineTypeAdapter { - - public AIPanicTypeAdapter() { - register("f_1588945", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIHurtByTarget.class) - public class AIHurtByTargetTypeAdapter2 extends FineTypeAdapter { - - public AIHurtByTargetTypeAdapter2() { - register("f_4352699", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityPolarBear.AIAttackPlayer.class) - public class AIAttackPlayerTypeAdapter extends FineTypeAdapter { - - public AIAttackPlayerTypeAdapter() { - register("f_4967813", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.passive.EntityRabbit.AIPanic.class) - public class AIPanicTypeAdapter2 extends FineTypeAdapter { - - public AIPanicTypeAdapter2() { - register("rabbit", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.passive.EntityRabbit.AIAvoidEntity.class) - public class AIAvoidEntityTypeAdapter extends FineTypeAdapter { - - public AIAvoidEntityTypeAdapter() { - register("rabbit", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.passive.EntityRabbit.AIRaidFarm.class) - public class AIRaidFarmTypeAdapter extends FineTypeAdapter { - - public AIRaidFarmTypeAdapter() { - register("rabbit", FineMode.FINE); - register("wantsToRaid", FineMode.FINE); - register("canRaid", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIEatGrass.class) - public class EntityAIEatGrassTypeAdapter extends FineTypeAdapter { - - public EntityAIEatGrassTypeAdapter() { - register("IS_TALL_GRASS", FineMode.FINE); - register("grassEaterEntity", FineMode.FINE); - register("entityWorld", FineMode.FINE); - register("eatingGrassTimer", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityShulker.AIAttack.class) - public class AIAttackTypeAdapter extends FineTypeAdapter { - - public AIAttackTypeAdapter() { - register("attackTime", FineMode.FINE); - register("f_0549306", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityShulker.AIPeek.class) - public class AIPeekTypeAdapter extends FineTypeAdapter { - - public AIPeekTypeAdapter() { - register("peekTime", FineMode.FINE); - register("f_7126754", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityShulker.AIAttackNearest.class) - public class AIAttackNearestTypeAdapter extends FineTypeAdapter { - - public AIAttackNearestTypeAdapter() { - register("f_8711122", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityShulker.AIDefenseAttack.class) - public class AIDefenseAttackTypeAdapter extends FineTypeAdapter { - - public AIDefenseAttackTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySilverfish.AISummonSilverfish.class) - public class AISummonSilverfishTypeAdapter extends FineTypeAdapter { - - public AISummonSilverfishTypeAdapter() { - register("silverfish", FineMode.FINE); - register("lookForFriends", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySilverfish.AIHideInStone.class) - public class AIHideInStoneTypeAdapter extends FineTypeAdapter { - - public AIHideInStoneTypeAdapter() { - register("facing", FineMode.FINE); - register("doMerge", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIRestrictSun.class) - public class EntityAIRestrictSunTypeAdapter extends FineTypeAdapter { - - public EntityAIRestrictSunTypeAdapter() { - register("entity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFleeSun.class) - public class EntityAIFleeSunTypeAdapter extends FineTypeAdapter { - - public EntityAIFleeSunTypeAdapter() { - register("creature", FineMode.FINE); - register("shelterX", FineMode.FINE); - register("shelterY", FineMode.FINE); - register("shelterZ", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - register("world", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAttackRangedBow.class) - public class EntityAIAttackRangedBowTypeAdapter extends FineTypeAdapter { - - public EntityAIAttackRangedBowTypeAdapter() { - register("entity", FineMode.FINE); - register("moveSpeedAmp", FineMode.FINE); - register("attackCooldown", FineMode.FINE); - register("maxAttackDistance", FineMode.FINE); - register("attackTime", FineMode.FINE); - register("seeTime", FineMode.FINE); - register("strafingClockwise", FineMode.FINE); - register("strafingBackwards", FineMode.FINE); - register("strafingTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAISkeletonRiders.class) - public class EntityAISkeletonRidersTypeAdapter extends FineTypeAdapter { - - public EntityAISkeletonRidersTypeAdapter() { - register("horse", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.passive.EntitySquid.AIMoveRandom.class) - public class AIMoveRandomTypeAdapter extends FineTypeAdapter { - - public AIMoveRandomTypeAdapter() { - register("squid", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityVex.AIChargeAttack.class) - public class AIChargeAttackTypeAdapter extends FineTypeAdapter { - - public AIChargeAttackTypeAdapter() { - register("f_5200292", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityVex.AIMoveRandom.class) - public class AIMoveRandomTypeAdapter2 extends FineTypeAdapter { - - public AIMoveRandomTypeAdapter2() { - register("f_3949223", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityVex.AICopyOwnerTarget.class) - public class AICopyOwnerTargetTypeAdapter extends FineTypeAdapter { - - public AICopyOwnerTargetTypeAdapter() { - register("f_7758303", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITradePlayer.class) - public class EntityAITradePlayerTypeAdapter extends FineTypeAdapter { - - public EntityAITradePlayerTypeAdapter() { - register("villager", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILookAtTradePlayer.class) - public class EntityAILookAtTradePlayerTypeAdapter extends FineTypeAdapter { - - public EntityAILookAtTradePlayerTypeAdapter() { - register("villager", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveIndoors.class) - public class EntityAIMoveIndoorsTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveIndoorsTypeAdapter() { - register("entity", FineMode.FINE); - register("doorInfo", FineMode.FINE); - register("insidePosX", FineMode.FINE); - register("insidePosZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIRestrictOpenDoor.class) - public class EntityAIRestrictOpenDoorTypeAdapter extends FineTypeAdapter { - - public EntityAIRestrictOpenDoorTypeAdapter() { - register("entity", FineMode.FINE); - register("frontDoor", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOpenDoor.class) - public class EntityAIOpenDoorTypeAdapter extends FineTypeAdapter { - - public EntityAIOpenDoorTypeAdapter() { - register("closeDoor", FineMode.FINE); - register("closeDoorTemporisation", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIVillagerMate.class) - public class EntityAIVillagerMateTypeAdapter extends FineTypeAdapter { - - public EntityAIVillagerMateTypeAdapter() { - register("villager", FineMode.FINE); - register("mate", FineMode.FINE); - register("world", FineMode.FINE); - register("matingTimeout", FineMode.FINE); - register("village", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowGolem.class) - public class EntityAIFollowGolemTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowGolemTypeAdapter() { - register("villager", FineMode.FINE); - register("ironGolem", FineMode.FINE); - register("takeGolemRoseTick", FineMode.FINE); - register("tookGolemRose", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest2.class) - public class EntityAIWatchClosest2TypeAdapter extends FineTypeAdapter { - - public EntityAIWatchClosest2TypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIVillagerInteract.class) - public class EntityAIVillagerInteractTypeAdapter extends FineTypeAdapter { - - public EntityAIVillagerInteractTypeAdapter() { - register("interactionDelay", FineMode.FINE); - register("villager", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIHarvestFarmland.class) - public class EntityAIHarvestFarmlandTypeAdapter extends FineTypeAdapter { - - public EntityAIHarvestFarmlandTypeAdapter() { - register("villager", FineMode.FINE); - register("hasFarmItem", FineMode.FINE); - register("wantsToReapStuff", FineMode.FINE); - register("currentTask", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityVindicator.AIJohnnyAttack.class) - public class AIJohnnyAttackTypeAdapter extends FineTypeAdapter { - - public AIJohnnyAttackTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySpellcasterIllager.AICastingApell.class) - public class AICastingApellTypeAdapter extends FineTypeAdapter { - - public AICastingApellTypeAdapter() { - register("f_1024672", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntitySpellcasterIllager.AIUseSpell.class) - public class AIUseSpellTypeAdapter extends FineTypeAdapter { - - public AIUseSpellTypeAdapter() { - register("spellWarmup", FineMode.FINE); - register("spellCooldown", FineMode.FINE); - register("f_4432138", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityIllusionIllager.AIMirriorSpell.class) - public class AIMirriorSpellTypeAdapter extends FineTypeAdapter { - - public AIMirriorSpellTypeAdapter() { - register("f_4096963", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityIllusionIllager.AIBlindnessSpell.class) - public class AIBlindnessSpellTypeAdapter extends FineTypeAdapter { - - public AIBlindnessSpellTypeAdapter() { - register("lastTargetId", FineMode.FINE); - register("f_2457942", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.passive.EntityWolf.AIAvoidEntity.class) - public class AIAvoidEntityTypeAdapter2 extends FineTypeAdapter { - - public AIAvoidEntityTypeAdapter2() { - register("wolf", FineMode.FINE); - register("f_5613973", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIBeg.class) - public class EntityAIBegTypeAdapter extends FineTypeAdapter { - - public EntityAIBegTypeAdapter() { - register("wolf", FineMode.FINE); - register("player", FineMode.FINE); - register("world", FineMode.FINE); - register("minPlayerDistance", FineMode.FINE); - register("timeoutCounter", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtByTarget.class) - public class EntityAIOwnerHurtByTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIOwnerHurtByTargetTypeAdapter() { - register("tameable", FineMode.FINE); - register("attacker", FineMode.FINE); - register("timestamp", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtTarget.class) - public class EntityAIOwnerHurtTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIOwnerHurtTargetTypeAdapter() { - register("tameable", FineMode.FINE); - register("attacker", FineMode.FINE); - register("timestamp", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.boss.EntityWither.AIDoNothing.class) - public class AIDoNothingTypeAdapter extends FineTypeAdapter { - - public AIDoNothingTypeAdapter() { - register("f_4462935", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.monster.EntityPigZombie.AIHurtByAggressor.class) - public class AIHurtByAggressorTypeAdapter extends FineTypeAdapter { - - public AIHurtByAggressorTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.monster.EntityPigZombie.AITargetAggressor.class) - public class AITargetAggressorTypeAdapter extends FineTypeAdapter { - - public AITargetAggressorTypeAdapter() { - } - } - -} +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.util.HashSet; +import java.util.Set; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineMultiTarget; +import com.minecrafttas.mctcommon.json.FineTarget; +import com.minecrafttas.mctcommon.json.FineTypeAdapter; + +import net.minecraft.item.Item; + +@FineMultiTarget +public class EntityAITypeAdapters { + + @FineTarget(net.minecraft.entity.ai.EntityAIBase.class) + public static class EntityAIBaseTypeAdapter extends FineTypeAdapter { + + public EntityAIBaseTypeAdapter() { + register("mutexBits", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsRestriction.class) + public static class EntityAIMoveTowardsRestrictionTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveTowardsRestrictionTypeAdapter() { + register("creature", FineMode.FINE); + register("movePosX", FineMode.FINE); + register("movePosY", FineMode.FINE); + register("movePosZ", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWander.class) + public static class EntityAIWanderTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderTypeAdapter() { + register("entity", FineMode.FINE); + register("x", FineMode.FINE); + register("y", FineMode.FINE); + register("z", FineMode.FINE); + register("speed", FineMode.FINE); + register("executionChance", FineMode.FINE); + register("mustUpdate", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWater.class) + public static class EntityAIWanderAvoidWaterTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderAvoidWaterTypeAdapter() { + register("probability", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest.class) + public static class EntityAIWatchClosestTypeAdapter extends FineTypeAdapter { + + public EntityAIWatchClosestTypeAdapter() { + register("entity", FineMode.FINE); + register("closestEntity", FineMode.FINE); + register("maxDistance", FineMode.FINE); + register("lookTime", FineMode.FINE); + register("chance", FineMode.FINE); + register("watchedClass", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookIdle.class) + public static class EntityAILookIdleTypeAdapter extends FineTypeAdapter { + + public EntityAILookIdleTypeAdapter() { + register("idleEntity", FineMode.FINE); + register("lookX", FineMode.FINE); + register("lookZ", FineMode.FINE); + register("idleTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITarget.class) + public static class EntityAITargetTypeAdapter extends FineTypeAdapter { + + public EntityAITargetTypeAdapter() { + register("taskOwner", FineMode.FINE); + register("shouldCheckSight", FineMode.FINE); + register("nearbyOnly", FineMode.FINE); + register("targetSearchStatus", FineMode.FINE); + register("targetSearchDelay", FineMode.FINE); + register("targetUnseenTicks", FineMode.FINE); + register("target", FineMode.FINE); + register("unseenMemoryTicks", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIHurtByTarget.class) + public static class EntityAIHurtByTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIHurtByTargetTypeAdapter() { + register("entityCallsForHelp", FineMode.FINE); + register("revengeTimerOld", FineMode.FINE); + register("excludedReinforcementTypes", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAINearestAttackableTarget.class) + public static class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { + + public EntityAINearestAttackableTargetTypeAdapter() { + register("targetClass", FineMode.FINE); + register("targetChance", FineMode.FINE); + register("sorter", FineMode.FINE); + register("targetEntitySelector", FineMode.FINE); + register("targetEntity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISit.class) + public static class EntityAISitTypeAdapter extends FineTypeAdapter { + + public EntityAISitTypeAdapter() { + register("tameable", FineMode.FINE); + register("isSitting", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITempt.class) + public static class EntityAITemptTypeAdapter extends FineTypeAdapter { + + public EntityAITemptTypeAdapter() { + register("temptedEntity", FineMode.FINE); + register("speed", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + register("pitch", FineMode.FINE); + register("yaw", FineMode.FINE); + register("temptingPlayer", FineMode.FINE); + register("delayTemptCounter", FineMode.FINE); + register("isRunning", FineMode.FINE); + register("temptItem", (obj, fgson) -> { + JsonArray out = new JsonArray(); + @SuppressWarnings("unchecked") + Set in = (Set) obj; + for (Item item : in) { + out.add(fgson.serialize(item, Item.class)); + } + return out; + }, (elem, fgson) -> { + Set out = new HashSet<>(); + JsonArray in = elem.getAsJsonArray(); + for (JsonElement element : in) { + out.add((Item) fgson.deserialize(element, Item.class)); + } + return out; + }); + register("scaredByPlayerMovement", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISwimming.class) + public static class EntityAISwimmingTypeAdapter extends FineTypeAdapter { + + public EntityAISwimmingTypeAdapter() { + register("entity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwner.class) + public static class EntityAIFollowOwnerTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowOwnerTypeAdapter() { + register("tameable", FineMode.FINE); + register("owner", FineMode.FINE); + register("world", FineMode.FINE); + register("followSpeed", FineMode.FINE); + register("petPathfinder", FineMode.FINE); + register("timeToRecalcPath", FineMode.FINE); + register("maxDist", FineMode.FINE); + register("minDist", FineMode.FINE); + register("oldWaterCost", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveToBlock.class) + public static class EntityAIMoveToBlockTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveToBlockTypeAdapter() { + register("creature", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("runDelay", FineMode.FINE); + register("timeoutCounter", FineMode.FINE); + register("maxStayTicks", FineMode.FINE); + register("destinationBlock", FineMode.FINE); + register("isAboveDestination", FineMode.FINE); + register("searchLength", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOcelotSit.class) + public static class EntityAIOcelotSitTypeAdapter extends FineTypeAdapter { + + public EntityAIOcelotSitTypeAdapter() { + register("ocelot", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILeapAtTarget.class) + public static class EntityAILeapAtTargetTypeAdapter extends FineTypeAdapter { + + public EntityAILeapAtTargetTypeAdapter() { + register("leaper", FineMode.FINE); + register("leapTarget", FineMode.FINE); + register("leapMotionY", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOcelotAttack.class) + public static class EntityAIOcelotAttackTypeAdapter extends FineTypeAdapter { + + public EntityAIOcelotAttackTypeAdapter() { + register("world", FineMode.FINE); + register("entity", FineMode.FINE); + register("target", FineMode.FINE); + register("attackCountdown", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMate.class) + public static class EntityAIMateTypeAdapter extends FineTypeAdapter { + + public EntityAIMateTypeAdapter() { + register("animal", FineMode.FINE); + register("mateClass", FineMode.FINE); + register("world", FineMode.FINE); + register("targetMate", FineMode.FINE); + register("spawnBabyDelay", FineMode.FINE); + register("moveSpeed", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITargetNonTamed.class) + public static class EntityAITargetNonTamedTypeAdapter extends FineTypeAdapter { + + public EntityAITargetNonTamedTypeAdapter() { + register("tameable", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAvoidEntity.class) + public static class EntityAIAvoidEntityTypeAdapter extends FineTypeAdapter { + + public EntityAIAvoidEntityTypeAdapter() { + register("canBeSeenSelector", FineMode.FINE); + register("entity", FineMode.FINE); + register("farSpeed", FineMode.FINE); + register("nearSpeed", FineMode.FINE); + register("closestLivingEntity", FineMode.FINE); + register("avoidDistance", FineMode.FINE); + register("path", FineMode.FINE); + register("navigation", FineMode.FINE); + register("classToAvoid", FineMode.FINE); + register("avoidTargetSelector", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAICreeperSwell.class) + public static class EntityAICreeperSwellTypeAdapter extends FineTypeAdapter { + + public EntityAICreeperSwellTypeAdapter() { + register("swellingCreeper", FineMode.FINE); + register("creeperAttackTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackMelee.class) + public static class EntityAIAttackMeleeTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackMeleeTypeAdapter() { + register("world", FineMode.FINE); + register("attacker", FineMode.FINE); + register("attackTick", FineMode.FINE); + register("speedTowardsTarget", FineMode.FINE); + register("longMemory", FineMode.FINE); + register("path", FineMode.FINE); + register("delayCounter", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + register("attackInterval", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIPanic.class) + public static class EntityAIPanicTypeAdapter extends FineTypeAdapter { + + public EntityAIPanicTypeAdapter() { + register("creature", FineMode.FINE); + register("speed", FineMode.FINE); + register("randPosX", FineMode.FINE); + register("randPosY", FineMode.FINE); + register("randPosZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowParent.class) + public static class EntityAIFollowParentTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowParentTypeAdapter() { + register("childAnimal", FineMode.FINE); + register("parentAnimal", FineMode.FINE); + register("moveSpeed", FineMode.FINE); + register("delayCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRunAroundLikeCrazy.class) + public static class EntityAIRunAroundLikeCrazyTypeAdapter extends FineTypeAdapter { + + public EntityAIRunAroundLikeCrazyTypeAdapter() { + register("horseHost", FineMode.FINE); + register("speed", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearestPlayer.class) + public static class EntityAIFindEntityNearestPlayerTypeAdapter extends FineTypeAdapter { + + public EntityAIFindEntityNearestPlayerTypeAdapter() { + register("LOGGER", FineMode.EXCLUDED); + register("entityLiving", FineMode.FINE); + register("predicate", FineMode.FINE); + register("sorter", FineMode.FINE); + register("entityTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIZombieAttack.class) + public static class EntityAIZombieAttackTypeAdapter extends FineTypeAdapter { + + public EntityAIZombieAttackTypeAdapter() { + register("zombie", FineMode.FINE); + register("raiseArmTicks", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveThroughVillage.class) + public static class EntityAIMoveThroughVillageTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveThroughVillageTypeAdapter() { + register("entity", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("path", FineMode.FINE); + register("doorInfo", FineMode.FINE); + register("isNocturnal", FineMode.FINE); + register("doorList", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIDoorInteract.class) + public static class EntityAIDoorInteractTypeAdapter extends FineTypeAdapter { + + public EntityAIDoorInteractTypeAdapter() { + register("entity", FineMode.FINE); + register("doorPosition", FineMode.FINE); + register("doorBlock", FineMode.FINE); + register("hasStoppedDoorInteraction", FineMode.FINE); + register("entityPositionX", FineMode.FINE); + register("entityPositionZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIBreakDoor.class) + public static class EntityAIBreakDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIBreakDoorTypeAdapter() { + register("breakingTime", FineMode.FINE); + register("previousBreakProgress", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsTarget.class) + public static class EntityAIMoveTowardsTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveTowardsTargetTypeAdapter() { + register("creature", FineMode.FINE); + register("targetEntity", FineMode.FINE); + register("movePosX", FineMode.FINE); + register("movePosY", FineMode.FINE); + register("movePosZ", FineMode.FINE); + register("speed", FineMode.FINE); + register("maxTargetDistance", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookAtVillager.class) + public static class EntityAILookAtVillagerTypeAdapter extends FineTypeAdapter { + + public EntityAILookAtVillagerTypeAdapter() { + register("ironGolem", FineMode.FINE); + register("villager", FineMode.FINE); + register("lookTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIDefendVillage.class) + public static class EntityAIDefendVillageTypeAdapter extends FineTypeAdapter { + + public EntityAIDefendVillageTypeAdapter() { + register("irongolem", FineMode.FINE); + register("villageAgressorTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILlamaFollowCaravan.class) + public static class EntityAILlamaFollowCaravanTypeAdapter extends FineTypeAdapter { + + public EntityAILlamaFollowCaravanTypeAdapter() { + register("llama", FineMode.FINE); + register("speedModifier", FineMode.FINE); + register("distCheckCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackRanged.class) + public static class EntityAIAttackRangedTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackRangedTypeAdapter() { + register("entityHost", FineMode.FINE); + register("rangedAttackEntityHost", FineMode.FINE); + register("attackTarget", FineMode.FINE); + register("rangedAttackTime", FineMode.FINE); + register("entityMoveSpeed", FineMode.FINE); + register("seeTime", FineMode.FINE); + register("attackIntervalMin", FineMode.FINE); + register("maxRangedAttackTime", FineMode.FINE); + register("attackRadius", FineMode.FINE); + register("maxAttackDistance", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearest.class) + public static class EntityAIFindEntityNearestTypeAdapter extends FineTypeAdapter { + + public EntityAIFindEntityNearestTypeAdapter() { + register("LOGGER", FineMode.EXCLUDED); + register("mob", FineMode.FINE); + register("predicate", FineMode.FINE); + register("sorter", FineMode.FINE); + register("target", FineMode.FINE); + register("classToCheck", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwnerFlying.class) + public static class EntityAIFollowOwnerFlyingTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowOwnerFlyingTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWaterFlying.class) + public static class EntityAIWanderAvoidWaterFlyingTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderAvoidWaterFlyingTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILandOnOwnersShoulder.class) + public static class EntityAILandOnOwnersShoulderTypeAdapter extends FineTypeAdapter { + + public EntityAILandOnOwnersShoulderTypeAdapter() { + register("entity", FineMode.FINE); + register("owner", FineMode.FINE); + register("isSittingOnShoulder", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollow.class) + public static class EntityAIFollowTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowTypeAdapter() { + register("entity", FineMode.FINE); + register("followPredicate", FineMode.FINE); + register("followingEntity", FineMode.FINE); + register("speedModifier", FineMode.FINE); + register("navigation", FineMode.FINE); + register("timeToRecalcPath", FineMode.FINE); + register("stopDistance", FineMode.FINE); + register("oldWaterCost", FineMode.FINE); + register("areaSize", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIEatGrass.class) + public static class EntityAIEatGrassTypeAdapter extends FineTypeAdapter { + + public EntityAIEatGrassTypeAdapter() { + register("IS_TALL_GRASS", FineMode.FINE); + register("grassEaterEntity", FineMode.FINE); + register("entityWorld", FineMode.FINE); + register("eatingGrassTimer", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRestrictSun.class) + public static class EntityAIRestrictSunTypeAdapter extends FineTypeAdapter { + + public EntityAIRestrictSunTypeAdapter() { + register("entity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFleeSun.class) + public static class EntityAIFleeSunTypeAdapter extends FineTypeAdapter { + + public EntityAIFleeSunTypeAdapter() { + register("creature", FineMode.FINE); + register("shelterX", FineMode.FINE); + register("shelterY", FineMode.FINE); + register("shelterZ", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("world", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackRangedBow.class) + public static class EntityAIAttackRangedBowTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackRangedBowTypeAdapter() { + register("entity", FineMode.FINE); + register("moveSpeedAmp", FineMode.FINE); + register("attackCooldown", FineMode.FINE); + register("maxAttackDistance", FineMode.FINE); + register("attackTime", FineMode.FINE); + register("seeTime", FineMode.FINE); + register("strafingClockwise", FineMode.FINE); + register("strafingBackwards", FineMode.FINE); + register("strafingTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISkeletonRiders.class) + public static class EntityAISkeletonRidersTypeAdapter extends FineTypeAdapter { + + public EntityAISkeletonRidersTypeAdapter() { + register("horse", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITradePlayer.class) + public static class EntityAITradePlayerTypeAdapter extends FineTypeAdapter { + + public EntityAITradePlayerTypeAdapter() { + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookAtTradePlayer.class) + public static class EntityAILookAtTradePlayerTypeAdapter extends FineTypeAdapter { + + public EntityAILookAtTradePlayerTypeAdapter() { + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveIndoors.class) + public static class EntityAIMoveIndoorsTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveIndoorsTypeAdapter() { + register("entity", FineMode.FINE); + register("doorInfo", FineMode.FINE); + register("insidePosX", FineMode.FINE); + register("insidePosZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRestrictOpenDoor.class) + public static class EntityAIRestrictOpenDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIRestrictOpenDoorTypeAdapter() { + register("entity", FineMode.FINE); + register("frontDoor", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOpenDoor.class) + public static class EntityAIOpenDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIOpenDoorTypeAdapter() { + register("closeDoor", FineMode.FINE); + register("closeDoorTemporisation", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIVillagerMate.class) + public static class EntityAIVillagerMateTypeAdapter extends FineTypeAdapter { + + public EntityAIVillagerMateTypeAdapter() { + register("villager", FineMode.FINE); + register("mate", FineMode.FINE); + register("world", FineMode.FINE); + register("matingTimeout", FineMode.FINE); + register("village", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowGolem.class) + public static class EntityAIFollowGolemTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowGolemTypeAdapter() { + register("villager", FineMode.FINE); + register("ironGolem", FineMode.FINE); + register("takeGolemRoseTick", FineMode.FINE); + register("tookGolemRose", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest2.class) + public static class EntityAIWatchClosest2TypeAdapter extends FineTypeAdapter { + + public EntityAIWatchClosest2TypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIVillagerInteract.class) + public static class EntityAIVillagerInteractTypeAdapter extends FineTypeAdapter { + + public EntityAIVillagerInteractTypeAdapter() { + register("interactionDelay", FineMode.FINE); + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIHarvestFarmland.class) + public static class EntityAIHarvestFarmlandTypeAdapter extends FineTypeAdapter { + + public EntityAIHarvestFarmlandTypeAdapter() { + register("villager", FineMode.FINE); + register("hasFarmItem", FineMode.FINE); + register("wantsToReapStuff", FineMode.FINE); + register("currentTask", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIBeg.class) + public static class EntityAIBegTypeAdapter extends FineTypeAdapter { + + public EntityAIBegTypeAdapter() { + register("wolf", FineMode.FINE); + register("player", FineMode.FINE); + register("world", FineMode.FINE); + register("minPlayerDistance", FineMode.FINE); + register("timeoutCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtByTarget.class) + public static class EntityAIOwnerHurtByTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIOwnerHurtByTargetTypeAdapter() { + register("tameable", FineMode.FINE); + register("attacker", FineMode.FINE); + register("timestamp", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtTarget.class) + public static class EntityAIOwnerHurtTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIOwnerHurtTargetTypeAdapter() { + register("tameable", FineMode.FINE); + register("attacker", FineMode.FINE); + register("timestamp", FineMode.FINE); + } + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java index 0a4568cd..b07d151f 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java @@ -1,25 +1,25 @@ package com.minecrafttas.tasmod.savestates.typeadapters; -import java.io.IOException; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.minecrafttas.mctcommon.json.FineGson; +import com.minecrafttas.mctcommon.json.FineTypeAdapter; import net.minecraft.item.Item; -public class ItemTypeAdapter extends TypeAdapter { +public class ItemTypeAdapter extends FineTypeAdapter { @Override - public void write(JsonWriter out, Item value) throws IOException { - out.value(Item.getIdFromItem(value)); + public JsonElement serialize(Object obj, FineGson fineJson, Class clazz) throws RuntimeException { + Item value = (Item) obj; + return new JsonPrimitive(Item.getIdFromItem(value)); } @Override - public Item read(JsonReader in) throws IOException { - if (!in.hasNext()) - return null; - return Item.getItemById(in.nextInt()); + public Object deserialize(JsonElement element, Class clazz, FineGson fineJson) { + JsonPrimitive value = element.getAsJsonPrimitive(); + Item.getItemById(value.getAsInt()); + return super.deserialize(element, clazz, fineJson); } } diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 41a51b3b..2e7d0b3d 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -64,48 +64,4 @@ mutable field net/minecraft/entity/ai/EntityAITasks taskEntries Ljava/util/Set; mutable field net/minecraft/entity/ai/EntityAITasks$EntityAITaskEntry action Lnet/minecraft/entity/ai/EntityAIBase; accessible field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; -mutable field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; - -accessible class net/minecraft/entity/monster/EntityBlaze$AIFireballAttack -accessible class net/minecraft/entity/monster/EntitySpider$AISpiderAttack -accessible class net/minecraft/entity/monster/EntitySpider$AISpiderTarget -accessible class net/minecraft/entity/monster/EntityGuardian$AIGuardianAttack -accessible class net/minecraft/entity/monster/EntityEnderman$AIPlaceBlock -accessible class net/minecraft/entity/monster/EntityEnderman$AITakeBlock -accessible class net/minecraft/entity/monster/EntityEnderman$AIFindPlayer -accessible class net/minecraft/entity/monster/EntityGhast$AIRandomFly -accessible class net/minecraft/entity/monster/EntityGhast$AILookAround -accessible class net/minecraft/entity/monster/EntityGhast$AIFireballAttack -accessible class net/minecraft/entity/passive/EntityLlama$AIHurtByTarget -accessible class net/minecraft/entity/passive/EntityLlama$AIDefendTarget -accessible class net/minecraft/entity/monster/EntitySlime$AISlimeFloat -accessible class net/minecraft/entity/monster/EntitySlime$AISlimeAttack -accessible class net/minecraft/entity/monster/EntitySlime$AISlimeFaceRandom -accessible class net/minecraft/entity/monster/EntitySlime$AISlimeHop -accessible class net/minecraft/entity/monster/EntityPolarBear$AIMeleeAttack -accessible class net/minecraft/entity/monster/EntityPolarBear$AIPanic -accessible class net/minecraft/entity/monster/EntityPolarBear$AIHurtByTarget -accessible class net/minecraft/entity/monster/EntityPolarBear$AIAttackPlayer -accessible class net/minecraft/entity/passive/EntityRabbit$AIPanic -accessible class net/minecraft/entity/passive/EntityRabbit$AIAvoidEntity -accessible class net/minecraft/entity/passive/EntityRabbit$AIRaidFarm -accessible class net/minecraft/entity/monster/EntityShulker$AIAttack -accessible class net/minecraft/entity/monster/EntityShulker$AIPeek -accessible class net/minecraft/entity/monster/EntityShulker$AIAttackNearest -accessible class net/minecraft/entity/monster/EntityShulker$AIDefenseAttack -accessible class net/minecraft/entity/monster/EntitySilverfish$AISummonSilverfish -accessible class net/minecraft/entity/monster/EntitySilverfish$AIHideInStone -accessible class net/minecraft/entity/monster/AbstractSkeleton$1 -accessible class net/minecraft/entity/passive/EntitySquid$AIMoveRandom -accessible class net/minecraft/entity/monster/EntityVex$AIChargeAttack -accessible class net/minecraft/entity/monster/EntityVex$AIMoveRandom -accessible class net/minecraft/entity/monster/EntityVex$AICopyOwnerTarget -accessible class net/minecraft/entity/monster/EntityVindicator$AIJohnnyAttack -accessible class net/minecraft/entity/monster/EntitySpellcasterIllager$AICastingApell -accessible class net/minecraft/entity/monster/EntitySpellcasterIllager$AIUseSpell -accessible class net/minecraft/entity/monster/EntityIllusionIllager$AIMirriorSpell -accessible class net/minecraft/entity/monster/EntityIllusionIllager$AIBlindnessSpell -accessible class net/minecraft/entity/passive/EntityWolf$AIAvoidEntity -accessible class net/minecraft/entity/boss/EntityWither$AIDoNothing -accessible class net/minecraft/entity/monster/EntityPigZombie$AIHurtByAggressor -accessible class net/minecraft/entity/monster/EntityPigZombie$AITargetAggressor \ No newline at end of file +mutable field net/minecraft/entity/ai/EntityAITasks executingTaskEntries Ljava/util/Set; \ No newline at end of file diff --git a/src/test/java/mctcommon/json/FineGsonTest.java b/src/test/java/mctcommon/json/FineGsonTest.java index 7335b00e..d5550819 100644 --- a/src/test/java/mctcommon/json/FineGsonTest.java +++ b/src/test/java/mctcommon/json/FineGsonTest.java @@ -66,7 +66,7 @@ public TestClassTypeAdapter() { public static class TestSuperClassAdapter extends FineTypeAdapter { public TestSuperClassAdapter() { register("bot", FineMode.FINE); - register("evil", obj -> new JsonPrimitive(((String) obj).toUpperCase()), element -> element.toString()); + register("evil", (obj, fgson) -> new JsonPrimitive(((String) obj).toUpperCase()), (element, fgson) -> element.toString()); } } diff --git a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java index 9c70675d..1a12c2f9 100644 --- a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java +++ b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java @@ -65,7 +65,7 @@ void testGenerateMulti() { + "public class GeneratedTypeAdapterTest {\n" + "\n" + " @FineTarget(TestSuperClass.class)\n" - + " public class TestSuperClassTypeAdapter extends FineTypeAdapter {\n" + + " public static class TestSuperClassTypeAdapter extends FineTypeAdapter {\n" + " \n" + " public TestSuperClassTypeAdapter() {\n" + " register(\"bot\", FineMode.FINE);\n" @@ -74,7 +74,7 @@ void testGenerateMulti() { + " }\n" + " \n" + " @FineTarget(TestClass.class)\n" - + " public class TestClassTypeAdapter extends FineTypeAdapter {\n" + + " public static class TestClassTypeAdapter extends FineTypeAdapter {\n" + " \n" + " public TestClassTypeAdapter() {\n" + " register(\"index\", FineMode.FINE);\n" From ef4bed34fd7fb4ba5951a5bbc3233dfba0cb8bf7 Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 21 Sep 2026 15:25:12 +0200 Subject: [PATCH 23/26] Disable generator test --- .../mctcommon/json/FineTarget.java | 2 +- .../typeadapters/EntityAITypeAdapters.java | 1368 ++++++++--------- .../json/FineTypeAdapterGeneratorTest.java | 116 -- 3 files changed, 685 insertions(+), 801 deletions(-) delete mode 100644 src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java index 13916c07..83c9f71f 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java @@ -10,4 +10,4 @@ @Retention(RetentionPolicy.RUNTIME) public @interface FineTarget { Class value(); -} \ No newline at end of file +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java index e73eeec6..aeccb5f6 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java @@ -1,684 +1,684 @@ -package com.minecrafttas.tasmod.savestates.typeadapters; - -import java.util.HashSet; -import java.util.Set; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.minecrafttas.mctcommon.json.FineField.FineMode; -import com.minecrafttas.mctcommon.json.FineMultiTarget; -import com.minecrafttas.mctcommon.json.FineTarget; -import com.minecrafttas.mctcommon.json.FineTypeAdapter; - -import net.minecraft.item.Item; - -@FineMultiTarget -public class EntityAITypeAdapters { - - @FineTarget(net.minecraft.entity.ai.EntityAIBase.class) - public static class EntityAIBaseTypeAdapter extends FineTypeAdapter { - - public EntityAIBaseTypeAdapter() { - register("mutexBits", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsRestriction.class) - public static class EntityAIMoveTowardsRestrictionTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveTowardsRestrictionTypeAdapter() { - register("creature", FineMode.FINE); - register("movePosX", FineMode.FINE); - register("movePosY", FineMode.FINE); - register("movePosZ", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWander.class) - public static class EntityAIWanderTypeAdapter extends FineTypeAdapter { - - public EntityAIWanderTypeAdapter() { - register("entity", FineMode.FINE); - register("x", FineMode.FINE); - register("y", FineMode.FINE); - register("z", FineMode.FINE); - register("speed", FineMode.FINE); - register("executionChance", FineMode.FINE); - register("mustUpdate", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWater.class) - public static class EntityAIWanderAvoidWaterTypeAdapter extends FineTypeAdapter { - - public EntityAIWanderAvoidWaterTypeAdapter() { - register("probability", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest.class) - public static class EntityAIWatchClosestTypeAdapter extends FineTypeAdapter { - - public EntityAIWatchClosestTypeAdapter() { - register("entity", FineMode.FINE); - register("closestEntity", FineMode.FINE); - register("maxDistance", FineMode.FINE); - register("lookTime", FineMode.FINE); - register("chance", FineMode.FINE); - register("watchedClass", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILookIdle.class) - public static class EntityAILookIdleTypeAdapter extends FineTypeAdapter { - - public EntityAILookIdleTypeAdapter() { - register("idleEntity", FineMode.FINE); - register("lookX", FineMode.FINE); - register("lookZ", FineMode.FINE); - register("idleTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITarget.class) - public static class EntityAITargetTypeAdapter extends FineTypeAdapter { - - public EntityAITargetTypeAdapter() { - register("taskOwner", FineMode.FINE); - register("shouldCheckSight", FineMode.FINE); - register("nearbyOnly", FineMode.FINE); - register("targetSearchStatus", FineMode.FINE); - register("targetSearchDelay", FineMode.FINE); - register("targetUnseenTicks", FineMode.FINE); - register("target", FineMode.FINE); - register("unseenMemoryTicks", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIHurtByTarget.class) - public static class EntityAIHurtByTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIHurtByTargetTypeAdapter() { - register("entityCallsForHelp", FineMode.FINE); - register("revengeTimerOld", FineMode.FINE); - register("excludedReinforcementTypes", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAINearestAttackableTarget.class) - public static class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { - - public EntityAINearestAttackableTargetTypeAdapter() { - register("targetClass", FineMode.FINE); - register("targetChance", FineMode.FINE); - register("sorter", FineMode.FINE); - register("targetEntitySelector", FineMode.FINE); - register("targetEntity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAISit.class) - public static class EntityAISitTypeAdapter extends FineTypeAdapter { - - public EntityAISitTypeAdapter() { - register("tameable", FineMode.FINE); - register("isSitting", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITempt.class) - public static class EntityAITemptTypeAdapter extends FineTypeAdapter { - - public EntityAITemptTypeAdapter() { - register("temptedEntity", FineMode.FINE); - register("speed", FineMode.FINE); - register("targetX", FineMode.FINE); - register("targetY", FineMode.FINE); - register("targetZ", FineMode.FINE); - register("pitch", FineMode.FINE); - register("yaw", FineMode.FINE); - register("temptingPlayer", FineMode.FINE); - register("delayTemptCounter", FineMode.FINE); - register("isRunning", FineMode.FINE); - register("temptItem", (obj, fgson) -> { - JsonArray out = new JsonArray(); - @SuppressWarnings("unchecked") - Set in = (Set) obj; - for (Item item : in) { - out.add(fgson.serialize(item, Item.class)); - } - return out; - }, (elem, fgson) -> { - Set out = new HashSet<>(); - JsonArray in = elem.getAsJsonArray(); - for (JsonElement element : in) { - out.add((Item) fgson.deserialize(element, Item.class)); - } - return out; - }); - register("scaredByPlayerMovement", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAISwimming.class) - public static class EntityAISwimmingTypeAdapter extends FineTypeAdapter { - - public EntityAISwimmingTypeAdapter() { - register("entity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwner.class) - public static class EntityAIFollowOwnerTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowOwnerTypeAdapter() { - register("tameable", FineMode.FINE); - register("owner", FineMode.FINE); - register("world", FineMode.FINE); - register("followSpeed", FineMode.FINE); - register("petPathfinder", FineMode.FINE); - register("timeToRecalcPath", FineMode.FINE); - register("maxDist", FineMode.FINE); - register("minDist", FineMode.FINE); - register("oldWaterCost", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveToBlock.class) - public static class EntityAIMoveToBlockTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveToBlockTypeAdapter() { - register("creature", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - register("runDelay", FineMode.FINE); - register("timeoutCounter", FineMode.FINE); - register("maxStayTicks", FineMode.FINE); - register("destinationBlock", FineMode.FINE); - register("isAboveDestination", FineMode.FINE); - register("searchLength", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOcelotSit.class) - public static class EntityAIOcelotSitTypeAdapter extends FineTypeAdapter { - - public EntityAIOcelotSitTypeAdapter() { - register("ocelot", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILeapAtTarget.class) - public static class EntityAILeapAtTargetTypeAdapter extends FineTypeAdapter { - - public EntityAILeapAtTargetTypeAdapter() { - register("leaper", FineMode.FINE); - register("leapTarget", FineMode.FINE); - register("leapMotionY", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOcelotAttack.class) - public static class EntityAIOcelotAttackTypeAdapter extends FineTypeAdapter { - - public EntityAIOcelotAttackTypeAdapter() { - register("world", FineMode.FINE); - register("entity", FineMode.FINE); - register("target", FineMode.FINE); - register("attackCountdown", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMate.class) - public static class EntityAIMateTypeAdapter extends FineTypeAdapter { - - public EntityAIMateTypeAdapter() { - register("animal", FineMode.FINE); - register("mateClass", FineMode.FINE); - register("world", FineMode.FINE); - register("targetMate", FineMode.FINE); - register("spawnBabyDelay", FineMode.FINE); - register("moveSpeed", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITargetNonTamed.class) - public static class EntityAITargetNonTamedTypeAdapter extends FineTypeAdapter { - - public EntityAITargetNonTamedTypeAdapter() { - register("tameable", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAvoidEntity.class) - public static class EntityAIAvoidEntityTypeAdapter extends FineTypeAdapter { - - public EntityAIAvoidEntityTypeAdapter() { - register("canBeSeenSelector", FineMode.FINE); - register("entity", FineMode.FINE); - register("farSpeed", FineMode.FINE); - register("nearSpeed", FineMode.FINE); - register("closestLivingEntity", FineMode.FINE); - register("avoidDistance", FineMode.FINE); - register("path", FineMode.FINE); - register("navigation", FineMode.FINE); - register("classToAvoid", FineMode.FINE); - register("avoidTargetSelector", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAICreeperSwell.class) - public static class EntityAICreeperSwellTypeAdapter extends FineTypeAdapter { - - public EntityAICreeperSwellTypeAdapter() { - register("swellingCreeper", FineMode.FINE); - register("creeperAttackTarget", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAttackMelee.class) - public static class EntityAIAttackMeleeTypeAdapter extends FineTypeAdapter { - - public EntityAIAttackMeleeTypeAdapter() { - register("world", FineMode.FINE); - register("attacker", FineMode.FINE); - register("attackTick", FineMode.FINE); - register("speedTowardsTarget", FineMode.FINE); - register("longMemory", FineMode.FINE); - register("path", FineMode.FINE); - register("delayCounter", FineMode.FINE); - register("targetX", FineMode.FINE); - register("targetY", FineMode.FINE); - register("targetZ", FineMode.FINE); - register("attackInterval", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIPanic.class) - public static class EntityAIPanicTypeAdapter extends FineTypeAdapter { - - public EntityAIPanicTypeAdapter() { - register("creature", FineMode.FINE); - register("speed", FineMode.FINE); - register("randPosX", FineMode.FINE); - register("randPosY", FineMode.FINE); - register("randPosZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowParent.class) - public static class EntityAIFollowParentTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowParentTypeAdapter() { - register("childAnimal", FineMode.FINE); - register("parentAnimal", FineMode.FINE); - register("moveSpeed", FineMode.FINE); - register("delayCounter", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIRunAroundLikeCrazy.class) - public static class EntityAIRunAroundLikeCrazyTypeAdapter extends FineTypeAdapter { - - public EntityAIRunAroundLikeCrazyTypeAdapter() { - register("horseHost", FineMode.FINE); - register("speed", FineMode.FINE); - register("targetX", FineMode.FINE); - register("targetY", FineMode.FINE); - register("targetZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearestPlayer.class) - public static class EntityAIFindEntityNearestPlayerTypeAdapter extends FineTypeAdapter { - - public EntityAIFindEntityNearestPlayerTypeAdapter() { - register("LOGGER", FineMode.EXCLUDED); - register("entityLiving", FineMode.FINE); - register("predicate", FineMode.FINE); - register("sorter", FineMode.FINE); - register("entityTarget", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIZombieAttack.class) - public static class EntityAIZombieAttackTypeAdapter extends FineTypeAdapter { - - public EntityAIZombieAttackTypeAdapter() { - register("zombie", FineMode.FINE); - register("raiseArmTicks", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveThroughVillage.class) - public static class EntityAIMoveThroughVillageTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveThroughVillageTypeAdapter() { - register("entity", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - register("path", FineMode.FINE); - register("doorInfo", FineMode.FINE); - register("isNocturnal", FineMode.FINE); - register("doorList", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIDoorInteract.class) - public static class EntityAIDoorInteractTypeAdapter extends FineTypeAdapter { - - public EntityAIDoorInteractTypeAdapter() { - register("entity", FineMode.FINE); - register("doorPosition", FineMode.FINE); - register("doorBlock", FineMode.FINE); - register("hasStoppedDoorInteraction", FineMode.FINE); - register("entityPositionX", FineMode.FINE); - register("entityPositionZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIBreakDoor.class) - public static class EntityAIBreakDoorTypeAdapter extends FineTypeAdapter { - - public EntityAIBreakDoorTypeAdapter() { - register("breakingTime", FineMode.FINE); - register("previousBreakProgress", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsTarget.class) - public static class EntityAIMoveTowardsTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveTowardsTargetTypeAdapter() { - register("creature", FineMode.FINE); - register("targetEntity", FineMode.FINE); - register("movePosX", FineMode.FINE); - register("movePosY", FineMode.FINE); - register("movePosZ", FineMode.FINE); - register("speed", FineMode.FINE); - register("maxTargetDistance", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILookAtVillager.class) - public static class EntityAILookAtVillagerTypeAdapter extends FineTypeAdapter { - - public EntityAILookAtVillagerTypeAdapter() { - register("ironGolem", FineMode.FINE); - register("villager", FineMode.FINE); - register("lookTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIDefendVillage.class) - public static class EntityAIDefendVillageTypeAdapter extends FineTypeAdapter { - - public EntityAIDefendVillageTypeAdapter() { - register("irongolem", FineMode.FINE); - register("villageAgressorTarget", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILlamaFollowCaravan.class) - public static class EntityAILlamaFollowCaravanTypeAdapter extends FineTypeAdapter { - - public EntityAILlamaFollowCaravanTypeAdapter() { - register("llama", FineMode.FINE); - register("speedModifier", FineMode.FINE); - register("distCheckCounter", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAttackRanged.class) - public static class EntityAIAttackRangedTypeAdapter extends FineTypeAdapter { - - public EntityAIAttackRangedTypeAdapter() { - register("entityHost", FineMode.FINE); - register("rangedAttackEntityHost", FineMode.FINE); - register("attackTarget", FineMode.FINE); - register("rangedAttackTime", FineMode.FINE); - register("entityMoveSpeed", FineMode.FINE); - register("seeTime", FineMode.FINE); - register("attackIntervalMin", FineMode.FINE); - register("maxRangedAttackTime", FineMode.FINE); - register("attackRadius", FineMode.FINE); - register("maxAttackDistance", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearest.class) - public static class EntityAIFindEntityNearestTypeAdapter extends FineTypeAdapter { - - public EntityAIFindEntityNearestTypeAdapter() { - register("LOGGER", FineMode.EXCLUDED); - register("mob", FineMode.FINE); - register("predicate", FineMode.FINE); - register("sorter", FineMode.FINE); - register("target", FineMode.FINE); - register("classToCheck", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwnerFlying.class) - public static class EntityAIFollowOwnerFlyingTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowOwnerFlyingTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWaterFlying.class) - public static class EntityAIWanderAvoidWaterFlyingTypeAdapter extends FineTypeAdapter { - - public EntityAIWanderAvoidWaterFlyingTypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILandOnOwnersShoulder.class) - public static class EntityAILandOnOwnersShoulderTypeAdapter extends FineTypeAdapter { - - public EntityAILandOnOwnersShoulderTypeAdapter() { - register("entity", FineMode.FINE); - register("owner", FineMode.FINE); - register("isSittingOnShoulder", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollow.class) - public static class EntityAIFollowTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowTypeAdapter() { - register("entity", FineMode.FINE); - register("followPredicate", FineMode.FINE); - register("followingEntity", FineMode.FINE); - register("speedModifier", FineMode.FINE); - register("navigation", FineMode.FINE); - register("timeToRecalcPath", FineMode.FINE); - register("stopDistance", FineMode.FINE); - register("oldWaterCost", FineMode.FINE); - register("areaSize", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIEatGrass.class) - public static class EntityAIEatGrassTypeAdapter extends FineTypeAdapter { - - public EntityAIEatGrassTypeAdapter() { - register("IS_TALL_GRASS", FineMode.FINE); - register("grassEaterEntity", FineMode.FINE); - register("entityWorld", FineMode.FINE); - register("eatingGrassTimer", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIRestrictSun.class) - public static class EntityAIRestrictSunTypeAdapter extends FineTypeAdapter { - - public EntityAIRestrictSunTypeAdapter() { - register("entity", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFleeSun.class) - public static class EntityAIFleeSunTypeAdapter extends FineTypeAdapter { - - public EntityAIFleeSunTypeAdapter() { - register("creature", FineMode.FINE); - register("shelterX", FineMode.FINE); - register("shelterY", FineMode.FINE); - register("shelterZ", FineMode.FINE); - register("movementSpeed", FineMode.FINE); - register("world", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIAttackRangedBow.class) - public static class EntityAIAttackRangedBowTypeAdapter extends FineTypeAdapter { - - public EntityAIAttackRangedBowTypeAdapter() { - register("entity", FineMode.FINE); - register("moveSpeedAmp", FineMode.FINE); - register("attackCooldown", FineMode.FINE); - register("maxAttackDistance", FineMode.FINE); - register("attackTime", FineMode.FINE); - register("seeTime", FineMode.FINE); - register("strafingClockwise", FineMode.FINE); - register("strafingBackwards", FineMode.FINE); - register("strafingTime", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAISkeletonRiders.class) - public static class EntityAISkeletonRidersTypeAdapter extends FineTypeAdapter { - - public EntityAISkeletonRidersTypeAdapter() { - register("horse", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAITradePlayer.class) - public static class EntityAITradePlayerTypeAdapter extends FineTypeAdapter { - - public EntityAITradePlayerTypeAdapter() { - register("villager", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAILookAtTradePlayer.class) - public static class EntityAILookAtTradePlayerTypeAdapter extends FineTypeAdapter { - - public EntityAILookAtTradePlayerTypeAdapter() { - register("villager", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIMoveIndoors.class) - public static class EntityAIMoveIndoorsTypeAdapter extends FineTypeAdapter { - - public EntityAIMoveIndoorsTypeAdapter() { - register("entity", FineMode.FINE); - register("doorInfo", FineMode.FINE); - register("insidePosX", FineMode.FINE); - register("insidePosZ", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIRestrictOpenDoor.class) - public static class EntityAIRestrictOpenDoorTypeAdapter extends FineTypeAdapter { - - public EntityAIRestrictOpenDoorTypeAdapter() { - register("entity", FineMode.FINE); - register("frontDoor", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOpenDoor.class) - public static class EntityAIOpenDoorTypeAdapter extends FineTypeAdapter { - - public EntityAIOpenDoorTypeAdapter() { - register("closeDoor", FineMode.FINE); - register("closeDoorTemporisation", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIVillagerMate.class) - public static class EntityAIVillagerMateTypeAdapter extends FineTypeAdapter { - - public EntityAIVillagerMateTypeAdapter() { - register("villager", FineMode.FINE); - register("mate", FineMode.FINE); - register("world", FineMode.FINE); - register("matingTimeout", FineMode.FINE); - register("village", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIFollowGolem.class) - public static class EntityAIFollowGolemTypeAdapter extends FineTypeAdapter { - - public EntityAIFollowGolemTypeAdapter() { - register("villager", FineMode.FINE); - register("ironGolem", FineMode.FINE); - register("takeGolemRoseTick", FineMode.FINE); - register("tookGolemRose", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest2.class) - public static class EntityAIWatchClosest2TypeAdapter extends FineTypeAdapter { - - public EntityAIWatchClosest2TypeAdapter() { - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIVillagerInteract.class) - public static class EntityAIVillagerInteractTypeAdapter extends FineTypeAdapter { - - public EntityAIVillagerInteractTypeAdapter() { - register("interactionDelay", FineMode.FINE); - register("villager", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIHarvestFarmland.class) - public static class EntityAIHarvestFarmlandTypeAdapter extends FineTypeAdapter { - - public EntityAIHarvestFarmlandTypeAdapter() { - register("villager", FineMode.FINE); - register("hasFarmItem", FineMode.FINE); - register("wantsToReapStuff", FineMode.FINE); - register("currentTask", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIBeg.class) - public static class EntityAIBegTypeAdapter extends FineTypeAdapter { - - public EntityAIBegTypeAdapter() { - register("wolf", FineMode.FINE); - register("player", FineMode.FINE); - register("world", FineMode.FINE); - register("minPlayerDistance", FineMode.FINE); - register("timeoutCounter", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtByTarget.class) - public static class EntityAIOwnerHurtByTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIOwnerHurtByTargetTypeAdapter() { - register("tameable", FineMode.FINE); - register("attacker", FineMode.FINE); - register("timestamp", FineMode.FINE); - } - } - - @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtTarget.class) - public static class EntityAIOwnerHurtTargetTypeAdapter extends FineTypeAdapter { - - public EntityAIOwnerHurtTargetTypeAdapter() { - register("tameable", FineMode.FINE); - register("attacker", FineMode.FINE); - register("timestamp", FineMode.FINE); - } - } - -} +package com.minecrafttas.tasmod.savestates.typeadapters; + +import java.util.HashSet; +import java.util.Set; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineMultiTarget; +import com.minecrafttas.mctcommon.json.FineTarget; +import com.minecrafttas.mctcommon.json.FineTypeAdapter; + +import net.minecraft.item.Item; + +@FineMultiTarget +public class EntityAITypeAdapters { + + @FineTarget(net.minecraft.entity.ai.EntityAIBase.class) + public static class EntityAIBaseTypeAdapter extends FineTypeAdapter { + + public EntityAIBaseTypeAdapter() { + register("mutexBits", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsRestriction.class) + public static class EntityAIMoveTowardsRestrictionTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveTowardsRestrictionTypeAdapter() { + register("creature", FineMode.FINE); + register("movePosX", FineMode.FINE); + register("movePosY", FineMode.FINE); + register("movePosZ", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWander.class) + public static class EntityAIWanderTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderTypeAdapter() { + register("entity", FineMode.FINE); + register("x", FineMode.FINE); + register("y", FineMode.FINE); + register("z", FineMode.FINE); + register("speed", FineMode.FINE); + register("executionChance", FineMode.FINE); + register("mustUpdate", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWater.class) + public static class EntityAIWanderAvoidWaterTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderAvoidWaterTypeAdapter() { + register("probability", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest.class) + public static class EntityAIWatchClosestTypeAdapter extends FineTypeAdapter { + + public EntityAIWatchClosestTypeAdapter() { + register("entity", FineMode.FINE); + register("closestEntity", FineMode.FINE); + register("maxDistance", FineMode.FINE); + register("lookTime", FineMode.FINE); + register("chance", FineMode.FINE); + register("watchedClass", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookIdle.class) + public static class EntityAILookIdleTypeAdapter extends FineTypeAdapter { + + public EntityAILookIdleTypeAdapter() { + register("idleEntity", FineMode.FINE); + register("lookX", FineMode.FINE); + register("lookZ", FineMode.FINE); + register("idleTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITarget.class) + public static class EntityAITargetTypeAdapter extends FineTypeAdapter { + + public EntityAITargetTypeAdapter() { + register("taskOwner", FineMode.FINE); + register("shouldCheckSight", FineMode.FINE); + register("nearbyOnly", FineMode.FINE); + register("targetSearchStatus", FineMode.FINE); + register("targetSearchDelay", FineMode.FINE); + register("targetUnseenTicks", FineMode.FINE); + register("target", FineMode.FINE); + register("unseenMemoryTicks", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIHurtByTarget.class) + public static class EntityAIHurtByTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIHurtByTargetTypeAdapter() { + register("entityCallsForHelp", FineMode.FINE); + register("revengeTimerOld", FineMode.FINE); + register("excludedReinforcementTypes", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAINearestAttackableTarget.class) + public static class EntityAINearestAttackableTargetTypeAdapter extends FineTypeAdapter { + + public EntityAINearestAttackableTargetTypeAdapter() { + register("targetClass", FineMode.FINE); + register("targetChance", FineMode.FINE); + register("sorter", FineMode.FINE); + register("targetEntitySelector", FineMode.FINE); + register("targetEntity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISit.class) + public static class EntityAISitTypeAdapter extends FineTypeAdapter { + + public EntityAISitTypeAdapter() { + register("tameable", FineMode.FINE); + register("isSitting", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITempt.class) + public static class EntityAITemptTypeAdapter extends FineTypeAdapter { + + public EntityAITemptTypeAdapter() { + register("temptedEntity", FineMode.FINE); + register("speed", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + register("pitch", FineMode.FINE); + register("yaw", FineMode.FINE); + register("temptingPlayer", FineMode.FINE); + register("delayTemptCounter", FineMode.FINE); + register("isRunning", FineMode.FINE); + register("temptItem", (obj, fgson) -> { + JsonArray out = new JsonArray(); + @SuppressWarnings("unchecked") + Set in = (Set) obj; + for (Item item : in) { + out.add(fgson.serialize(item, Item.class)); + } + return out; + }, (elem, fgson) -> { + Set out = new HashSet<>(); + JsonArray in = elem.getAsJsonArray(); + for (JsonElement element : in) { + out.add((Item) fgson.deserialize(element, Item.class)); + } + return out; + }); + register("scaredByPlayerMovement", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISwimming.class) + public static class EntityAISwimmingTypeAdapter extends FineTypeAdapter { + + public EntityAISwimmingTypeAdapter() { + register("entity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwner.class) + public static class EntityAIFollowOwnerTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowOwnerTypeAdapter() { + register("tameable", FineMode.FINE); + register("owner", FineMode.FINE); + register("world", FineMode.FINE); + register("followSpeed", FineMode.FINE); + register("petPathfinder", FineMode.FINE); + register("timeToRecalcPath", FineMode.FINE); + register("maxDist", FineMode.FINE); + register("minDist", FineMode.FINE); + register("oldWaterCost", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveToBlock.class) + public static class EntityAIMoveToBlockTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveToBlockTypeAdapter() { + register("creature", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("runDelay", FineMode.FINE); + register("timeoutCounter", FineMode.FINE); + register("maxStayTicks", FineMode.FINE); + register("destinationBlock", FineMode.FINE); + register("isAboveDestination", FineMode.FINE); + register("searchLength", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOcelotSit.class) + public static class EntityAIOcelotSitTypeAdapter extends FineTypeAdapter { + + public EntityAIOcelotSitTypeAdapter() { + register("ocelot", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILeapAtTarget.class) + public static class EntityAILeapAtTargetTypeAdapter extends FineTypeAdapter { + + public EntityAILeapAtTargetTypeAdapter() { + register("leaper", FineMode.FINE); + register("leapTarget", FineMode.FINE); + register("leapMotionY", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOcelotAttack.class) + public static class EntityAIOcelotAttackTypeAdapter extends FineTypeAdapter { + + public EntityAIOcelotAttackTypeAdapter() { + register("world", FineMode.FINE); + register("entity", FineMode.FINE); + register("target", FineMode.FINE); + register("attackCountdown", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMate.class) + public static class EntityAIMateTypeAdapter extends FineTypeAdapter { + + public EntityAIMateTypeAdapter() { + register("animal", FineMode.FINE); + register("mateClass", FineMode.FINE); + register("world", FineMode.FINE); + register("targetMate", FineMode.FINE); + register("spawnBabyDelay", FineMode.FINE); + register("moveSpeed", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITargetNonTamed.class) + public static class EntityAITargetNonTamedTypeAdapter extends FineTypeAdapter { + + public EntityAITargetNonTamedTypeAdapter() { + register("tameable", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAvoidEntity.class) + public static class EntityAIAvoidEntityTypeAdapter extends FineTypeAdapter { + + public EntityAIAvoidEntityTypeAdapter() { + register("canBeSeenSelector", FineMode.FINE); + register("entity", FineMode.FINE); + register("farSpeed", FineMode.FINE); + register("nearSpeed", FineMode.FINE); + register("closestLivingEntity", FineMode.FINE); + register("avoidDistance", FineMode.FINE); + register("path", FineMode.FINE); + register("navigation", FineMode.FINE); + register("classToAvoid", FineMode.FINE); + register("avoidTargetSelector", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAICreeperSwell.class) + public static class EntityAICreeperSwellTypeAdapter extends FineTypeAdapter { + + public EntityAICreeperSwellTypeAdapter() { + register("swellingCreeper", FineMode.FINE); + register("creeperAttackTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackMelee.class) + public static class EntityAIAttackMeleeTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackMeleeTypeAdapter() { + register("world", FineMode.FINE); + register("attacker", FineMode.FINE); + register("attackTick", FineMode.FINE); + register("speedTowardsTarget", FineMode.FINE); + register("longMemory", FineMode.FINE); + register("path", FineMode.FINE); + register("delayCounter", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + register("attackInterval", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIPanic.class) + public static class EntityAIPanicTypeAdapter extends FineTypeAdapter { + + public EntityAIPanicTypeAdapter() { + register("creature", FineMode.FINE); + register("speed", FineMode.FINE); + register("randPosX", FineMode.FINE); + register("randPosY", FineMode.FINE); + register("randPosZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowParent.class) + public static class EntityAIFollowParentTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowParentTypeAdapter() { + register("childAnimal", FineMode.FINE); + register("parentAnimal", FineMode.FINE); + register("moveSpeed", FineMode.FINE); + register("delayCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRunAroundLikeCrazy.class) + public static class EntityAIRunAroundLikeCrazyTypeAdapter extends FineTypeAdapter { + + public EntityAIRunAroundLikeCrazyTypeAdapter() { + register("horseHost", FineMode.FINE); + register("speed", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearestPlayer.class) + public static class EntityAIFindEntityNearestPlayerTypeAdapter extends FineTypeAdapter { + + public EntityAIFindEntityNearestPlayerTypeAdapter() { + register("LOGGER", FineMode.EXCLUDED); + register("entityLiving", FineMode.FINE); + register("predicate", FineMode.FINE); + register("sorter", FineMode.FINE); + register("entityTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIZombieAttack.class) + public static class EntityAIZombieAttackTypeAdapter extends FineTypeAdapter { + + public EntityAIZombieAttackTypeAdapter() { + register("zombie", FineMode.FINE); + register("raiseArmTicks", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveThroughVillage.class) + public static class EntityAIMoveThroughVillageTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveThroughVillageTypeAdapter() { + register("entity", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("path", FineMode.FINE); + register("doorInfo", FineMode.FINE); + register("isNocturnal", FineMode.FINE); + register("doorList", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIDoorInteract.class) + public static class EntityAIDoorInteractTypeAdapter extends FineTypeAdapter { + + public EntityAIDoorInteractTypeAdapter() { + register("entity", FineMode.FINE); + register("doorPosition", FineMode.FINE); + register("doorBlock", FineMode.FINE); + register("hasStoppedDoorInteraction", FineMode.FINE); + register("entityPositionX", FineMode.FINE); + register("entityPositionZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIBreakDoor.class) + public static class EntityAIBreakDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIBreakDoorTypeAdapter() { + register("breakingTime", FineMode.FINE); + register("previousBreakProgress", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveTowardsTarget.class) + public static class EntityAIMoveTowardsTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveTowardsTargetTypeAdapter() { + register("creature", FineMode.FINE); + register("targetEntity", FineMode.FINE); + register("movePosX", FineMode.FINE); + register("movePosY", FineMode.FINE); + register("movePosZ", FineMode.FINE); + register("speed", FineMode.FINE); + register("maxTargetDistance", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookAtVillager.class) + public static class EntityAILookAtVillagerTypeAdapter extends FineTypeAdapter { + + public EntityAILookAtVillagerTypeAdapter() { + register("ironGolem", FineMode.FINE); + register("villager", FineMode.FINE); + register("lookTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIDefendVillage.class) + public static class EntityAIDefendVillageTypeAdapter extends FineTypeAdapter { + + public EntityAIDefendVillageTypeAdapter() { + register("irongolem", FineMode.FINE); + register("villageAgressorTarget", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILlamaFollowCaravan.class) + public static class EntityAILlamaFollowCaravanTypeAdapter extends FineTypeAdapter { + + public EntityAILlamaFollowCaravanTypeAdapter() { + register("llama", FineMode.FINE); + register("speedModifier", FineMode.FINE); + register("distCheckCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackRanged.class) + public static class EntityAIAttackRangedTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackRangedTypeAdapter() { + register("entityHost", FineMode.FINE); + register("rangedAttackEntityHost", FineMode.FINE); + register("attackTarget", FineMode.FINE); + register("rangedAttackTime", FineMode.FINE); + register("entityMoveSpeed", FineMode.FINE); + register("seeTime", FineMode.FINE); + register("attackIntervalMin", FineMode.FINE); + register("maxRangedAttackTime", FineMode.FINE); + register("attackRadius", FineMode.FINE); + register("maxAttackDistance", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFindEntityNearest.class) + public static class EntityAIFindEntityNearestTypeAdapter extends FineTypeAdapter { + + public EntityAIFindEntityNearestTypeAdapter() { + register("LOGGER", FineMode.EXCLUDED); + register("mob", FineMode.FINE); + register("predicate", FineMode.FINE); + register("sorter", FineMode.FINE); + register("target", FineMode.FINE); + register("classToCheck", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowOwnerFlying.class) + public static class EntityAIFollowOwnerFlyingTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowOwnerFlyingTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWanderAvoidWaterFlying.class) + public static class EntityAIWanderAvoidWaterFlyingTypeAdapter extends FineTypeAdapter { + + public EntityAIWanderAvoidWaterFlyingTypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILandOnOwnersShoulder.class) + public static class EntityAILandOnOwnersShoulderTypeAdapter extends FineTypeAdapter { + + public EntityAILandOnOwnersShoulderTypeAdapter() { + register("entity", FineMode.FINE); + register("owner", FineMode.FINE); + register("isSittingOnShoulder", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollow.class) + public static class EntityAIFollowTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowTypeAdapter() { + register("entity", FineMode.FINE); + register("followPredicate", FineMode.FINE); + register("followingEntity", FineMode.FINE); + register("speedModifier", FineMode.FINE); + register("navigation", FineMode.FINE); + register("timeToRecalcPath", FineMode.FINE); + register("stopDistance", FineMode.FINE); + register("oldWaterCost", FineMode.FINE); + register("areaSize", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIEatGrass.class) + public static class EntityAIEatGrassTypeAdapter extends FineTypeAdapter { + + public EntityAIEatGrassTypeAdapter() { + register("IS_TALL_GRASS", FineMode.FINE); + register("grassEaterEntity", FineMode.FINE); + register("entityWorld", FineMode.FINE); + register("eatingGrassTimer", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRestrictSun.class) + public static class EntityAIRestrictSunTypeAdapter extends FineTypeAdapter { + + public EntityAIRestrictSunTypeAdapter() { + register("entity", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFleeSun.class) + public static class EntityAIFleeSunTypeAdapter extends FineTypeAdapter { + + public EntityAIFleeSunTypeAdapter() { + register("creature", FineMode.FINE); + register("shelterX", FineMode.FINE); + register("shelterY", FineMode.FINE); + register("shelterZ", FineMode.FINE); + register("movementSpeed", FineMode.FINE); + register("world", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIAttackRangedBow.class) + public static class EntityAIAttackRangedBowTypeAdapter extends FineTypeAdapter { + + public EntityAIAttackRangedBowTypeAdapter() { + register("entity", FineMode.FINE); + register("moveSpeedAmp", FineMode.FINE); + register("attackCooldown", FineMode.FINE); + register("maxAttackDistance", FineMode.FINE); + register("attackTime", FineMode.FINE); + register("seeTime", FineMode.FINE); + register("strafingClockwise", FineMode.FINE); + register("strafingBackwards", FineMode.FINE); + register("strafingTime", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAISkeletonRiders.class) + public static class EntityAISkeletonRidersTypeAdapter extends FineTypeAdapter { + + public EntityAISkeletonRidersTypeAdapter() { + register("horse", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAITradePlayer.class) + public static class EntityAITradePlayerTypeAdapter extends FineTypeAdapter { + + public EntityAITradePlayerTypeAdapter() { + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAILookAtTradePlayer.class) + public static class EntityAILookAtTradePlayerTypeAdapter extends FineTypeAdapter { + + public EntityAILookAtTradePlayerTypeAdapter() { + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIMoveIndoors.class) + public static class EntityAIMoveIndoorsTypeAdapter extends FineTypeAdapter { + + public EntityAIMoveIndoorsTypeAdapter() { + register("entity", FineMode.FINE); + register("doorInfo", FineMode.FINE); + register("insidePosX", FineMode.FINE); + register("insidePosZ", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIRestrictOpenDoor.class) + public static class EntityAIRestrictOpenDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIRestrictOpenDoorTypeAdapter() { + register("entity", FineMode.FINE); + register("frontDoor", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOpenDoor.class) + public static class EntityAIOpenDoorTypeAdapter extends FineTypeAdapter { + + public EntityAIOpenDoorTypeAdapter() { + register("closeDoor", FineMode.FINE); + register("closeDoorTemporisation", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIVillagerMate.class) + public static class EntityAIVillagerMateTypeAdapter extends FineTypeAdapter { + + public EntityAIVillagerMateTypeAdapter() { + register("villager", FineMode.FINE); + register("mate", FineMode.FINE); + register("world", FineMode.FINE); + register("matingTimeout", FineMode.FINE); + register("village", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIFollowGolem.class) + public static class EntityAIFollowGolemTypeAdapter extends FineTypeAdapter { + + public EntityAIFollowGolemTypeAdapter() { + register("villager", FineMode.FINE); + register("ironGolem", FineMode.FINE); + register("takeGolemRoseTick", FineMode.FINE); + register("tookGolemRose", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIWatchClosest2.class) + public static class EntityAIWatchClosest2TypeAdapter extends FineTypeAdapter { + + public EntityAIWatchClosest2TypeAdapter() { + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIVillagerInteract.class) + public static class EntityAIVillagerInteractTypeAdapter extends FineTypeAdapter { + + public EntityAIVillagerInteractTypeAdapter() { + register("interactionDelay", FineMode.FINE); + register("villager", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIHarvestFarmland.class) + public static class EntityAIHarvestFarmlandTypeAdapter extends FineTypeAdapter { + + public EntityAIHarvestFarmlandTypeAdapter() { + register("villager", FineMode.FINE); + register("hasFarmItem", FineMode.FINE); + register("wantsToReapStuff", FineMode.FINE); + register("currentTask", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIBeg.class) + public static class EntityAIBegTypeAdapter extends FineTypeAdapter { + + public EntityAIBegTypeAdapter() { + register("wolf", FineMode.FINE); + register("player", FineMode.FINE); + register("world", FineMode.FINE); + register("minPlayerDistance", FineMode.FINE); + register("timeoutCounter", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtByTarget.class) + public static class EntityAIOwnerHurtByTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIOwnerHurtByTargetTypeAdapter() { + register("tameable", FineMode.FINE); + register("attacker", FineMode.FINE); + register("timestamp", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.entity.ai.EntityAIOwnerHurtTarget.class) + public static class EntityAIOwnerHurtTargetTypeAdapter extends FineTypeAdapter { + + public EntityAIOwnerHurtTargetTypeAdapter() { + register("tameable", FineMode.FINE); + register("attacker", FineMode.FINE); + register("timestamp", FineMode.FINE); + } + } + +} diff --git a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java deleted file mode 100644 index 1a12c2f9..00000000 --- a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package mctcommon.json; - -import static org.junit.jupiter.api.Assertions.assertIterableEquals; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.junit.jupiter.api.Test; - -import com.minecrafttas.mctcommon.json.FineTypeAdapterGenerator; - -class FineTypeAdapterGeneratorTest { - - private class TestClass extends TestSuperClass { - private int index = 7; - private String lol = "Laughing out loud"; - private TestSubClass subClass = new TestSubClass(); - private boolean excluded = false; - - @Override - public boolean equals(Object obj) { - if (obj instanceof TestClass) { - TestClass other = (TestClass) obj; - return index == other.index && lol.equals(other.lol) && subClass.equals(other.subClass) && excluded == other.excluded && bot == other.bot && evil.equals(evil); - } - return super.equals(obj); - } - } - - private class TestSubClass { - private boolean isWater = true; - - @Override - public boolean equals(Object obj) { - if (obj instanceof TestSubClass) { - TestSubClass other = (TestSubClass) obj; - return isWater == other.isWater; - } - return super.equals(obj); - } - } - - private static class TestSuperClass { - protected long bot = 8999; - protected String evil = "Squids are evil!"; - } - - @Test - void testGenerateMulti() { - FineTypeAdapterGenerator generator = new FineTypeAdapterGenerator("GeneratedTypeAdapterTest", "typeadapter"); - generator.addClass(TestClass.class); - List actual = generator.generateMulti(); - List expected = Arrays.asList(String.format("package typeadapter;\n" - + "\n" - + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" - + "import com.minecrafttas.mctcommon.json.FineMultiTarget;\n" - + "import com.minecrafttas.mctcommon.json.FineTarget;\n" - + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" - + "\n" - + "import mctcommon.json.FineTypeAdapterGeneratorTest$TestSuperClass;\n" - + "import mctcommon.json.FineTypeAdapterGeneratorTest$TestClass;\n" - + "\n" - + "@FineMultiTarget\n" - + "public class GeneratedTypeAdapterTest {\n" - + "\n" - + " @FineTarget(TestSuperClass.class)\n" - + " public static class TestSuperClassTypeAdapter extends FineTypeAdapter {\n" - + " \n" - + " public TestSuperClassTypeAdapter() {\n" - + " register(\"bot\", FineMode.FINE);\n" - + " register(\"evil\", FineMode.FINE);\n" - + " }\n" - + " }\n" - + " \n" - + " @FineTarget(TestClass.class)\n" - + " public static class TestClassTypeAdapter extends FineTypeAdapter {\n" - + " \n" - + " public TestClassTypeAdapter() {\n" - + " register(\"index\", FineMode.FINE);\n" - + " register(\"lol\", FineMode.FINE);\n" - + " register(\"subClass\", FineMode.FINE);\n" - + " register(\"excluded\", FineMode.FINE);\n" - + " }\n" - + " }\n" - + " \n" - + "}").split("\n")); - assertIterableEquals(expected, actual); - } - - @Test - void testGenerateSingle() { - FineTypeAdapterGenerator generator = new FineTypeAdapterGenerator("GeneratedTypeAdapterTest", "typeadapter"); - generator.addClass(TestSubClass.class); - List actual = generator.generate(); - List expected = new ArrayList<>(Arrays.asList(String.format("package typeadapter;\n" - + "\n" - + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" - + "import com.minecrafttas.mctcommon.json.FineMultiTarget;\n" - + "import com.minecrafttas.mctcommon.json.FineTarget;\n" - + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" - + "\n" - + "import mctcommon.json.FineTypeAdapterGeneratorTest$TestSubClass;\n" - + "\n" - + "@FineTarget(TestSubClass.class)\n" - + "public class TestSubClassTypeAdapter extends FineTypeAdapter {\n" - + "\n" - + " public TestSubClassTypeAdapter() {\n" - + " register(\"isWater\", FineMode.FINE);\n" - + " }\n" - + "}\n" - + "\n").split("\n"))); - expected.add(""); - assertIterableEquals(expected, actual); - } -} From 70d61851ba50c393bc39c4c14f13aa99a5a9050d Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 21 Sep 2026 20:11:47 +0200 Subject: [PATCH 24/26] [Savestates] More type adapters, more generators --- .../json/FineTypeAdapterGenerator.java | 44 ++++--- .../PathNavigateTypeAdapters.java | 74 ++++++++++++ .../util/TypeAdapterGenerator.java | 26 ++++ .../json/FineTypeAdapterGeneratorTest.java | 112 ++++++++++++++++++ 4 files changed, 237 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java create mode 100644 src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/TypeAdapterGenerator.java create mode 100644 src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java index f8e7f429..d4d5157a 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapterGenerator.java @@ -3,10 +3,9 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; +import java.util.Set; public class FineTypeAdapterGenerator { @@ -15,7 +14,7 @@ public class FineTypeAdapterGenerator { protected final String packagge; protected final List importLines = new ArrayList<>(); - protected final Map, List> classLines = new LinkedHashMap<>(); + protected final Set> classList = new LinkedHashSet<>(); public FineTypeAdapterGenerator(String className, String packagge) { this.className = className; @@ -36,9 +35,9 @@ public List generate() { out.add(String.format("package %s;", packagge)); out.add(""); out.addAll(importLines); - out.add(""); - Collection> classLines = this.classLines.values(); - classLines.forEach(e -> e.forEach(e1 -> out.add(e1))); + for (Class clazz : classList) { + out.addAll(buildClass(clazz, false)); + } return out; } @@ -47,12 +46,13 @@ public List generateMulti() { out.add(String.format("package %s;", packagge)); out.add(""); out.addAll(importLines); - out.add(""); out.add("@FineMultiTarget"); out.add(String.format("public class %s {", className)); out.add(""); - Collection> classLines = this.classLines.values(); - classLines.forEach(e -> e.forEach(e1 -> out.add("\t" + e1))); + for (Class clazz : classList) { + List classLines = buildClass(clazz, true); + classLines.forEach(e1 -> out.add("\t" + e1)); + } out.add("}"); return out; } @@ -69,7 +69,7 @@ public void addClass(T object) { } public void addClass(Class clazz) { - if (classLines.containsKey(clazz)) + if (classList.contains(clazz)) return; // if (clazz.getName().contains("$")) { @@ -80,23 +80,29 @@ public void addClass(Class clazz) { if (superclazz != Object.class) addClass(superclazz); + classList.add(clazz); + } + + private List buildClass(Class clazz, boolean isStatic) { + List out = new ArrayList<>(); + String clazzName = clazz.getSimpleName(); List fields = FineTypeAdapter.getFieldList(clazz); -// importLines.add(String.format("import %s;", clazz.getName())); - classLines.put(clazz, splitNewLine(String.format("" + out.addAll(splitNewLine(String.format("" + "@FineTarget(%s.class)\n" - + "public static class %sTypeAdapter extends FineTypeAdapter {\n" + + "public %sclass %sTypeAdapter extends FineTypeAdapter {\n" + "\n" - + "\tpublic %sTypeAdapter() {", clazz.getName().replace("$", "."), clazzName, clazzName))); + + "\tpublic %sTypeAdapter() {", clazz.getName().replace("$", "."), isStatic ? "static " : "", clazzName, clazzName))); for (Field field : fields) { - classLines.get(clazz).add(String.format("\t\tregister(\"%s\", FineMode.FINE);", field.getName())); + out.add(String.format("\t\tregister(\"%s\", FineMode.FINE);", field.getName())); } - classLines.get(clazz).add("\t}"); - classLines.get(clazz).add("}"); - classLines.get(clazz).add(""); + out.add("\t}"); + out.add("}"); + out.add(""); + return out; } protected List splitNewLine(String text) { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java new file mode 100644 index 00000000..2429cad6 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java @@ -0,0 +1,74 @@ +package com.minecrafttas.tasmod.savestates.typeadapters; + +import com.google.gson.JsonElement; +import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineGson; +import com.minecrafttas.mctcommon.json.FineMultiTarget; +import com.minecrafttas.mctcommon.json.FineTarget; +import com.minecrafttas.mctcommon.json.FineTypeAdapter; + +@FineMultiTarget +public class PathNavigateTypeAdapters { + + @FineTarget(net.minecraft.pathfinding.PathNavigate.class) + public static class PathNavigateTypeAdapter extends FineTypeAdapter { + + public PathNavigateTypeAdapter() { + register("entity", FineMode.FINE); + register("world", FineMode.FINE); + register("currentPath", FineMode.FINE); + register("speed", FineMode.FINE); + register("pathSearchRange", FineMode.EXCLUDED); + register("totalTicks", FineMode.FINE); + register("ticksAtLastPos", FineMode.FINE); + register("lastPosCheck", FineMode.FINE); + register("timeoutCachedNode", FineMode.FINE); + register("timeoutTimer", FineMode.FINE); + register("lastTimeoutCheck", FineMode.FINE); + register("timeoutLimit", FineMode.FINE); + register("maxDistanceToWaypoint", FineMode.FINE); + register("tryUpdatePath", FineMode.FINE); + register("lastTimeUpdated", FineMode.FINE); + register("nodeProcessor", FineMode.EXCLUDED); + register("targetPos", FineMode.FINE); + register("pathFinder", FineMode.EXCLUDED); + } + } + + @FineTarget(net.minecraft.pathfinding.PathNavigateGround.class) + public static class PathNavigateGroundTypeAdapter extends FineTypeAdapter { + + public PathNavigateGroundTypeAdapter() { + register("shouldAvoidSun", FineMode.FINE); + } + + @Override + public Object deserialize(JsonElement element, Class clazz, FineGson fineJson) { + Object obj = constructNew(clazz); + return deserialize(element, clazz, fineJson, obj); + } + } + + @FineTarget(net.minecraft.pathfinding.PathNavigateClimber.class) + public static class PathNavigateClimberTypeAdapter extends FineTypeAdapter { + + public PathNavigateClimberTypeAdapter() { + register("targetPosition", FineMode.FINE); + } + } + + @FineTarget(net.minecraft.pathfinding.PathNavigateFlying.class) + public static class PathNavigateFlyingTypeAdapter extends FineTypeAdapter { + + public PathNavigateFlyingTypeAdapter() { + } + } + + @FineTarget(net.minecraft.pathfinding.PathNavigateSwimmer.class) + public static class PathNavigateSwimmerTypeAdapter extends FineTypeAdapter { + + public PathNavigateSwimmerTypeAdapter() { + } + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/TypeAdapterGenerator.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/TypeAdapterGenerator.java new file mode 100644 index 00000000..68a36709 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/util/TypeAdapterGenerator.java @@ -0,0 +1,26 @@ +package com.minecrafttas.tasmod.savestates.typeadapters.util; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +import com.minecrafttas.mctcommon.json.FineTypeAdapterGenerator; + +import net.minecraft.pathfinding.PathNavigateClimber; +import net.minecraft.pathfinding.PathNavigateFlying; +import net.minecraft.pathfinding.PathNavigateGround; +import net.minecraft.pathfinding.PathNavigateSwimmer; + +public class TypeAdapterGenerator { + + public static void main(String[] args) { + FineTypeAdapterGenerator fgenerator = new FineTypeAdapterGenerator("PathNavigateTypeAdapters", "com.minecrafttas.tasmod.savestates.typeadapters"); + fgenerator.addClass(PathNavigateGround.class, PathNavigateClimber.class, PathNavigateFlying.class, PathNavigateSwimmer.class); + try { + Files.write(Paths.get("src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java"), fgenerator.generateMulti(), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java new file mode 100644 index 00000000..89b25212 --- /dev/null +++ b/src/test/java/mctcommon/json/FineTypeAdapterGeneratorTest.java @@ -0,0 +1,112 @@ +package mctcommon.json; + +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.minecrafttas.mctcommon.json.FineTypeAdapterGenerator; + +class FineTypeAdapterGeneratorTest { + + private class TestClass extends TestSuperClass { + private int index = 7; + private String lol = "Laughing out loud"; + private TestSubClass subClass = new TestSubClass(); + private boolean excluded = false; + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestClass) { + TestClass other = (TestClass) obj; + return index == other.index && lol.equals(other.lol) && subClass.equals(other.subClass) && excluded == other.excluded && bot == other.bot && evil.equals(evil); + } + return super.equals(obj); + } + } + + private class TestSubClass { + private boolean isWater = true; + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestSubClass) { + TestSubClass other = (TestSubClass) obj; + return isWater == other.isWater; + } + return super.equals(obj); + } + } + + private static class TestSuperClass { + protected long bot = 8999; + protected String evil = "Squids are evil!"; + } + + @Test + void testGenerateMulti() { + FineTypeAdapterGenerator generator = new FineTypeAdapterGenerator("GeneratedTypeAdapterTest", "typeadapter"); + generator.addClass(TestClass.class); + List actual = generator.generateMulti(); + List expected = Arrays.asList(String.format("package typeadapter;\n" + + "\n" + + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" + + "import com.minecrafttas.mctcommon.json.FineMultiTarget;\n" + + "import com.minecrafttas.mctcommon.json.FineTarget;\n" + + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" + + "\n" + + "@FineMultiTarget\n" + + "public class GeneratedTypeAdapterTest {\n" + + "\n" + + " @FineTarget(mctcommon.json.FineTypeAdapterGeneratorTest.TestSuperClass.class)\n" + + " public static class TestSuperClassTypeAdapter extends FineTypeAdapter {\n" + + " \n" + + " public TestSuperClassTypeAdapter() {\n" + + " register(\"bot\", FineMode.FINE);\n" + + " register(\"evil\", FineMode.FINE);\n" + + " }\n" + + " }\n" + + " \n" + + " @FineTarget(mctcommon.json.FineTypeAdapterGeneratorTest.TestClass.class)\n" + + " public static class TestClassTypeAdapter extends FineTypeAdapter {\n" + + " \n" + + " public TestClassTypeAdapter() {\n" + + " register(\"index\", FineMode.FINE);\n" + + " register(\"lol\", FineMode.FINE);\n" + + " register(\"subClass\", FineMode.FINE);\n" + + " register(\"excluded\", FineMode.FINE);\n" + + " }\n" + + " }\n" + + " \n" + + "}").split("\n")); + assertIterableEquals(expected, actual); + } + + @Test + void testGenerateSingle() { + FineTypeAdapterGenerator generator = new FineTypeAdapterGenerator("GeneratedTypeAdapterTest", "typeadapter"); + generator.addClass(TestSubClass.class); + List actual = generator.generate(); + System.out.println(String.join("\n", actual)); + List expected = new ArrayList<>(Arrays.asList(String.format("package typeadapter;\n" + + "\n" + + "import com.minecrafttas.mctcommon.json.FineField.FineMode;\n" + + "import com.minecrafttas.mctcommon.json.FineMultiTarget;\n" + + "import com.minecrafttas.mctcommon.json.FineTarget;\n" + + "import com.minecrafttas.mctcommon.json.FineTypeAdapter;\n" + + "\n" + + "@FineTarget(mctcommon.json.FineTypeAdapterGeneratorTest.TestSubClass.class)\n" + + "public class TestSubClassTypeAdapter extends FineTypeAdapter {\n" + + "\n" + + " public TestSubClassTypeAdapter() {\n" + + " register(\"isWater\", FineMode.FINE);\n" + + " }\n" + + "}\n" + + "\n").split("\n"))); + expected.add(""); + assertIterableEquals(expected, actual); + } +} From 1b133f6e9c9ec73fac4664d788fd327b14053034 Mon Sep 17 00:00:00 2001 From: Scribble Date: Sun, 27 Sep 2026 16:39:39 +0200 Subject: [PATCH 25/26] [Savestates] Fix AI task deserialisation --- .../storage/builtin/EntityAiTaskStorage.java | 70 +++---------------- .../typeadapters/EntityAITypeAdapters.java | 2 +- .../typeadapters/ItemTypeAdapter.java | 5 +- .../PathNavigateTypeAdapters.java | 14 +--- 4 files changed, 16 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java index 9dbde3bc..1662ddb7 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityAiTaskStorage.java @@ -1,10 +1,7 @@ package com.minecrafttas.tasmod.savestates.storage.builtin; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; +import java.lang.reflect.Modifier; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -131,18 +128,21 @@ private JsonObject serialiseAITasks(EntityAITasks tasks) { return out; } + @SuppressWarnings("unchecked") private JsonArray serialiseAIEntries(Set taskEntries) { JsonArray serialisedEntries = new JsonArray(); for (EntityAITasks.EntityAITaskEntry entry : taskEntries) { JsonObject jsonAiTaskEntry = new JsonObject(); Class clazz = entry.action.getClass(); + if (clazz.isAnonymousClass()) + clazz = (Class) clazz.getSuperclass(); jsonAiTaskEntry.addProperty("priority", entry.priority); jsonAiTaskEntry.addProperty("using", entry.using); jsonAiTaskEntry.addProperty("class", clazz.getName()); try { System.out.println(clazz.getName()); - jsonAiTaskEntry.add("action", serializeAction(entry.action, clazz)); + jsonAiTaskEntry.add("action", fgson.serialize(entry.action)); } catch (Exception e) { throw new SavestateException(e, "Could not serialise AI Task %s", entry.action.getClass().getName()); } @@ -152,19 +152,6 @@ private JsonArray serialiseAIEntries(Set taskEntries) { return serialisedEntries; } - private JsonElement serializeAction(EntityAIBase action, Class clazz) { -// @SuppressWarnings("unchecked") -// Class superclazz = (Class) clazz.getSuperclass(); -// -// JsonObject out = new JsonObject(); -// -// if (superclazz != EntityAIBase.class) -// out = serializeAction(action, superclazz); -// -// return JsonUtils.mergeJsonObjects(out, gsonInstance.toJsonTree(action, clazz).getAsJsonObject()); - return fgson.serialize(action); - } - @Override public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { for (Entry elements : loadedData.entrySet()) { @@ -199,7 +186,7 @@ private Set deserialiseAIEntries(Set taskE JsonObject jsonEntry = jsonEntryElement.getAsJsonObject(); // Deserialise the type of the AI action - System.out.println(jsonEntry.get("class").getAsString()); +// System.out.println(jsonEntry.get("class").getAsString()); Class clazz; try { clazz = Class.forName(jsonEntry.get("class").getAsString(), false, getClass().getClassLoader()).asSubclass(EntityAIBase.class); @@ -217,7 +204,7 @@ private Set deserialiseAIEntries(Set taskE } createNew = false; - vanillaEntry.action = deserialiseAction(vanillaAction, jsonEntry.get("action")); + vanillaEntry.action = (EntityAIBase) fgson.deserialize(jsonEntry.get("action"), vanillaAction.getClass(), vanillaAction); vanillaEntry.using = using; out.add(vanillaEntry); break; @@ -228,9 +215,11 @@ private Set deserialiseAIEntries(Set taskE } int priority = jsonEntry.get("priority").getAsInt(); + if (Modifier.isAbstract(clazz.getModifiers())) + continue; EntityAIBase action = JsonUtils.constructNew(clazz); try { - action = deserialiseAction(action, jsonEntry.get("action")); + action = (EntityAIBase) fgson.deserialize(jsonEntry.get("action"), action.getClass(), action); } catch (Exception e) { e.printStackTrace(); continue; @@ -241,43 +230,4 @@ private Set deserialiseAIEntries(Set taskE } return out; } - - private EntityAIBase deserialiseAction(EntityAIBase action, JsonElement json) { - JsonObject jsonObject = json.getAsJsonObject(); - List fields = getFieldList(action.getClass()); - - for (Field field : fields) { - field.setAccessible(true); - String fieldname = field.getName(); - Class fieldClass = field.getType(); - - JsonElement value = jsonObject.get(fieldname); - - if (value == null) - continue; - - Object deserialised = gsonInstance.fromJson(value, fieldClass); - try { - field.set(action, deserialised); - } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - } - - return action; - } - - private List getFieldList(Class clazz) { - @SuppressWarnings("unchecked") - Class superclazz = (Class) clazz.getSuperclass(); - List out = new ArrayList<>(); - - if (superclazz != EntityAIBase.class) { - out.addAll(getFieldList(superclazz)); - } - - out.addAll(Arrays.asList(clazz.getDeclaredFields())); - - return out; - } } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java index aeccb5f6..746980c7 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java @@ -433,7 +433,7 @@ public static class EntityAIAttackRangedTypeAdapter extends FineTypeAdapter { public EntityAIAttackRangedTypeAdapter() { register("entityHost", FineMode.FINE); - register("rangedAttackEntityHost", FineMode.FINE); + register("rangedAttackEntityHost", FineMode.EXCLUDED); register("attackTarget", FineMode.FINE); register("rangedAttackTime", FineMode.FINE); register("entityMoveSpeed", FineMode.FINE); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java index b07d151f..729ee503 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/ItemTypeAdapter.java @@ -16,10 +16,9 @@ public JsonElement serialize(Object obj, FineGson fineJson, Class clazz) thro } @Override - public Object deserialize(JsonElement element, Class clazz, FineGson fineJson) { + public Object deserialize(JsonElement element, Class clazz, FineGson fineJson, Object existing) { JsonPrimitive value = element.getAsJsonPrimitive(); - Item.getItemById(value.getAsInt()); - return super.deserialize(element, clazz, fineJson); + return Item.getItemById(value.getAsInt()); } } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java index 2429cad6..c70c518b 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/PathNavigateTypeAdapters.java @@ -1,8 +1,6 @@ package com.minecrafttas.tasmod.savestates.typeadapters; -import com.google.gson.JsonElement; import com.minecrafttas.mctcommon.json.FineField.FineMode; -import com.minecrafttas.mctcommon.json.FineGson; import com.minecrafttas.mctcommon.json.FineMultiTarget; import com.minecrafttas.mctcommon.json.FineTarget; import com.minecrafttas.mctcommon.json.FineTypeAdapter; @@ -18,7 +16,7 @@ public PathNavigateTypeAdapter() { register("world", FineMode.FINE); register("currentPath", FineMode.FINE); register("speed", FineMode.FINE); - register("pathSearchRange", FineMode.EXCLUDED); + register("pathSearchRange", FineMode.FINE); register("totalTicks", FineMode.FINE); register("ticksAtLastPos", FineMode.FINE); register("lastPosCheck", FineMode.FINE); @@ -29,9 +27,9 @@ public PathNavigateTypeAdapter() { register("maxDistanceToWaypoint", FineMode.FINE); register("tryUpdatePath", FineMode.FINE); register("lastTimeUpdated", FineMode.FINE); - register("nodeProcessor", FineMode.EXCLUDED); + register("nodeProcessor", FineMode.FINE); register("targetPos", FineMode.FINE); - register("pathFinder", FineMode.EXCLUDED); + register("pathFinder", FineMode.FINE); } } @@ -41,12 +39,6 @@ public static class PathNavigateGroundTypeAdapter extends FineTypeAdapter { public PathNavigateGroundTypeAdapter() { register("shouldAvoidSun", FineMode.FINE); } - - @Override - public Object deserialize(JsonElement element, Class clazz, FineGson fineJson) { - Object obj = constructNew(clazz); - return deserialize(element, clazz, fineJson, obj); - } } @FineTarget(net.minecraft.pathfinding.PathNavigateClimber.class) From 055370981e82c70c22e7596275d2b7baa579f0db Mon Sep 17 00:00:00 2001 From: Scribble Date: Sun, 27 Sep 2026 16:39:39 +0200 Subject: [PATCH 26/26] [Savestates] Experimental FineTypeAdapter setting for targetting Anonymous classes --- .../minecrafttas/mctcommon/json/FineGson.java | 50 +++++++++++++++++-- .../mctcommon/json/FineTarget.java | 6 ++- .../mctcommon/json/FineTypeAdapter.java | 4 +- .../typeadapters/EntityAITypeAdapters.java | 26 ++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java index 30f7f11a..02c7725f 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineGson.java @@ -1,6 +1,7 @@ package com.minecrafttas.mctcommon.json; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -10,6 +11,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; +import com.google.gson.internal.ConstructorConstructor; +import com.google.gson.reflect.TypeToken; /** * A fine grained gson replacement @@ -18,7 +21,7 @@ */ public class FineGson { - private Map, FineTypeAdapter> typeAdapters = new HashMap<>(); + private TypeAdapterMap typeAdapters = new TypeAdapterMap(); private final Gson gsonInstance; @@ -37,8 +40,10 @@ public void registerTypeAdapter(Class type) { if (!FineTypeAdapter.class.isAssignableFrom(type)) { throw new RuntimeException(String.format("Trying to register type adapter %s, but it doesn't extend FineTypeAdapter", type.getName())); } - Class targetType = type.getAnnotation(FineTarget.class).value(); + FineTarget fineTargetAnnotation = type.getAnnotation(FineTarget.class); + Class targetType = fineTargetAnnotation.value(); FineTypeAdapter adapter; + try { adapter = (FineTypeAdapter) type.newInstance(); } catch (InstantiationException | IllegalAccessException e) { @@ -80,11 +85,18 @@ public JsonElement serialize(Object obj, Class type) { } public Object deserialize(JsonElement element, Class type) { + if (!typeAdapters.containsKey(type)) + return gsonInstance.fromJson(element, type); + Object obj = constructNew(type); + return deserialize(element, type, obj); + } + + public Object deserialize(JsonElement element, Class type, Object existing) { if (!typeAdapters.containsKey(type)) return gsonInstance.fromJson(element, type); FineTypeAdapter adapter = typeAdapters.get(type); - Object out = adapter.deserialize(element, type, this); + Object out = adapter.deserialize(element, type, this, existing); Class superclass = type.getSuperclass(); if (superclass != Object.class) { @@ -101,4 +113,36 @@ public Gson getGsonInstance() { public Map, FineTypeAdapter> getTypeAdapters() { return typeAdapters; } + + private class TypeAdapterMap extends HashMap, FineTypeAdapter> { + + @Override + public boolean containsKey(Object key) { + return get(key) != null; + } + + @Override + public FineTypeAdapter get(Object key) { + Class classKey = (Class) key; + if (classKey.isAnonymousClass()) { + for (FineTypeAdapter adapter : values()) { + FineTarget fineTargetAnnotation = adapter.getClass().getAnnotation(FineTarget.class); + if (fineTargetAnnotation == null) + continue; + Class enclosingType = fineTargetAnnotation.enclosingclazz(); + Class superType = fineTargetAnnotation.superclazz(); + if (classKey.getEnclosingClass() == enclosingType && classKey.getSuperclass() == superType) + return adapter; + } + return null; + } + return super.get(key); + } + } + + public static T constructNew(Class clazz) { + ConstructorConstructor constructor = new ConstructorConstructor(Collections.emptyMap(), true, Collections.emptyList()); + TypeToken token = TypeToken.get(clazz); + return constructor.get(token, true).construct(); + } } diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java index 83c9f71f..432bbdfc 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTarget.java @@ -9,5 +9,9 @@ @Target(TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface FineTarget { - Class value(); + Class value() default Object.class; + + Class superclazz() default Object.class; + + Class enclosingclazz() default Object.class; } diff --git a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java index 9a4c9785..0515cdfe 100644 --- a/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java +++ b/src/main/java/com/minecrafttas/mctcommon/json/FineTypeAdapter.java @@ -86,8 +86,8 @@ public JsonElement serialize(Object obj, FineGson fineJson, Class clazz) thro } public Object deserialize(JsonElement element, Class clazz, FineGson fineJson) { - Object obj = constructNew(clazz); - return deserialize(element, clazz, fineJson, obj); + Object existing = FineGson.constructNew(clazz); + return deserialize(element, clazz, fineJson, existing); } public Object deserialize(JsonElement element, Class clazz, FineGson fineJson, Object obj) { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java index 746980c7..75420bd5 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/typeadapters/EntityAITypeAdapters.java @@ -6,10 +6,13 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.minecrafttas.mctcommon.json.FineField.FineMode; +import com.minecrafttas.mctcommon.json.FineGson; import com.minecrafttas.mctcommon.json.FineMultiTarget; import com.minecrafttas.mctcommon.json.FineTarget; import com.minecrafttas.mctcommon.json.FineTypeAdapter; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.monster.AbstractSkeleton; import net.minecraft.item.Item; @FineMultiTarget @@ -81,6 +84,29 @@ public EntityAILookIdleTypeAdapter() { } } + @FineTarget(enclosingclazz = AbstractSkeleton.class, superclazz = EntityAIAttackMelee.class) + public static class AbstractSkeletonAITypeAdapter extends FineTypeAdapter { + + public AbstractSkeletonAITypeAdapter() { + register("world", FineMode.FINE); + register("attacker", FineMode.FINE); + register("attackTick", FineMode.FINE); + register("speedTowardsTarget", FineMode.FINE); + register("longMemory", FineMode.FINE); + register("path", FineMode.FINE); + register("delayCounter", FineMode.FINE); + register("targetX", FineMode.FINE); + register("targetY", FineMode.FINE); + register("targetZ", FineMode.FINE); + register("attackInterval", FineMode.FINE); + } + + @Override + public JsonElement serialize(Object obj, FineGson fineJson, Class clazz) throws RuntimeException { + return super.serialize(obj, fineJson, EntityAIAttackMelee.class); + } + } + @FineTarget(net.minecraft.entity.ai.EntityAITarget.class) public static class EntityAITargetTypeAdapter extends FineTypeAdapter {