From e3cbcfbd5ee062e350d4d0adef404e033bfb4223 Mon Sep 17 00:00:00 2001 From: Byron Marohn Date: Sat, 14 Oct 2023 23:11:57 -0700 Subject: [PATCH 1/3] Forcibly mark chunks as needing saving after pasting contents Signed-off-by: Byron Marohn --- .../structures/StructuresAPI.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/main/java/com/playmonumenta/structures/StructuresAPI.java b/src/main/java/com/playmonumenta/structures/StructuresAPI.java index 7e71f25..fa85fe3 100644 --- a/src/main/java/com/playmonumenta/structures/StructuresAPI.java +++ b/src/main/java/com/playmonumenta/structures/StructuresAPI.java @@ -27,6 +27,9 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Deque; import java.util.EnumSet; import java.util.HashMap; @@ -568,6 +571,11 @@ public void run() { return future; } + private static boolean ATTEMPTED_REFLECTION = false; + private static @Nullable Object CHUNK_STATUS_FULL_OBJ = null; + private static @Nullable Method GET_HANDLE_METHOD = null; + private static @Nullable Method SET_UNSAVED_METHOD = null; + /* * Unmarks chunks so that they can be unloaded. (the opposite of markAndLoadChunks) * @@ -585,6 +593,42 @@ public static void unmarkChunksAsync(org.bukkit.World world, Region region) { for (final BlockVector2 chunkCoords : region.getChunks()) { final Consumer consumer = (final Chunk chunk) -> { + // Prior to marking the chunk for unloading, reach into paper internals to make sure the chunk is flagged for saving + // For some reason on 1.19 FAWE is not always marking chunks as needing to save, so sometimes on unload with no player interaction they don't save + if (!ATTEMPTED_REFLECTION) { + // First, cache the reflection results for faster use later. This is only attempted once. + ATTEMPTED_REFLECTION = true; + try { + Class chunkStatusClass = Class.forName("net.minecraft.world.level.chunk.ChunkStatus"); + Field chunkStatusFullField = chunkStatusClass.getDeclaredField("o"); // "FULL" in 1.19.4 + CHUNK_STATUS_FULL_OBJ = chunkStatusFullField.get(null); + GET_HANDLE_METHOD = chunk.getClass().getMethod("getHandle", chunkStatusClass); + Object chunkAccess = GET_HANDLE_METHOD.invoke(chunk, CHUNK_STATUS_FULL_OBJ); + Method SET_UNSAVED_METHOD = chunkAccess.getClass().getMethod("a", boolean.class); // "setUnsaved" in 1.19.4 + SET_UNSAVED_METHOD.invoke(chunkAccess, true); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | NoSuchFieldException | ClassNotFoundException e) { + CHUNK_STATUS_FULL_OBJ = null; + GET_HANDLE_METHOD = null; + SET_UNSAVED_METHOD = null; + plugin.getLogger().warning("Failed to use reflection to access setUnsaved() chunk method. Possibly this is because this is not running on a 1.19+ paper server, in which case you can disregard this warning"); + e.printStackTrace(); + } + } + + // Use the reflection results if they exist to set the chunk as needing to save + if (CHUNK_STATUS_FULL_OBJ != null && GET_HANDLE_METHOD != null && SET_UNSAVED_METHOD != null) { + try { + Object chunkAccess = GET_HANDLE_METHOD.invoke(chunk, CHUNK_STATUS_FULL_OBJ); + SET_UNSAVED_METHOD.invoke(chunkAccess, true); + plugin.getLogger().finer(() -> "Successfully marked chunk at " + chunk.getX() + "," + chunk.getZ() + " as needing saving prior to unloading"); + } catch (InvocationTargetException | IllegalAccessException e) { + GET_HANDLE_METHOD = null; + SET_UNSAVED_METHOD = null; + plugin.getLogger().severe("Failed to use reflection to access setUnsaved() chunk method but it previously worked. This is a bug in this plugin."); + e.printStackTrace(); + } + } + WorldChunkKey key = new WorldChunkKey(world.getUID(), chunk.getChunkKey()); Integer references = CHUNK_TICKET_REFERENCE_COUNT.remove(key); if (references == null || references <= 0) { From a38f8088dfdbaf5095d5eb49d18eee95d80772d1 Mon Sep 17 00:00:00 2001 From: Byron Marohn Date: Sat, 14 Oct 2023 23:15:23 -0700 Subject: [PATCH 2/3] Remove m14 deployment Signed-off-by: Byron Marohn --- build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9ce45d1..e6e64d6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -212,12 +212,10 @@ tasks.create("play-deploy") { put(shadowJar.archiveFile.get().getAsFile(), "/home/epic/play/m8/server_config/plugins") put(shadowJar.archiveFile.get().getAsFile(), "/home/epic/play/m11/server_config/plugins") put(shadowJar.archiveFile.get().getAsFile(), "/home/epic/play/m13/server_config/plugins") - put(shadowJar.archiveFile.get().getAsFile(), "/home/epic/play/m14/server_config/plugins") put(shadowJar.archiveFile.get().getAsFile(), "/home/epic/play/m15/server_config/plugins") execute("cd /home/epic/play/m8/server_config/plugins && rm -f MonumentaStructureManagement.jar && ln -s " + shadowJar.archiveFileName.get() + " MonumentaStructureManagement.jar") execute("cd /home/epic/play/m11/server_config/plugins && rm -f MonumentaStructureManagement.jar && ln -s " + shadowJar.archiveFileName.get() + " MonumentaStructureManagement.jar") execute("cd /home/epic/play/m13/server_config/plugins && rm -f MonumentaStructureManagement.jar && ln -s " + shadowJar.archiveFileName.get() + " MonumentaStructureManagement.jar") - execute("cd /home/epic/play/m14/server_config/plugins && rm -f MonumentaStructureManagement.jar && ln -s " + shadowJar.archiveFileName.get() + " MonumentaStructureManagement.jar") execute("cd /home/epic/play/m15/server_config/plugins && rm -f MonumentaStructureManagement.jar && ln -s " + shadowJar.archiveFileName.get() + " MonumentaStructureManagement.jar") } } From 482fa1892a4968cb3cfe4920d51ede1778d0d7db Mon Sep 17 00:00:00 2001 From: Byron Marohn Date: Sat, 14 Oct 2023 23:22:20 -0700 Subject: [PATCH 3/3] Fix local variable masking global one Signed-off-by: Byron Marohn --- src/main/java/com/playmonumenta/structures/StructuresAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/playmonumenta/structures/StructuresAPI.java b/src/main/java/com/playmonumenta/structures/StructuresAPI.java index fa85fe3..628a6f0 100644 --- a/src/main/java/com/playmonumenta/structures/StructuresAPI.java +++ b/src/main/java/com/playmonumenta/structures/StructuresAPI.java @@ -604,7 +604,7 @@ public static void unmarkChunksAsync(org.bukkit.World world, Region region) { CHUNK_STATUS_FULL_OBJ = chunkStatusFullField.get(null); GET_HANDLE_METHOD = chunk.getClass().getMethod("getHandle", chunkStatusClass); Object chunkAccess = GET_HANDLE_METHOD.invoke(chunk, CHUNK_STATUS_FULL_OBJ); - Method SET_UNSAVED_METHOD = chunkAccess.getClass().getMethod("a", boolean.class); // "setUnsaved" in 1.19.4 + SET_UNSAVED_METHOD = chunkAccess.getClass().getMethod("a", boolean.class); // "setUnsaved" in 1.19.4 SET_UNSAVED_METHOD.invoke(chunkAccess, true); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | NoSuchFieldException | ClassNotFoundException e) { CHUNK_STATUS_FULL_OBJ = null;