Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/minecrafttas/tasmod/TASmod.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -42,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;
Expand Down Expand Up @@ -105,11 +107,14 @@ 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);

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();
Expand Down Expand Up @@ -173,6 +178,7 @@ public void onServerStart(MinecraftServer server) {
EventListenerRegistry.register(globalRandomness);
}
mathRandomness = new MathRNG(0);
squidRNG.setSeed(globalRandomness.getCurrentSeed() + 1000L);
}

@Override
Expand Down Expand Up @@ -242,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() {
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/minecrafttas/tasmod/ktrng/builtin/SquidRNG.java
Original file line number Diff line number Diff line change
@@ -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";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -14,6 +15,9 @@ public class MixinEntitySquid {

@WrapWithCondition(method = "<init>", 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -92,7 +92,7 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) {

for (Entry<String, JsonElement> 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")) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
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.EntityLivingBase;
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());

mainObject.add("revengeTarget", gsonInstance.toJsonTree(entityLiving.getRevengeTarget()));
mainObject.add("lastAttackedEntity", gsonInstance.toJsonTree(entityLiving.getLastAttackedEntity()));

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<EntityAITaskEntry> 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<String, JsonElement> 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();

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());
}
}
}

private void deserialiseAITasks(EntityAITasks tasks, JsonObject jsonTasks) {
tasks.taskEntries = deserialiseAIEntries(tasks, jsonTasks.get("taskEntries").getAsJsonArray());
tasks.executingTaskEntries = deserialiseAIEntries(tasks, jsonTasks.get("executingTaskEntries").getAsJsonArray());
}

private Set<EntityAITaskEntry> deserialiseAIEntries(EntityAITasks tasks, JsonArray jsonEntries) {
Set<EntityAITaskEntry> out = new LinkedHashSet<>();
for (JsonElement jsonEntryElement : jsonEntries) {
JsonObject jsonEntry = jsonEntryElement.getAsJsonObject();
int priority = jsonEntry.get("priority").getAsInt();
boolean using = jsonEntry.get("using").getAsBoolean();
Class<? extends EntityAIBase> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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 <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<T> rawType = (Class<T>) type.getRawType();
if (!BlockPos.class.isAssignableFrom(rawType))
return null;
return new TypeAdapter<T>() {
@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());
}
};
}
}
Loading