diff --git a/gradle.properties b/gradle.properties index 9129b224..b0387ad9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,5 +16,5 @@ mod_email=scribble@minecrafttas.com # TASmod properties group=com.minecrafttas artifact=TASmod-1.12.2 -version=Beta2.1 +version=Beta3 release=false diff --git a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java index 1170342e..03d5c1f4 100644 --- a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java +++ b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java @@ -94,7 +94,7 @@ public interface EventBase { */ public static void register(EventBase eventListener) { if (eventListener == null) { - throw new NullPointerException("Tried to register a packethandler with value null"); + throw new NullPointerException("Tried to register an eventListener with value null"); } for (Class type : searchForInterfaces(eventListener.getClass())) { @@ -153,7 +153,7 @@ public static void register(List eventListeners) { */ public static void unregister(EventBase eventListener) { if (eventListener == null) { - throw new NullPointerException("Tried to unregister a packethandler with value null"); + throw new NullPointerException("Tried to unregister an eventListener with value null"); } for (Class type : searchForInterfaces(eventListener.getClass())) { if (EventBase.class.isAssignableFrom(type)) { diff --git a/src/main/java/com/minecrafttas/mctcommon/events/EventServer.java b/src/main/java/com/minecrafttas/mctcommon/events/EventServer.java index ea26c691..6973b2ab 100644 --- a/src/main/java/com/minecrafttas/mctcommon/events/EventServer.java +++ b/src/main/java/com/minecrafttas/mctcommon/events/EventServer.java @@ -13,6 +13,19 @@ */ public interface EventServer { + /** + * Fired, just before the server initialised, for both integrated and dedicated server. + */ + @FunctionalInterface + public static interface EventServerStart extends EventBase { + + /** + * Fired, when the server is initialised, for both integrated and dedicated server. + * @param server The server + */ + public void onServerStart(MinecraftServer server); + } + /** * Fired, when the server is initialised, for both integrated and dedicated server. */ diff --git a/src/main/java/com/minecrafttas/mctcommon/mixin/MixinMinecraftServer.java b/src/main/java/com/minecrafttas/mctcommon/mixin/MixinMinecraftServer.java index 4ea7d14f..b921efc9 100644 --- a/src/main/java/com/minecrafttas/mctcommon/mixin/MixinMinecraftServer.java +++ b/src/main/java/com/minecrafttas/mctcommon/mixin/MixinMinecraftServer.java @@ -9,6 +9,7 @@ import com.minecrafttas.mctcommon.events.EventListenerRegistry; import com.minecrafttas.mctcommon.events.EventServer.EventServerGameLoop; 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.events.EventServer.EventServerTick; @@ -17,6 +18,11 @@ @Mixin(MinecraftServer.class) public class MixinMinecraftServer { + @Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;init()Z")) + public void inject_initStart(CallbackInfo ci) { + EventListenerRegistry.fireEvent(EventServerStart.class, (MinecraftServer) (Object) this); + } + @Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;init()Z", shift = Shift.AFTER)) public void inject_init(CallbackInfo ci) { EventListenerRegistry.fireEvent(EventServerInit.class, (MinecraftServer) (Object) this); diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 51700db5..302f0860 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -8,6 +8,7 @@ import com.minecrafttas.mctcommon.CommandRegistry; import com.minecrafttas.mctcommon.events.EventListenerRegistry; 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.networking.PacketHandlerRegistry; import com.minecrafttas.mctcommon.networking.Server; @@ -24,6 +25,8 @@ import com.minecrafttas.tasmod.commands.CommandSavestate; import com.minecrafttas.tasmod.commands.CommandTickrate; import com.minecrafttas.tasmod.handlers.PlayUntilHandler; +import com.minecrafttas.tasmod.ktrng.GlobalRandomnessTimer; +import com.minecrafttas.tasmod.ktrng.MathRandomness; import com.minecrafttas.tasmod.playback.PlaybackControllerServer; import com.minecrafttas.tasmod.playback.metadata.builtin.StartpositionMetadataExtension; import com.minecrafttas.tasmod.registries.TASmodAPIRegistry; @@ -32,6 +35,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.KTRNGSeedStorage; import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer; import com.minecrafttas.tasmod.ticksync.TickSyncServer; import com.minecrafttas.tasmod.util.LoggerMarkers; @@ -48,7 +52,7 @@ * * @author Scribble */ -public class TASmod implements ModInitializer, EventServerInit, EventServerStop { +public class TASmod implements ModInitializer, EventServerStart, EventServerInit, EventServerStop { public static final Logger LOGGER = LogManager.getLogger("TASmod"); @@ -85,6 +89,12 @@ public class TASmod implements ModInitializer, EventServerInit, EventServerStop public static ClientMotionStorage motionStorage = new ClientMotionStorage(); + public static GlobalRandomnessTimer globalRandomness; + + public static KTRNGSeedStorage seedStorage = new KTRNGSeedStorage(); + + public static MathRandomness mathRandomness = new MathRandomness(0); + @Override public void onInitialize() { @@ -128,12 +138,18 @@ public void onInitialize() { EventListenerRegistry.register(resourcepackHandler); PacketHandlerRegistry.register(playUntil); EventListenerRegistry.register(playUntil); - EventListenerRegistry.register(TASmodAPIRegistry.SAVESTATE_STORAGE); registerSavestateStorage(); } + @Override + public void onServerStart(MinecraftServer server) { + globalRandomness = new GlobalRandomnessTimer(); + EventListenerRegistry.register(globalRandomness); + mathRandomness = new MathRandomness(); + } + @Override public void onServerInit(MinecraftServer server) { LOGGER.info("Initializing server"); @@ -196,6 +212,7 @@ public void onServerStop(MinecraftServer mcserver) { private void registerSavestateStorage() { TASmodAPIRegistry.SAVESTATE_STORAGE.register(motionStorage); + TASmodAPIRegistry.SAVESTATE_STORAGE.register(seedStorage); } public static MinecraftServer getServerInstance() { diff --git a/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java b/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java index 51ac126b..dda3601f 100644 --- a/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java +++ b/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java @@ -27,7 +27,7 @@ interface EventServerSavestate extends EventBase { * Fired when loading a savestate, before the savestate folder is copied */ @FunctionalInterface - interface EventServerLoadstate extends EventBase { + interface EventServerLoadstatePre extends EventBase { /** * Fired when loading a savestate, before the savestate folder is copied @@ -35,7 +35,22 @@ interface EventServerLoadstate extends EventBase { * @param server The server instance * @param paths The {@link SavestatePaths} object */ - public void onServerLoadstate(MinecraftServer server, SavestatePaths paths); + public void onServerLoadstatePre(MinecraftServer server, SavestatePaths paths); + } + + /** + * Fired when loading a savestate, after the savestate folder is copied + */ + @FunctionalInterface + interface EventServerLoadstatePost extends EventBase { + + /** + * Fired when loading a savestate, after the savestate folder is copied + * + * @param server The server instance + * @param paths The {@link SavestatePaths} object + */ + public void onServerLoadstatePost(MinecraftServer server, SavestatePaths paths); } /** @@ -47,7 +62,7 @@ interface EventServerCompleteLoadstate extends EventBase { /** * Fired one tick after a loadstate was carried out */ - public void onServerLoadstateComplete(); + public void onServerLoadstateComplete(MinecraftServer server, SavestatePaths paths); } /** diff --git a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java index 0269a886..37758dd3 100644 --- a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java +++ b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java @@ -18,6 +18,7 @@ import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.events.EventClient.EventDrawHotbar; +import com.minecrafttas.tasmod.ktrng.KTRNGWorldHandler; import com.minecrafttas.tasmod.playback.PlaybackControllerClient; import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate; import com.minecrafttas.tasmod.playback.filecommands.builtin.DesyncMonitorFileCommandExtension; @@ -296,17 +297,37 @@ public boolean checkInit() { y += 14; -// if (TASmod.ktrngHandler.isLoaded()) { -// title = "ktrng_randomseed"; -// if (configuration.getProperty(title + "_x", "err").equals("err")) -// setDefaults(title, y); -// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title -// + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> { -// if (Minecraft.getMinecraft().currentScreen == this) -// return "KTRNG"; -// return "RandomSeed: " + TASmod.ktrngHandler.getGlobalSeedClient(); -// })); -// } + title = "ktrng_randomseed"; + if (configuration.getProperty(title + "_x", "err").equals("err")) + setDefaults(title, y); + lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> { + if (Minecraft.getMinecraft().currentScreen == this) + return "KTRNG"; + return "Global RandomSeed: " + TASmod.globalRandomness.getCurrentSeed(); + })); + +// y += 14; +// title = "ktrng_entitycount"; +// if (configuration.getProperty(title + "_x", "err").equals("err")) +// setDefaults(title, y); +// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title +// + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> { +// if (Minecraft.getMinecraft().currentScreen == this) +// return "EntityCount"; +// return "EntityCount: " + EntityRandomness.entityCounter; +// })); + + y += 14; + title = "ktrng_worldseed"; + if (configuration.getProperty(title + "_x", "err").equals("err")) + setDefaults(title, y); + lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> { + if (Minecraft.getMinecraft().currentScreen == this) + return "WorldRNG"; + return "WorldRNG: " + KTRNGWorldHandler.getWorldRandom(); + })); title = "facing"; y += 14; diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/EntityRandomness.java b/src/main/java/com/minecrafttas/tasmod/ktrng/EntityRandomness.java new file mode 100644 index 00000000..a5de00bf --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/EntityRandomness.java @@ -0,0 +1,16 @@ +package com.minecrafttas.tasmod.ktrng; + +import com.minecrafttas.tasmod.TASmod; + +public class EntityRandomness extends RandomBase { + + public static long entityCount = 0; + + public EntityRandomness() { + super(TASmod.globalRandomness.getCurrentSeed()); + } + + public EntityRandomness(long seed) { + super(seed); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRandomnessTimer.java b/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRandomnessTimer.java new file mode 100644 index 00000000..6d64417b --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRandomnessTimer.java @@ -0,0 +1,31 @@ +package com.minecrafttas.tasmod.ktrng; + +import com.minecrafttas.mctcommon.events.EventServer; + +import net.minecraft.server.MinecraftServer; + +public class GlobalRandomnessTimer implements EventServer.EventServerTick { + + private final RandomBase globalRandomness; + + private long currentSeed = 0L; + + public GlobalRandomnessTimer() { + globalRandomness = new RandomBase(0L); + } + + @Override + public void onServerTick(MinecraftServer server) { + globalRandomness.advance(); + currentSeed = globalRandomness.getSeed(); + } + + public long getCurrentSeed() { + return currentSeed; + } + + public void setSeed(long newSeed) { + globalRandomness.setSeed(newSeed); + currentSeed = newSeed; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRandomnessTimerClient.java b/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRandomnessTimerClient.java new file mode 100644 index 00000000..ea94251c --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/GlobalRandomnessTimerClient.java @@ -0,0 +1,38 @@ +package com.minecrafttas.tasmod.ktrng; + +import com.minecrafttas.mctcommon.events.EventClient; + +import net.minecraft.client.Minecraft; + +public class GlobalRandomnessTimerClient implements EventClient.EventClientTick { + + private final RandomBase globalRandomness; + private final RandomBase uuidRandomness; + + private long currentSeed = 0L; + + public GlobalRandomnessTimerClient() { + globalRandomness = new RandomBase(0L); + uuidRandomness = new RandomBase(0L); + } + + @Override + public void onClientTick(Minecraft mc) { + currentSeed = globalRandomness.nextLong(); + uuidRandomness.setSeed(currentSeed); + } + + public long getCurrentSeed() { + return currentSeed; + } + + public RandomBase getUUIDRandom() { + return uuidRandomness; + } + + public void setSeed(long newSeed) { + globalRandomness.setSeed(newSeed); + currentSeed = newSeed; + } + +} diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/KTRNGEntityHandler.java b/src/main/java/com/minecrafttas/tasmod/ktrng/KTRNGEntityHandler.java new file mode 100644 index 00000000..62da4da6 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/KTRNGEntityHandler.java @@ -0,0 +1,38 @@ +package com.minecrafttas.tasmod.ktrng; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.Entity; +import net.minecraft.world.WorldServer; + +public class KTRNGEntityHandler { + + public static Map getRandomnessList() { + Map out = new HashMap<>(); + WorldServer[] worlds = TASmod.getServerInstance().worlds; + for (WorldServer worldServer : worlds) { + for (Entity entity : worldServer.loadedEntityList) { + UUID entityUUID = entity.getUniqueID(); + EntityRandomness entityRandomness = (EntityRandomness) entity.rand; + out.put(entityUUID, entityRandomness); + } + } + return out; + } + + public static void setRandomnessList(Map randomnessList) { + WorldServer[] worlds = TASmod.getServerInstance().worlds; + for (WorldServer worldServer : worlds) { + for (Entity entity : worldServer.loadedEntityList) { + UUID uuid = entity.getUniqueID(); + EntityRandomness rand = randomnessList.get(uuid); + if (rand != null) + entity.rand = rand; + } + } + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/KTRNGWorldHandler.java b/src/main/java/com/minecrafttas/tasmod/ktrng/KTRNGWorldHandler.java new file mode 100644 index 00000000..d1c66971 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/KTRNGWorldHandler.java @@ -0,0 +1,64 @@ +package com.minecrafttas.tasmod.ktrng; + +import java.util.HashMap; +import java.util.Map; + +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.world.WorldServer; + +public class KTRNGWorldHandler { + + public static Map getWorldRandomnessMap() { + Map out = new HashMap<>(); + WorldServer[] worlds = TASmod.getServerInstance().worlds; + int id = 0; + for (WorldServer worldServer : worlds) { + WorldRandomness worldRandomness = (WorldRandomness) worldServer.rand; + out.put(id, worldRandomness); + id++; + } + return out; + } + + public static Map getWorldLCGMap() { + Map out = new HashMap<>(); + WorldServer[] worlds = TASmod.getServerInstance().worlds; + int id = 0; + for (WorldServer worldServer : worlds) { + int updateLCG = worldServer.updateLCG; + out.put(id, updateLCG); + id++; + } + return out; + } + + public static void setWorldRandomnessMap(Map randomnessList) { + WorldServer[] worlds = TASmod.getServerInstance().worlds; + int id = 0; + for (WorldServer worldServer : worlds) { + WorldRandomness worldRandomness = randomnessList.get(id); + if (worldRandomness != null) + worldServer.rand = worldRandomness; + id++; + } + } + + public static void setWorldLCGMap(Map lcgList) { + WorldServer[] worlds = TASmod.getServerInstance().worlds; + int id = 0; + for (WorldServer worldServer : worlds) { + Integer updateLCG = lcgList.get(id); + if (updateLCG != null) + worldServer.updateLCG = updateLCG; + id++; + } + } + + public static String getWorldRandom() { + if (TASmod.getServerInstance().worlds[0] != null) + return Long.toString(((WorldRandomness) TASmod.getServerInstance().worlds[0].rand).getSeed()); + else + return ""; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java b/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java index d071cd81..18926f41 100644 --- a/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java @@ -40,7 +40,6 @@ public class KillTheRNGHandler implements EventServerTick, EventPlayerJoinedClie * @param isLoaded If the KillTheRNG mod is loaded */ public KillTheRNGHandler(boolean isLoaded) { - this.isLoaded = isLoaded; if (isLoaded) { diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/MathRandomness.java b/src/main/java/com/minecrafttas/tasmod/ktrng/MathRandomness.java new file mode 100644 index 00000000..686b5f91 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/MathRandomness.java @@ -0,0 +1,19 @@ +package com.minecrafttas.tasmod.ktrng; + +import com.minecrafttas.tasmod.TASmod; + +/** + *

Randomness instance for hooking into {@link Math#random()} + * + * @author Scribble + */ +public class MathRandomness extends RandomBase { + + public MathRandomness() { + super(TASmod.globalRandomness.getCurrentSeed()); + } + + public MathRandomness(long seed) { + super(seed); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/RandomBase.java b/src/main/java/com/minecrafttas/tasmod/ktrng/RandomBase.java new file mode 100644 index 00000000..8f2be415 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/RandomBase.java @@ -0,0 +1,208 @@ +package com.minecrafttas.tasmod.ktrng; + +import java.util.Random; + +import com.minecrafttas.tasmod.TASmod; +import com.minecrafttas.tasmod.util.LoggerMarkers; + +import kaptainwutax.seedutils.lcg.LCG; +import kaptainwutax.seedutils.rand.JRand; + +public class RandomBase extends Random { + + private String name; + private String description; + + private long timesCalled = 0; + + private boolean enabled; + private boolean client; + + private long initialSeed; + + public RandomBase() { + super(); + } + + public RandomBase(long seed) { + super(seed); + this.initialSeed = seed; + } + + @Override + public void setSeed(long seedIn) { + setSeed(seedIn, true); + } + + public void setSeed(long seedIn, boolean shouldLog) { + if (shouldLog) + fireSetEvent("setSeed()", seedIn, "", 8); + super.setSeed(seedIn ^ 0x5deece66dL); + } + + public long getSeed() { + long saved = timesCalled; + long seed = reverse(super.nextLong()) ^ 0x5deece66dL; + super.setSeed(seed); + timesCalled = saved; + return seed ^ 0x5deece66dL; + } + + public static long reverse(long in) { + return (((7847617 * ((24667315 * (in >>> 32) + 18218081 * (in & 0xffffffffL) + 67552711) >> 32) - 18218081 * ((-4824621 * (in >>> 32) + 7847617 * (in & 0xffffffffL) + 7847617) >> 32)) - 11) * 246154705703781L) & 0xffffffffffffL; + } + + public String getName() { + return this.name; + } + + public String getDescription() { + return description; + } + + public long getTimesCalled() { + return timesCalled; + } + + public boolean isEnabled() { + return enabled; + } + + public boolean isClient() { + return client; + } + + @Override + public long nextLong() { + timesCalled++; + long seedstored = getSeed(); + long value = super.nextLong(); + fireGetEvent("nextLong()", seedstored, Long.toString(value)); + return value; + } + + @Override + public double nextDouble() { + timesCalled++; + long seedstored = getSeed(); + double value = super.nextDouble(); + fireGetEvent("nextDouble()", seedstored, Double.toString(value)); + return value; + } + + @Override + public boolean nextBoolean() { + timesCalled++; + long seedstored = getSeed(); + boolean value = super.nextBoolean(); + fireGetEvent("nextBoolean()", seedstored, Boolean.toString(value)); + return value; + } + + @Override + public int nextInt() { + timesCalled++; + long seedstored = getSeed(); + int value = super.nextInt(); + fireGetEvent("nextInt()", seedstored, Integer.toString(value)); + return value; + } + + @Override + public int nextInt(int bound) { + timesCalled++; + long seedstored = getSeed(); + int value = super.nextInt(bound); + fireGetEvent(String.format("nextInt(%s)", bound), seedstored, Integer.toString(value)); + return value; + } + + @Override + public float nextFloat() { + return super.nextFloat(); + } + + @Override + public void nextBytes(byte[] bytes) { + super.nextBytes(bytes); + } + + @Override + public double nextGaussian() { + timesCalled++; + double value = 0; + value = super.nextGaussian(); + return value; + } + + public void advance() { + advance(1); + } + + public void advance(long i) { + JRand thing = JRand.ofInternalSeed(getSeed()); + thing.advance(i); + setSeed(thing.getSeed(), false); + } + + public long getSeedAt(int steps) { + JRand thing = new JRand(getSeed()).combine(steps); + return thing.getSeed(); + } + + public long distance(RandomBase random) { + return RandomBase.distance(this.getSeed(), random.getSeed()); + } + + public long distance(long seed) { + return RandomBase.distance(this.getSeed(), seed); + } + + public static long distance(RandomBase random1, RandomBase random2) { + return RandomBase.distance(random1.getSeed(), random2.getSeed()); + } + + public static long distance(long seed, long seed2) { + return LCG.JAVA.distance(seed, seed2); + } + + @Override + public String toString() { + return Long.toString(getSeed()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RandomBase) { + RandomBase custom = (RandomBase) obj; + return custom.name.equals(name); + } else { + return super.equals(obj); + } + } + + public void fireSetEvent(String eventType, long seed, String value, int stackTraceOffset) { + fireEvent(eventType, seed, value, stackTraceOffset); + } + + public void fireGetEvent(String eventType, long seed, String value) { + //fireEvent(eventType, seed, value, 3); + } + + public void fireEvent(String eventType, long seed, String value, int stackTraceOffset) { + StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[stackTraceOffset]; + String methodName = stackTraceElement.getMethodName(); + String[] classNames = stackTraceElement.getClassName().split("\\."); + String className = classNames[classNames.length - 1]; + if (methodName.equals("showBarrierParticles")) + return; + String out = className + "." + methodName + + (stackTraceElement.isNativeMethod() ? "(Native Method)" : (stackTraceElement.getFileName() != null && stackTraceElement.getLineNumber() >= 0 ? "(" + stackTraceElement.getFileName() + ":" + stackTraceElement.getLineNumber() + + ")" : (stackTraceElement.getFileName() != null ? "(" + stackTraceElement.getFileName() + ")" : "(Unknown Source)"))); + TASmod.LOGGER.debug(LoggerMarkers.KillTheRNG, "{} {}\t{}\t{}", eventType, seed, value, out); + } + + public long getInitialSeed() { + return initialSeed; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/WorldRandomness.java b/src/main/java/com/minecrafttas/tasmod/ktrng/WorldRandomness.java new file mode 100644 index 00000000..01a51b7c --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/ktrng/WorldRandomness.java @@ -0,0 +1,19 @@ +package com.minecrafttas.tasmod.ktrng; + +import com.minecrafttas.tasmod.TASmod; + +public class WorldRandomness extends RandomBase { + + public WorldRandomness(long seed) { + super(seed); + } + + public WorldRandomness() { + super(TASmod.globalRandomness.getCurrentSeed()); + } + + @Override + public void fireEvent(String val, long seed, String value, int offset) { + //super.fireEvent(val, seed, value, 5); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntity.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntity.java new file mode 100644 index 00000000..3bef0312 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinEntity.java @@ -0,0 +1,33 @@ +package com.minecrafttas.tasmod.mixin.killtherng; + +import java.util.Random; +import java.util.UUID; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.minecrafttas.tasmod.ktrng.EntityRandomness; + +import net.minecraft.entity.Entity; +import net.minecraft.world.World; + +@Mixin(Entity.class) +public class MixinEntity { + + @ModifyExpressionValue(method = "", at = @At(value = "NEW", target = "Ljava/util/Random;")) + public Random modify_entityRandom(Random original, World world) { + if (!world.isRemote) { + return new EntityRandomness(); + } else { + return new EntityRandomness(0L); + } + } + + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/MathHelper;getRandomUUID(Ljava/util/Random;)Ljava/util/UUID;")) + private UUID wrap_getRandomUUID(Random rand, Operation original) { + return original.call(new Random()); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinRenderLivingBase.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinRenderLivingBase.java new file mode 100644 index 00000000..f7953eb3 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinRenderLivingBase.java @@ -0,0 +1,44 @@ +package com.minecrafttas.tasmod.mixin.killtherng; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +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 com.minecrafttas.tasmod.ktrng.RandomBase; + +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderLivingBase; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; + +@SuppressWarnings("rawtypes") +@Mixin(RenderLivingBase.class) +public abstract class MixinRenderLivingBase extends Render { + + @Unique + private long previousSeed = 0; + + protected MixinRenderLivingBase(RenderManager renderManager) { + super(renderManager); + } + + @SuppressWarnings("unchecked") + @Inject(method = "renderName", at = @At(value = "HEAD")) + public void inject_renderName(EntityLivingBase entity, double d, double e, double f, CallbackInfo ci) { + Entity serverEntity = TASmod.getServerInstance().getEntityFromUuid(entity.getUniqueID()); + if (serverEntity == null) + return; + RandomBase random = (RandomBase) serverEntity.rand; + long seed = random.getSeed(); + long distance = -random.distance(random.getInitialSeed()); + GlStateManager.alphaFunc(516, 0.1F); + this.renderEntityName(entity, d, e + 0.69D, f, Long.toString(random.getInitialSeed()), 64); + this.renderEntityName(entity, d, e + 0.46D, f, Long.toString(seed), 64); + this.renderEntityName(entity, d, e + 0.23D, f, Long.toString(distance), 64); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinWorld.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinWorld.java new file mode 100644 index 00000000..8a710c49 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/MixinWorld.java @@ -0,0 +1,20 @@ +package com.minecrafttas.tasmod.mixin.killtherng; + +import java.util.Random; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.minecrafttas.tasmod.ktrng.WorldRandomness; + +import net.minecraft.world.World; + +@Mixin(World.class) +public class MixinWorld { + + @ModifyExpressionValue(method = "", at = @At(value = "NEW", target = "Ljava/util/Random;")) + public Random modify_worldRandom(Random original) { + return new WorldRandomness(); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityItem.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityItem.java new file mode 100644 index 00000000..a94c9bf5 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityItem.java @@ -0,0 +1,20 @@ +package com.minecrafttas.tasmod.mixin.killtherng.mathrand; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.world.World; + +@Mixin(EntityItem.class) +public class MixinEntityItem { + + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/Math;random()D")) + private double wrap_entityItemInit(Operation original, World world, double d, double e, double f) { + return TASmod.mathRandomness.nextDouble(); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityLivingBase.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityLivingBase.java new file mode 100644 index 00000000..2d882de9 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityLivingBase.java @@ -0,0 +1,25 @@ +package com.minecrafttas.tasmod.mixin.killtherng.mathrand; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; + +@Mixin(EntityLivingBase.class) +public class MixinEntityLivingBase { + + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/Math;random()D")) + private double wrap_entityLivingBase(Operation original, World world) { + return TASmod.mathRandomness.nextDouble(); + } + + @WrapOperation(method = "attackEntityFrom", at = @At(value = "INVOKE", target = "Ljava/lang/Math;random()D")) + private double wrap_attackEntityFrom(Operation original) { + return TASmod.mathRandomness.nextDouble(); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityTNTPrimed.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityTNTPrimed.java new file mode 100644 index 00000000..bd8fec2d --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityTNTPrimed.java @@ -0,0 +1,21 @@ +package com.minecrafttas.tasmod.mixin.killtherng.mathrand; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityTNTPrimed; +import net.minecraft.world.World; + +@Mixin(EntityTNTPrimed.class) +public class MixinEntityTNTPrimed { + + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/Math;random()D")) + private double wrap_entityTNTPrimedInit(Operation original, World world, double d, double e, double f, EntityLivingBase entityLivingBase) { + return TASmod.mathRandomness.nextDouble(); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityXPOrb.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityXPOrb.java new file mode 100644 index 00000000..ed776195 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinEntityXPOrb.java @@ -0,0 +1,20 @@ +package com.minecrafttas.tasmod.mixin.killtherng.mathrand; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.entity.item.EntityXPOrb; +import net.minecraft.world.World; + +@Mixin(EntityXPOrb.class) +public class MixinEntityXPOrb { + + @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Ljava/lang/Math;random()D")) + private double wrap_entityXPOrb(Operation original, World world, double d, double e, double f, int i) { + return TASmod.mathRandomness.nextDouble(); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinWorldEntitySpawner.java b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinWorldEntitySpawner.java new file mode 100644 index 00000000..e4c718ca --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/mixin/killtherng/mathrand/MixinWorldEntitySpawner.java @@ -0,0 +1,20 @@ +package com.minecrafttas.tasmod.mixin.killtherng.mathrand; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.minecrafttas.tasmod.TASmod; + +import net.minecraft.world.WorldEntitySpawner; +import net.minecraft.world.WorldServer; + +@Mixin(WorldEntitySpawner.class) +public class MixinWorldEntitySpawner { + + @WrapOperation(method = "findChunksForSpawning", at = @At(value = "INVOKE", target = "Ljava/lang/Math;random()D")) + private double wrap_worldEntitySpawnerFindChunks(Operation original, WorldServer worldServer, boolean bl, boolean bl2, boolean bl3) { + return TASmod.mathRandomness.nextDouble(); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java index 33816e55..23b27d45 100644 --- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java +++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java @@ -20,6 +20,7 @@ public class TASmodAPIRegistry { * savestate/rerecord count and category. * *

Any custom class has to implement PlaybackMetadataExtension + *

Side: Client

*/ public static final PlaybackMetadataRegistry PLAYBACK_METADATA = new PlaybackMetadataRegistry(); @@ -28,7 +29,7 @@ public class TASmodAPIRegistry { * *

File commands give the opportunity to run commands on each recorded tick and each played back tick.
* File commands also have access to the TASfile so that data can be stored and read in/from the TASfile. - * + *

Side: Client

*/ public static final PlaybackFileCommandsRegistry PLAYBACK_FILE_COMMAND = new PlaybackFileCommandsRegistry(); @@ -39,6 +40,7 @@ public class TASmodAPIRegistry { * or extend an existing flavor (like {@link Beta1Flavor}) and overwrite parts of the methods. * *

The resulting flavor can be registered here and can be found as a saving option with /saveTAS + *

Side: Client

*/ public static final SerialiserFlavorRegistry SERIALISER_FLAVOR = new SerialiserFlavorRegistry(); @@ -47,6 +49,7 @@ public class TASmodAPIRegistry { * *

Create a new ClientCommand by extending {@link ClientCommandBase},
* then create a command like normal, as it extends from the vanilla {@link CommandBase} + *

Side: Client

*/ public static final ClientCommandRegistry CLIENT_COMMANDS = new ClientCommandRegistry(); diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java index 7c486dbf..bbd88526 100644 --- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java +++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java @@ -46,7 +46,6 @@ public enum TASmodKeybinds implements KeybindID { TASmodClient.virtual.CAMERA_ANGLE.updateNextCameraAngle(0, 45); }), TEST1("Various Testing", "TASmod", Keyboard.KEY_F12, () -> { - Minecraft.getMinecraft().displayGuiScreen(null); }, VirtualKeybindings::isKeyDown), TEST2("Various Testing2", "TASmod", Keyboard.KEY_F7, () -> { }, VirtualKeybindings::isKeyDown); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java index 150b67d5..ea4d0745 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java @@ -384,7 +384,7 @@ private void loadStateInner(SavestatePaths paths, SavestateCallback cb, Savestat Path sourcefolder = paths.getSourceFolder(); Path targetfolder = paths.getTargetFolder(); - EventListenerRegistry.fireEvent(EventSavestate.EventServerLoadstate.class, server, paths); + EventListenerRegistry.fireEvent(EventSavestate.EventServerLoadstatePre.class, server, paths); /* * Prevents loading an InputSavestate when loading index 0 (Index 0 is the @@ -445,6 +445,8 @@ private void loadStateInner(SavestatePaths paths, SavestateCallback cb, Savestat worldHandler.sendChunksToClient(); + EventListenerRegistry.fireEvent(EventSavestate.EventServerLoadstatePost.class, server, paths); + if (SavestateFlags.BLOCK_PAUSE_TICKRATE.isBlocked(flags)) { TASmod.tickratechanger.pauseGame(false); } else { @@ -467,7 +469,7 @@ private void loadStateInner(SavestatePaths paths, SavestateCallback cb, Savestat * Rn it's not a problem, but this should be looked at... */ TASmod.tickSchedulerServer.add(() -> { - EventListenerRegistry.fireEvent(EventSavestate.EventServerCompleteLoadstate.class); + EventListenerRegistry.fireEvent(EventSavestate.EventServerCompleteLoadstate.class, server, paths); onLoadstateComplete(); }); } diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandlerClient.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandlerClient.java index 878ec01f..a1bc64b7 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandlerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandlerClient.java @@ -36,45 +36,8 @@ public void loadPlayer(NBTTagCompound compound) { // Clear any accidental applied potion particles on the client ((AccessorEntityLivingBase) player).clearPotionEffects(); - /* - * TODO - * The following 20 lines are all one - * gross workaround for correctly applying the player motion - * to the client... - * - * The motion is applied - * to the player in a previous step and unfortunately - * player.readFromNBT(compound) overwrites the - * previously applied motion... - * - * So this workaround makes sure that the motion is not overwritten - * Fixing this, requires restructuring the steps for loadstating - * and since I plan to do this anyway at some point, I will - * leave this here and be done for today*/ - double x = player.motionX; - double y = player.motionY; - double z = player.motionZ; - - float rx = player.moveForward; - float ry = player.moveVertical; - float rz = player.moveStrafing; - - boolean sprinting = player.isSprinting(); - float jumpVector = player.jumpMovementFactor; - player.readFromNBT(compound); - player.motionX = x; - player.motionY = y; - player.motionZ = z; - - player.moveForward = rx; - player.moveVertical = ry; - player.moveStrafing = rz; - - player.setSprinting(sprinting); - player.jumpMovementFactor = jumpVector; - LOGGER.trace(LoggerMarkers.Savestate, "Setting client gamemode"); // #86 int gamemode = compound.getInteger("playerGameType"); diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateResourcePackHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateResourcePackHandler.java index dcd76051..54c23313 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateResourcePackHandler.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateResourcePackHandler.java @@ -35,7 +35,7 @@ * * @author Scribble */ -public class SavestateResourcePackHandler implements EventSavestate.EventServerLoadstate, ServerPacketHandler, ClientPacketHandler { +public class SavestateResourcePackHandler implements EventSavestate.EventServerLoadstatePre, ServerPacketHandler, ClientPacketHandler { /** * The server future for waiting until the client is done unloading the RP @@ -48,7 +48,7 @@ public class SavestateResourcePackHandler implements EventSavestate.EventServerL public static CountDownLatch clientRPLatch; @Override - public void onServerLoadstate(MinecraftServer server, SavestatePaths paths) { + public void onServerLoadstatePre(MinecraftServer server, SavestatePaths paths) { if (server.getResourcePackUrl().isEmpty() || server.isDedicatedServer()) return; diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateTempHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateTempHandler.java index 619985e8..0474b760 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateTempHandler.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateTempHandler.java @@ -29,7 +29,7 @@ * * @author Scribble */ -public class SavestateTempHandler implements EventControllerStateChange, EventRecordClear, EventSavestate.EventServerLoadstate { +public class SavestateTempHandler implements EventControllerStateChange, EventRecordClear, EventSavestate.EventServerLoadstatePre { private final Logger logger; private final SavestateHandlerServer handler; @@ -149,7 +149,7 @@ public void setNoSave(boolean noSave) { } @Override - public void onServerLoadstate(MinecraftServer server, SavestatePaths paths) { + public void onServerLoadstatePre(MinecraftServer server, SavestatePaths paths) { createState = false; } } 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 1f911302..3e1b5b3a 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionBase.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionBase.java @@ -25,5 +25,12 @@ public SavestateStorageExtensionBase(String fileName) { public abstract JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave); - public abstract void onLoadstate(MinecraftServer server, JsonObject loadedData); + public void onLoadstatePre(MinecraftServer server, JsonObject loadedData) { + } + + public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { + } + + public void onLoadstateComplete(MinecraftServer server, JsonObject loadedData) { + } } 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 8ab26bec..086e74cd 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionRegistry.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateStorageExtensionRegistry.java @@ -3,13 +3,14 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Map; import com.google.gson.JsonObject; import com.minecrafttas.mctcommon.registry.AbstractRegistry; import com.minecrafttas.tasmod.TASmod; -import com.minecrafttas.tasmod.events.EventSavestate.EventServerLoadstate; -import com.minecrafttas.tasmod.events.EventSavestate.EventServerSavestate; +import com.minecrafttas.tasmod.events.EventSavestate; import com.minecrafttas.tasmod.savestates.SavestateIndexer; import com.minecrafttas.tasmod.savestates.SavestateIndexer.SavestatePaths; import com.minecrafttas.tasmod.savestates.exceptions.LoadstateException; @@ -18,7 +19,9 @@ import net.minecraft.server.MinecraftServer; -public class SavestateStorageExtensionRegistry extends AbstractRegistry implements EventServerSavestate, EventServerLoadstate { +public class SavestateStorageExtensionRegistry extends AbstractRegistry implements EventSavestate.EventServerSavestate, EventSavestate.EventServerLoadstatePre, EventSavestate.EventServerLoadstatePost, EventSavestate.EventServerCompleteLoadstate { + + Map jsonMap = new HashMap<>(); public SavestateStorageExtensionRegistry() { super("SAVESTATESTORAGE_REGISTRY", new LinkedHashMap<>()); @@ -47,8 +50,8 @@ public void onServerSavestate(MinecraftServer server, SavestatePaths paths) { } } - @Override - public void onServerLoadstate(MinecraftServer server, SavestatePaths paths) { + private void load(SavestatePaths paths) { + jsonMap.clear(); Path storageDir = paths.getTargetFolder().resolve(SavestateIndexer.savestateDataDir); if (!Files.exists(storageDir)) { try { @@ -72,8 +75,29 @@ public void onServerLoadstate(MinecraftServer server, SavestatePaths paths) { } catch (IOException e) { throw new LoadstateException(e, "Can't load %s in %s extension", storage.fileName, storage.getExtensionName()); } + jsonMap.put(storage, loadedData); + } + } + + @Override + public void onServerLoadstatePre(MinecraftServer server, SavestatePaths paths) { + load(paths); + for (SavestateStorageExtensionBase storage : REGISTRY.values()) { + storage.onLoadstatePre(server, jsonMap.get(storage)); + } + } + + @Override + public void onServerLoadstatePost(MinecraftServer server, SavestatePaths paths) { + for (SavestateStorageExtensionBase storage : REGISTRY.values()) { + storage.onLoadstatePost(server, jsonMap.get(storage)); + } + } - storage.onLoadstate(server, loadedData); + @Override + public void onServerLoadstateComplete(MinecraftServer server, SavestatePaths paths) { + for (SavestateStorageExtensionBase storage : REGISTRY.values()) { + storage.onLoadstateComplete(TASmod.getServerInstance(), jsonMap.get(storage)); } } } 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 26b7151b..81f89e55 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 @@ -87,7 +87,7 @@ public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { } @Override - public void onLoadstate(MinecraftServer server, JsonObject loadedData) { + public void onLoadstatePost(MinecraftServer server, JsonObject loadedData) { PlayerList list = server.getPlayerList(); for (Entry motionDataJsonElement : loadedData.entrySet()) { @@ -97,17 +97,16 @@ public void onLoadstate(MinecraftServer server, JsonObject loadedData) { EntityPlayerMP player; if (playerUUID.equals("singleplayer")) { String ownerName = server.getServerOwner(); - if (ownerName == null) { + if (ownerName == null) continue; - } + player = list.getPlayerByUsername(ownerName); } else { player = list.getPlayerByUUID(UUID.fromString(playerUUID)); } - if (player == null) { + if (player == null) continue; - } try { TASmod.server.sendTo(player, new TASmodBufferBuilder(SAVESTATE_SET_MOTION).writeMotionData(motionData)); 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 new file mode 100644 index 00000000..4a2324a5 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/builtin/KTRNGSeedStorage.java @@ -0,0 +1,116 @@ +package com.minecrafttas.tasmod.savestates.storage.builtin; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.minecrafttas.tasmod.TASmod; +import com.minecrafttas.tasmod.ktrng.EntityRandomness; +import com.minecrafttas.tasmod.ktrng.KTRNGEntityHandler; +import com.minecrafttas.tasmod.ktrng.KTRNGWorldHandler; +import com.minecrafttas.tasmod.ktrng.WorldRandomness; +import com.minecrafttas.tasmod.savestates.storage.SavestateStorageExtensionBase; + +import net.minecraft.server.MinecraftServer; + +public class KTRNGSeedStorage extends SavestateStorageExtensionBase { + + public KTRNGSeedStorage() { + super("killtherngSeeds.json"); + } + + @Override + public JsonObject onSavestate(MinecraftServer server, JsonObject dataToSave) { + long currentSeed = TASmod.globalRandomness.getCurrentSeed(); + dataToSave.addProperty("globalSeed", currentSeed); + + JsonObject entityRandomDataJson = new JsonObject(); + + JsonObject entityRandomListJson = new JsonObject(); + Map randomList = KTRNGEntityHandler.getRandomnessList(); + for (Entry entry : randomList.entrySet()) { + entityRandomListJson.addProperty(entry.getKey().toString(), entry.getValue().getSeed()); + } + + entityRandomDataJson.add("entityList", entityRandomListJson); + + dataToSave.add("entityRandom", entityRandomDataJson); + + JsonObject worldRandomDataJson = new JsonObject(); + + JsonObject worldListJson = new JsonObject(); + Map worldRandom = KTRNGWorldHandler.getWorldRandomnessMap(); + for (Entry entry : worldRandom.entrySet()) { + worldListJson.addProperty(entry.getKey().toString(), entry.getValue().getSeed()); + } + + worldRandomDataJson.add("worldList", worldListJson); + + JsonObject lcgListJson = new JsonObject(); + Map lcgMap = KTRNGWorldHandler.getWorldLCGMap(); + for (Entry entry : lcgMap.entrySet()) { + lcgListJson.addProperty(entry.getKey().toString(), entry.getValue()); + } + + worldRandomDataJson.add("lcgList", lcgListJson); + + dataToSave.add("worldRandom", worldRandomDataJson); + + dataToSave.addProperty("mathRandom", Long.toString(TASmod.mathRandomness.getSeed())); + + return dataToSave; + } + + @Override + public void onLoadstateComplete(MinecraftServer server, JsonObject loadedData) { + TASmod.LOGGER.debug("Loading KTRNG seeds"); + long newSeed = loadedData.get("globalSeed").getAsLong(); + TASmod.globalRandomness.setSeed(newSeed); + + JsonObject entityRandomDataJson = loadedData.get("entityRandom").getAsJsonObject(); + + JsonObject entityRandomListJson = entityRandomDataJson.get("entityList").getAsJsonObject(); + + Map randomList = new HashMap<>(); + for (Entry entry : entityRandomListJson.entrySet()) { + UUID uuid = UUID.fromString(entry.getKey().toString()); + EntityRandomness entityRandomness = new EntityRandomness(entry.getValue().getAsLong()); + + randomList.put(uuid, entityRandomness); + } + + KTRNGEntityHandler.setRandomnessList(randomList); + + JsonObject worldRandomJson = loadedData.get("worldRandom").getAsJsonObject(); + JsonObject worldListJson = worldRandomJson.get("worldList").getAsJsonObject(); + + Map worldList = new HashMap<>(); + for (Entry entry : worldListJson.entrySet()) { + int id = Integer.parseInt(entry.getKey()); + WorldRandomness worldRandomness = new WorldRandomness(entry.getValue().getAsLong()); + + worldList.put(id, worldRandomness); + } + + JsonObject worldLCGList = worldRandomJson.get("lcgList").getAsJsonObject(); + Map lcgList = new HashMap<>(); + for (Entry entry : worldLCGList.entrySet()) { + int id = Integer.parseInt(entry.getKey()); + int lcg = entry.getValue().getAsInt(); + + lcgList.put(id, lcg); + } + + KTRNGWorldHandler.setWorldRandomnessMap(worldList); + + TASmod.mathRandomness.setSeed(loadedData.get("mathRandom").getAsLong()); + } + + @Override + public String getExtensionName() { + return "KTRNGSeedStorage"; + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java b/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java index 1d2951ed..1a08fe30 100644 --- a/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java +++ b/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java @@ -47,6 +47,8 @@ public class LoggerMarkers implements EventDrawHotbarAlways { public static final Marker Mouse = MarkerManager.getMarker("Mouse"); + public static final Marker KillTheRNG = MarkerManager.getMarker("KillTheRNG"); + @Override public void onDrawHotbarAlways() { ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index dec8d114..67c0563a 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -26,8 +26,8 @@ ] }, "mixins": [ - "tasmod.mixin.json", - "mctcommon.mixin.json" + "mctcommon.mixin.json", + "tasmod.mixin.json" ], "depends": { "fabricloader": ">=0.14.19", diff --git a/src/main/resources/log4j.xml b/src/main/resources/log4j.xml index 88fd9007..d2826b99 100644 --- a/src/main/resources/log4j.xml +++ b/src/main/resources/log4j.xml @@ -15,6 +15,8 @@ onMatch="${sys:tasmod.marker.keyboard:-DENY}" onMismatch="NEUTRAL" /> + diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener index 0029bc11..1f287702 100644 --- a/src/main/resources/tasmod.accesswidener +++ b/src/main/resources/tasmod.accesswidener @@ -11,4 +11,9 @@ accessible field net/minecraft/world/World worldInfo Lnet/minecraft/world/storag accessible method net/minecraft/world/storage/SaveHandler setSessionLock ()V -accessible field net/minecraft/client/settings/KeyBinding CATEGORY_ORDER Ljava/util/Map; \ No newline at end of file +accessible field net/minecraft/client/settings/KeyBinding CATEGORY_ORDER Ljava/util/Map; + +#KillTheRNG +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; \ No newline at end of file diff --git a/src/main/resources/tasmod.mixin.json b/src/main/resources/tasmod.mixin.json index b500e7d6..2daed941 100644 --- a/src/main/resources/tasmod.mixin.json +++ b/src/main/resources/tasmod.mixin.json @@ -21,7 +21,15 @@ "events.MixinEntityPlayerMP", // Fixing forge and vanilla stuff - "fixes.MixinDragonFightManager" + "fixes.MixinDragonFightManager", + + "killtherng.MixinEntity", + "killtherng.MixinWorld", + "killtherng.mathrand.MixinEntityLivingBase", + "killtherng.mathrand.MixinEntityItem", + "killtherng.mathrand.MixinEntityXPOrb", + "killtherng.mathrand.MixinEntityTNTPrimed", + "killtherng.mathrand.MixinWorldEntitySpawner" ], "client": [ @@ -68,6 +76,9 @@ // Fixes "fixes.MixinMinecraftFullscreen", "fixes.MixinNetworkManager", - "fixes.MixinMouseHelper" + "fixes.MixinMouseHelper", + + // KTRNG + "killtherng.MixinRenderLivingBase" ] } \ No newline at end of file diff --git a/src/test/java/tasmod/killtherng/RNGTest.java b/src/test/java/tasmod/killtherng/RNGTest.java new file mode 100644 index 00000000..b969345e --- /dev/null +++ b/src/test/java/tasmod/killtherng/RNGTest.java @@ -0,0 +1,39 @@ +package tasmod.killtherng; + +import com.minecrafttas.tasmod.ktrng.RandomBase; + +public class RNGTest { + + public static void main(String[] args) { + long[] longlist = new long[] { + //@formatter:off + 113621727298730L, + 161845404674820L + //@formatter:on + }; + + printDistance(longlist); + + longlist = new long[] { + //@formatter:off + 161845404674820L, + 107865211428631L, + 252587169991970L, + 223075662074294L, + 66246869218509L, + 81210955942352L, + 183553865074233L, + 11371681017552L + //@formatter:on + }; +// printDistance(longlist); + } + + private static void printDistance(long[] list) { + long prev = list[0]; + for (long l : list) { + System.out.println(RandomBase.distance(prev, l)); + } + System.out.println(""); + } +}