diff --git a/build.gradle b/build.gradle index 0dacea1f..47a057d6 100644 --- a/build.gradle +++ b/build.gradle @@ -2,14 +2,13 @@ plugins { // loom plugin id "fabric-loom" version "${loom_version}" id "ploceus" version "${loom_version}" - id "com.palantir.git-version" version "4.2.0" - id "com.diffplug.spotless" version "8.1.0" + id "com.diffplug.spotless" version "8.6.0" } // set basic properties def hash = "" if(project.release=="false") { - hash = "-SNAPSHOT_"+versionDetails().gitHash.substring(0,7) + hash = "-SNAPSHOT_"+getGitCommitHash() } version = project.version+hash group = project.group @@ -109,4 +108,22 @@ spotless { eclipse().configFile("formatter/TASmodFormatter.xml") } enforceCheck false +} + +def getGitCommitHash() { + def gitFolder = "$projectDir/.git/" + def takeFromHash = 7 + /* + * '.git/HEAD' contains either + * in case of detached head: the currently checked out commit hash + * otherwise: a reference to a file containing the current commit hash + */ + def head = new File(gitFolder + "HEAD").text.split(":") // .git/HEAD + def isCommit = head.length == 1 + // def isRef = head.length > 1 // ref: refs/heads/master + + if(isCommit) return head[0].trim().take(takeFromHash) // e5a7c79edabb + + def refHead = new File(gitFolder + head[1].trim()) // .git/refs/heads/master + refHead.text.trim().take takeFromHash } \ No newline at end of file diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 877af57e..3f05ad30 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -33,6 +33,7 @@ import com.minecrafttas.tasmod.ktrng.builtin.MathRNG; import com.minecrafttas.tasmod.ktrng.builtin.WorldSeedRNG; import com.minecrafttas.tasmod.ktrng.events.KillTheRNGMonitor; +import com.minecrafttas.tasmod.ktrng.handlers.UUIDHandler; import com.minecrafttas.tasmod.playback.PlaybackControllerServer; import com.minecrafttas.tasmod.playback.metadata.builtin.StartpositionMetadataExtension; import com.minecrafttas.tasmod.registries.TASmodAPIRegistry; @@ -41,6 +42,9 @@ 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.EntityBatSpawnPositionStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntitySquidRotationStorage; +import com.minecrafttas.tasmod.savestates.storage.builtin.EntityTickTimersStorage; import com.minecrafttas.tasmod.savestates.storage.builtin.KTRNGSeedStorage; import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer; import com.minecrafttas.tasmod.ticksync.TickSyncServer; @@ -98,6 +102,9 @@ 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 MathRNG mathRandomness = new MathRNG(0); @@ -105,6 +112,8 @@ public class TASmod implements ModInitializer, EventServerStart, EventServerInit public static KillTheRNGMonitor debugRand = new KillTheRNGMonitor(); + public static UUIDHandler uuidHandler = new UUIDHandler(); + public static Configuration config; @Override @@ -151,6 +160,7 @@ public void onInitialize() { EventListenerRegistry.register(resourcepackHandler); PacketHandlerRegistry.register(playUntil); EventListenerRegistry.register(playUntil); + EventListenerRegistry.register(uuidHandler); EventListenerRegistry.register(TASmodAPIRegistry.SAVESTATE_STORAGE); registerSavestateStorage(); @@ -158,8 +168,10 @@ public void onInitialize() { @Override public void onServerStart(MinecraftServer server) { - globalRandomness = new GlobalRNG(); - EventListenerRegistry.register(globalRandomness); + if (globalRandomness == null) { + globalRandomness = new GlobalRNG(); + EventListenerRegistry.register(globalRandomness); + } mathRandomness = new MathRNG(0); } @@ -227,6 +239,9 @@ 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); } public static MinecraftServer getServerInstance() { diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRNG.java b/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRNG.java index 87ab3b2f..80882c10 100644 --- a/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRNG.java +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRNG.java @@ -5,6 +5,13 @@ import kaptainwutax.seedutils.rand.JRand; import net.minecraft.server.MinecraftServer; +/** + *
Special RNG generating seeds for each new rng instance. + *
This RNG advances to it's next seed every server tick. Any new RNG created then uses the {@link #currentSeed},
+ * which makes it have a deterministic starting seed
+ *
+ * @author Scribble
+ */
public class GlobalRNG implements EventServer.EventServerTick {
private final JRand globalRNG;
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/RandomBase.java b/src/main/java/com/minecrafttas/tasmod/ktrng/RandomBase.java
index 01b0355e..375b8adf 100644
--- a/src/main/java/com/minecrafttas/tasmod/ktrng/RandomBase.java
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/RandomBase.java
@@ -10,16 +10,21 @@
import kaptainwutax.seedutils.lcg.LCG;
import kaptainwutax.seedutils.rand.JRand;
+/**
+ * Base RNG class extending the {@link Random} class, but designed to be easily modifyable and monitorable.
+ *
+ * @author Scribble
+ */
public abstract class RandomBase extends Random implements Registerable {
- RNGSide side;
- private long initialSeed;
- private JRand jrand;
+ protected RNGSide side;
+ protected long initialSeed;
+ protected JRand jrand;
public RandomBase() {
super(TASmod.globalRandomness.getCurrentSeed());
initialSeed = TASmod.globalRandomness.getCurrentSeed();
- jrand = new JRand(initialSeed);
+ jrand = new JRand(initialSeed, false);
}
public RandomBase(long seed) {
@@ -31,9 +36,9 @@ public RandomBase(long seed) {
@Override
public void setSeed(long seedIn) {
super.setSeed(seedIn);
- if (jrand != null)
+ if (jrand != null) {
jrand.setSeed(seedIn, false);
-// super.setSeed(seedIn ^ 0x5deece66dL);
+ }
}
public long getSeed() {
@@ -146,8 +151,8 @@ public String toString() {
return Long.toString(getSeed());
}
- public void fireSetEvent(String eventType, long seed, String value, int stackTraceOffset) {
- fireRNGEvent(eventType, seed, value, stackTraceOffset);
+ public void fireSetEvent(String eventType, long seed, String value) {
+// fireRNGEvent(eventType, seed, value, stackTraceOffset);
}
public void fireGetEvent(String eventType, long seed, String value) {
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/EntityRNG.java b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/EntityRNG.java
index 0fc0aafa..d897edef 100644
--- a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/EntityRNG.java
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/EntityRNG.java
@@ -1,19 +1,34 @@
package com.minecrafttas.tasmod.ktrng.builtin;
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
+import com.minecrafttas.tasmod.events.EventKillTheRNGServer;
import com.minecrafttas.tasmod.ktrng.RandomBase;
+import net.minecraft.entity.Entity;
+
+/**
+ * Custom RNG making {@link Entity#rand} deterministic
+ *
+ * @author Scribble
+ */
public class EntityRNG extends RandomBase {
- public EntityRNG() {
+ private Entity entity;
+
+ public EntityRNG(Entity entity) {
super();
+ this.entity = entity;
}
- public EntityRNG(long seed) {
+ public EntityRNG(long seed, Entity entity) {
super(seed);
+ this.entity = entity;
}
@Override
public void fireRNGEvent(String eventType, long seed, String value, int stackTraceOffset) {
+ String rngType = String.format("%s(%s)", entity.getClass().getSimpleName(), entity.getUniqueID());
+ EventListenerRegistry.fireEvent(EventKillTheRNGServer.EventRNG.class, super.side, eventType, seed, value, rngType, 9);
}
@Override
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/MathRNG.java b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/MathRNG.java
index 3334f350..e5397ae1 100644
--- a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/MathRNG.java
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/MathRNG.java
@@ -3,7 +3,7 @@
import com.minecrafttas.tasmod.ktrng.RandomBase;
/**
- *
Randomness instance for hooking into {@link Math#random()}
+ * Custom RNG making {@link Math#random()} deterministic
*
* @author Scribble
*/
@@ -17,6 +17,11 @@ public MathRNG(long seed) {
super(seed);
}
+ @Override
+ public void fireRNGEvent(String eventType, long seed, String value, int stackTraceOffset) {
+// super.fireRNGEvent(eventType, seed, value, stackTraceOffset);
+ }
+
@Override
public String getExtensionName() {
return "MathRNG";
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/UUIDRNG.java b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/UUIDRNG.java
new file mode 100644
index 00000000..4d96e9bb
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/UUIDRNG.java
@@ -0,0 +1,31 @@
+package com.minecrafttas.tasmod.ktrng.builtin;
+
+import com.minecrafttas.tasmod.TASmod;
+import com.minecrafttas.tasmod.ktrng.RandomBase;
+
+import net.minecraft.entity.Entity;
+
+/**
+ * Custom RNG making {@link Entity#entityUniqueID} deterministic
+ *
+ * @author Scribble
+ */
+public class UUIDRNG extends RandomBase {
+
+ public static int uuidcounter;
+
+ public UUIDRNG(int shift) {
+ super(TASmod.globalRandomness.getCurrentSeed() + shift);
+ }
+
+ @Override
+ public void fireRNGEvent(String eventType, long seed, String value, int stackTraceOffset) {
+// super.fireRNGEvent(eventType, seed, value, stackTraceOffset);
+ }
+
+ @Override
+ public String getExtensionName() {
+ return "UUIDRNG";
+ }
+
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldRNG.java b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldRNG.java
index d8fab814..fcef7ea2 100644
--- a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldRNG.java
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldRNG.java
@@ -2,6 +2,13 @@
import com.minecrafttas.tasmod.ktrng.RandomBase;
+import net.minecraft.world.World;
+
+/**
+ * Custom RNG making {@link World#rand} deterministic
+ *
+ * @author Scribble
+ */
public class WorldRNG extends RandomBase {
public WorldRNG() {
@@ -14,7 +21,7 @@ public WorldRNG(long seed) {
@Override
public void fireRNGEvent(String val, long seed, String value, int offset) {
- super.fireRNGEvent(val, seed, value, 9);
+// super.fireRNGEvent(val, seed, value, 9);
}
@Override
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldSeedRNG.java b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldSeedRNG.java
index 80d4a3d3..78a007aa 100644
--- a/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldSeedRNG.java
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/builtin/WorldSeedRNG.java
@@ -2,6 +2,13 @@
import com.minecrafttas.tasmod.ktrng.RandomBase;
+import net.minecraft.world.World;
+
+/**
+ * Custom RNG separating {@link World#setRandomSeed(int, int, int) worldseed setting behaviour} from the normal RNG
+ *
+ * @author Scribble
+ */
public class WorldSeedRNG extends RandomBase {
public WorldSeedRNG() {
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/handlers/KTRNGEntityHandler.java b/src/main/java/com/minecrafttas/tasmod/ktrng/handlers/KTRNGEntityHandler.java
index 58536c1f..25d49fce 100644
--- a/src/main/java/com/minecrafttas/tasmod/ktrng/handlers/KTRNGEntityHandler.java
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/handlers/KTRNGEntityHandler.java
@@ -10,6 +10,7 @@
import net.minecraft.entity.Entity;
import net.minecraft.world.WorldServer;
+@Deprecated
public class KTRNGEntityHandler {
public static Map Generates and distributes UUIDs deterministically
+ * This is necessary since the RNG is deterministic and would result in duplicated UUIDs
+ *
+ * @author Scribble
+ */
+public class UUIDHandler implements EventServerTick {
+
+ private int uuidIndex;
+
+ public UUIDHandler() {
+ }
+
+ @Override
+ public void onServerTick(MinecraftServer server) {
+ uuidIndex = -1;
+ }
+
+ public UUIDRNG getNewUUIDRNG() {
+ return new UUIDRNG(uuidIndex++);
+ }
+
+ public UUID getNewUUID() {
+ return MathHelper.getRandomUUID(getNewUUIDRNG());
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntity.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntity.java
index 211b4ee6..dc3655ea 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntity.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntity.java
@@ -9,6 +9,7 @@
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.minecrafttas.tasmod.TASmod;
import com.minecrafttas.tasmod.ktrng.builtin.EntityRNG;
import net.minecraft.entity.Entity;
@@ -20,13 +21,16 @@ public class MixinEntity {
@ModifyExpressionValue(method = " 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/EntityTickTimersStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityTickTimersStorage.java
new file mode 100644
index 00000000..7d356430
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/EntityTickTimersStorage.java
@@ -0,0 +1,91 @@
+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/KTRNGSeedStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/KTRNGSeedStorage.java
index 3f90834e..a0622fbb 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/KTRNGSeedStorage.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/KTRNGSeedStorage.java
@@ -14,7 +14,9 @@
import com.minecrafttas.tasmod.ktrng.handlers.KTRNGWorldHandler;
import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase;
+import net.minecraft.entity.Entity;
import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.WorldServer;
public class KTRNGSeedStorage extends SavestateStorageExtensionBase {
@@ -74,16 +76,19 @@ public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) {
JsonObject entityRandomListJson = entityRandomDataJson.get("entityList").getAsJsonObject();
- Map