Skip to content

Commit 9587580

Browse files
committed
Add tick list entry storage
1 parent 34a6970 commit 9587580

File tree

10 files changed

+235
-15
lines changed

10 files changed

+235
-15
lines changed

build.gradle

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ if(project.release=="false") {
1515
version = project.version+hash
1616
group = project.group
1717

18-
// compile for java 8
19-
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
18+
java {
19+
// compile for java 8
20+
sourceCompatibility = targetCompatibility = 11
21+
}
2022

2123
loom {
2224
// set access widener

src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package com.minecrafttas.mctcommon.events;
22

3-
import org.apache.commons.lang3.ClassUtils;
4-
53
import java.lang.reflect.InvocationTargetException;
64
import java.lang.reflect.Method;
75
import java.util.ArrayList;
86
import java.util.HashMap;
97

8+
import org.apache.commons.lang3.ArrayUtils;
9+
import org.apache.commons.lang3.ClassUtils;
10+
1011
/**
1112
* Registry for making objects available to listen for events.<br>
1213
* <br>
@@ -94,7 +95,8 @@ public static void register(EventBase eventListener) {
9495
if (eventListener == null) {
9596
throw new NullPointerException("Tried to register a packethandler with value null");
9697
}
97-
for (Class<?> type : eventListener.getClass().getInterfaces()) {
98+
99+
for (Class<?> type : searchForInterfaces(eventListener.getClass())) {
98100
if (EventBase.class.isAssignableFrom(type)) {
99101

100102
// If a new event type is being registered, add a new arraylist
@@ -107,6 +109,18 @@ public static void register(EventBase eventListener) {
107109
}
108110
}
109111

112+
private static Class<?>[] searchForInterfaces(Class<?> clazz) {
113+
if (clazz == null) {
114+
return new Class<?>[] {};
115+
}
116+
Class<?>[] interfaces = clazz.getInterfaces();
117+
Class<?> superclass = clazz.getSuperclass();
118+
if (superclass != null && superclass != Object.class) {
119+
interfaces = ArrayUtils.addAll(interfaces, searchForInterfaces(superclass));
120+
}
121+
return interfaces;
122+
}
123+
110124
/**
111125
* Registers multiple objects to be an event listener. The objects must
112126
* implement an event extending {@link EventBase}
@@ -128,7 +142,7 @@ public static void unregister(EventBase eventListener) {
128142
if (eventListener == null) {
129143
throw new NullPointerException("Tried to unregister a packethandler with value null");
130144
}
131-
for (Class<?> type : eventListener.getClass().getInterfaces()) {
145+
for (Class<?> type : searchForInterfaces(eventListener.getClass())) {
132146
if (EventBase.class.isAssignableFrom(type)) {
133147
ArrayList<EventBase> registryList = EVENTLISTENER_REGISTRY.get(type);
134148
if (registryList != null) {

src/main/java/com/minecrafttas/tasmod/TASmod.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.minecrafttas.tasmod.playback.metadata.integrated.StartpositionMetadataExtension;
3030
import com.minecrafttas.tasmod.registries.TASmodPackets;
3131
import com.minecrafttas.tasmod.savestates.SavestateHandlerServer;
32+
import com.minecrafttas.tasmod.savestates.storage.NextTickListEntryStorage;
3233
import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer;
3334
import com.minecrafttas.tasmod.ticksync.TickSyncServer;
3435
import com.minecrafttas.tasmod.util.LoggerMarkers;
@@ -113,6 +114,7 @@ public void onInitialize() {
113114
PacketHandlerRegistry.register(startPositionMetadataExtension);
114115
PacketHandlerRegistry.register(tabCompletionUtils);
115116
PacketHandlerRegistry.register(commandFileCommand);
117+
EventListenerRegistry.register(new NextTickListEntryStorage());
116118
}
117119

118120
@Override

src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import com.minecrafttas.mctcommon.events.EventListenerRegistry.EventBase;
66

7+
import net.minecraft.server.MinecraftServer;
8+
79
public interface EventSavestate {
810

911
/**
@@ -19,7 +21,7 @@ interface EventServerSavestate extends EventBase {
1921
* @param target Target folder, where the savestate is copied to
2022
* @param current The current folder that will be copied from
2123
*/
22-
public void onServerSavestate(int index, Path target, Path current);
24+
public void onServerSavestate(MinecraftServer server, int index, Path target, Path current);
2325
}
2426

2527
/**
@@ -35,7 +37,7 @@ interface EventServerLoadstate extends EventBase {
3537
* @param target Target folder, where the savestate is copied to
3638
* @param current The current folder that will be copied from
3739
*/
38-
public void onServerLoadstate(int index, Path target, Path current);
40+
public void onServerLoadstate(MinecraftServer server, int index, Path target, Path current);
3941
}
4042

4143
/**
@@ -49,10 +51,10 @@ interface EventServerCompleteLoadstate extends EventBase {
4951
*/
5052
public void onServerLoadstateComplete();
5153
}
52-
54+
5355
@FunctionalInterface
5456
interface EventClientSavestate extends EventBase {
55-
57+
5658
public void onClientSavestate();
5759
}
5860
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.minecrafttas.tasmod.mixin.storage;
2+
3+
import org.spongepowered.asm.mixin.Mixin;
4+
import org.spongepowered.asm.mixin.gen.Accessor;
5+
6+
import net.minecraft.world.NextTickListEntry;
7+
8+
@Mixin(NextTickListEntry.class)
9+
public interface AccessorNextTickListEntry {
10+
11+
@Accessor
12+
public long getTickEntryID();
13+
}

src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ public static enum SavestateState {
8686
private final SavestatePlayerHandler playerHandler;
8787
private final SavestateWorldHandler worldHandler;
8888

89+
public static final Path storageDir = Path.of("tasmod/");
90+
8991
private final Logger logger;
9092
public static boolean wasLoading;
9193

@@ -195,7 +197,7 @@ public void saveState(int savestateIndex, boolean tickrate0, boolean changeIndex
195197
Path currentfolder = savestateDirectory.resolve(".." + File.separator + worldname);
196198
Path targetfolder = getSavestateFile(indexToSave);
197199

198-
EventListenerRegistry.fireEvent(EventSavestate.EventServerSavestate.class, indexToSave, targetfolder, currentfolder);
200+
EventListenerRegistry.fireEvent(EventSavestate.EventServerSavestate.class, server, indexToSave, targetfolder, currentfolder);
199201

200202
if (Files.exists(targetfolder)) {
201203
logger.warn(LoggerMarkers.Savestate, "WARNING! Overwriting the savestate with the index {}", indexToSave);
@@ -334,7 +336,7 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
334336
Path currentfolder = savestateDirectory.resolve(".." + File.separator + worldname);
335337
Path targetfolder = getSavestateFile(indexToLoad);
336338

337-
EventListenerRegistry.fireEvent(EventSavestate.EventServerLoadstate.class, indexToLoad, targetfolder, currentfolder);
339+
EventListenerRegistry.fireEvent(EventSavestate.EventServerLoadstate.class, server, indexToLoad, targetfolder, currentfolder);
338340

339341
/*
340342
* Prevents loading an InputSavestate when loading index 0 (Index 0 is the
@@ -625,7 +627,7 @@ private void saveSavestateDataFile(boolean legacy) {
625627
*/
626628
private void loadSavestateDataFile() {
627629
logger.trace(LoggerMarkers.Savestate, "Loading savestate data file");
628-
Path tasmodDir = savestateDirectory.resolve("../" + server.getFolderName() + "/tasmod/");
630+
Path tasmodDir = savestateDirectory.resolve("../" + server.getFolderName()).resolve(storageDir);
629631
Path savestateDat = tasmodDir.resolve("savestateData.txt");
630632

631633
if (!Files.exists(savestateDat)) {
@@ -655,7 +657,7 @@ private void loadSavestateDataFile() {
655657
public void loadCurrentIndexFromFile() {
656658
logger.trace(LoggerMarkers.Savestate, "Loading current index from file");
657659
int index = -1;
658-
Path tasmodDir = savestateDirectory.resolve("../" + server.getFolderName() + "/tasmod/");
660+
Path tasmodDir = savestateDirectory.resolve("../" + server.getFolderName()).resolve(storageDir);
659661
if (!Files.exists(tasmodDir)) {
660662
try {
661663
Files.createDirectory(tasmodDir);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.minecrafttas.tasmod.savestates.storage;
2+
3+
import com.minecrafttas.tasmod.events.EventSavestate.EventServerLoadstate;
4+
import com.minecrafttas.tasmod.events.EventSavestate.EventServerSavestate;
5+
6+
public abstract class AbstractExtendStorage implements EventServerSavestate, EventServerLoadstate {
7+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package com.minecrafttas.tasmod.savestates.storage;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.io.InputStreamReader;
6+
import java.io.OutputStream;
7+
import java.io.OutputStreamWriter;
8+
import java.io.Reader;
9+
import java.io.Writer;
10+
import java.lang.reflect.Type;
11+
import java.nio.charset.StandardCharsets;
12+
import java.nio.file.Files;
13+
import java.nio.file.Path;
14+
import java.util.Set;
15+
16+
import com.google.gson.Gson;
17+
import com.google.gson.GsonBuilder;
18+
import com.google.gson.JsonArray;
19+
import com.google.gson.JsonDeserializationContext;
20+
import com.google.gson.JsonDeserializer;
21+
import com.google.gson.JsonElement;
22+
import com.google.gson.JsonObject;
23+
import com.google.gson.JsonParseException;
24+
import com.google.gson.JsonSerializationContext;
25+
import com.google.gson.JsonSerializer;
26+
import com.google.gson.stream.JsonReader;
27+
import com.minecrafttas.tasmod.mixin.storage.AccessorNextTickListEntry;
28+
import com.minecrafttas.tasmod.savestates.SavestateHandlerServer;
29+
import com.minecrafttas.tasmod.util.Ducks.WorldServerDuck;
30+
31+
import net.minecraft.block.Block;
32+
import net.minecraft.server.MinecraftServer;
33+
import net.minecraft.util.math.BlockPos;
34+
import net.minecraft.world.NextTickListEntry;
35+
import net.minecraft.world.WorldServer;
36+
37+
public class NextTickListEntryStorage extends AbstractExtendStorage {
38+
39+
private Path file = Path.of("ticklistEntries.json");
40+
41+
@Override
42+
public void onServerSavestate(MinecraftServer server, int index, Path target, Path current) {
43+
Gson gson = new GsonBuilder().registerTypeAdapter(NextTickListEntry.class, new NextTickListEntrySerializer()).setPrettyPrinting().create();
44+
WorldServer[] worlds = server.worlds;
45+
46+
Path path = current.resolve(SavestateHandlerServer.storageDir).resolve(file);
47+
48+
JsonObject dimensionJson = new JsonObject();
49+
for (int i = 0; i < worlds.length; i++) {
50+
int dimension = getDimension(i);
51+
WorldServer world = worlds[i];
52+
WorldServerDuck worldserverDuck = (WorldServerDuck) world;
53+
54+
JsonArray tickListJson = new JsonArray();
55+
56+
Set<NextTickListEntry> tickListEntries = worldserverDuck.getTickListEntriesHashSet();
57+
for (NextTickListEntry nextTickListEntry : tickListEntries) {
58+
tickListJson.add(gson.toJsonTree(nextTickListEntry));
59+
}
60+
61+
dimensionJson.add(Integer.toString(dimension), tickListJson);
62+
}
63+
64+
OutputStream out = null;
65+
try {
66+
out = Files.newOutputStream(path);
67+
Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
68+
writer.write(gson.toJson(dimensionJson));
69+
writer.close();
70+
} catch (IOException e) {
71+
e.printStackTrace();
72+
return;
73+
}
74+
}
75+
76+
@Override
77+
public void onServerLoadstate(MinecraftServer server, int index, Path target, Path current) {
78+
Gson gson = new GsonBuilder().registerTypeAdapter(NextTickListEntry.class, new NextTickListEntryDeserializer()).create();
79+
WorldServer[] worlds = server.worlds;
80+
81+
Path path = current.resolve(SavestateHandlerServer.storageDir).resolve(file);
82+
83+
InputStream in = null;
84+
try {
85+
in = Files.newInputStream(path);
86+
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
87+
JsonReader jsonreader = gson.newJsonReader(reader);
88+
89+
reader.close();
90+
} catch (IOException e) {
91+
e.printStackTrace();
92+
return;
93+
}
94+
95+
JsonObject dimensionJson = new JsonObject();
96+
for (int i = 0; i < worlds.length; i++) {
97+
int dimension = getDimension(i);
98+
WorldServer world = worlds[i];
99+
WorldServerDuck worldserverDuck = (WorldServerDuck) world;
100+
101+
JsonArray tickListJson = new JsonArray();
102+
103+
Set<NextTickListEntry> tickListEntries = worldserverDuck.getTickListEntriesHashSet();
104+
for (NextTickListEntry nextTickListEntry : tickListEntries) {
105+
tickListJson.add(gson.toJsonTree(nextTickListEntry));
106+
}
107+
108+
dimensionJson.add(Integer.toString(dimension), tickListJson);
109+
}
110+
}
111+
112+
private int getDimension(int index) {
113+
switch (index) {
114+
case 0:
115+
return 0;
116+
case 1:
117+
return -1;
118+
case 2:
119+
return 1;
120+
default:
121+
return index - 1;
122+
}
123+
}
124+
125+
public class NextTickListEntrySerializer implements JsonSerializer<NextTickListEntry> {
126+
127+
@Override
128+
public JsonElement serialize(NextTickListEntry src, Type typeOfSrc, JsonSerializationContext context) {
129+
JsonObject obj = new JsonObject();
130+
131+
long tickEntryId = ((AccessorNextTickListEntry) src).getTickEntryID();
132+
int priority = src.priority;
133+
int block = Block.getIdFromBlock(src.getBlock());
134+
long blockPos = src.position.toLong();
135+
long scheduledTime = src.scheduledTime;
136+
137+
obj.addProperty("tickEntryId", tickEntryId);
138+
obj.addProperty("block", block);
139+
obj.addProperty("scheduledTime", scheduledTime);
140+
obj.addProperty("blockPos", blockPos);
141+
obj.addProperty("priority", priority);
142+
return obj;
143+
}
144+
145+
}
146+
147+
public class NextTickListEntryDeserializer implements JsonDeserializer<NextTickListEntry> {
148+
149+
@Override
150+
public NextTickListEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
151+
NextTickListEntry entry = null;
152+
if (json.isJsonObject()) {
153+
JsonObject jsonObject = (JsonObject) json;
154+
Block block = Block.getBlockById(jsonObject.get("block").getAsInt());
155+
long scheduledTime = jsonObject.get("scheduledTime").getAsLong();
156+
BlockPos blockPos = BlockPos.fromLong(jsonObject.get("blockPos").getAsLong());
157+
int priority = jsonObject.get("priority").getAsInt();
158+
159+
entry = new NextTickListEntry(blockPos, block);
160+
entry.setScheduledTime(scheduledTime);
161+
entry.setPriority(priority);
162+
} else {
163+
throw new JsonParseException("Not a json object");
164+
}
165+
return entry;
166+
}
167+
}
168+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.minecrafttas.tasmod.savestates.storage;
2+
/**
3+
* Package for extending the vanilla storage.
4+
*
5+
* Some things do not get stored by the vanilla storage,
6+
* causing discrepancies for savestates
7+
*
8+
*/

src/main/resources/tasmod.mixin.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
"events.MixinEntityPlayerMP",
2020

2121
// Fixing forge and vanilla stuff
22-
"fixes.MixinDragonFightManager"
22+
"fixes.MixinDragonFightManager",
23+
24+
"storage.AccessorNextTickListEntry"
2325
],
2426
"client": [
2527
// General

0 commit comments

Comments
 (0)