From 8fff833e84867393ac14e4f173a65c6769195f5d Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 16 Jul 2023 14:46:26 +0100 Subject: [PATCH] fix: correct reflected fields for chunk needs saving - fixes #4064 --- .../bukkit/listener/ChunkListener.java | 42 ++++++++++------- .../bukkit/listener/SingleWorldListener.java | 47 +++++++++---------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java index 9af09527c..763263e99 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java @@ -26,6 +26,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; +import com.plotsquared.core.util.ReflectionUtils; import com.plotsquared.core.util.ReflectionUtils.RefClass; import com.plotsquared.core.util.ReflectionUtils.RefField; import com.plotsquared.core.util.ReflectionUtils.RefMethod; @@ -64,9 +65,11 @@ public class ChunkListener implements Listener { private final PlotAreaManager plotAreaManager; private final int version; + private RefMethod methodSetUnsaved; private RefMethod methodGetHandleChunk; private RefMethod methodGetHandleWorld; - private RefField mustSave; + private RefField mustNotSave; + private Object objChunkStatusFull = null; /* private RefMethod methodGetFullChunk; private RefMethod methodGetBukkitChunk; @@ -79,7 +82,6 @@ public class ChunkListener implements Listener { */ private Chunk lastChunk; private boolean ignoreUnload = false; - private boolean isTrueForNotSave = true; @Inject public ChunkListener(final @NonNull PlotAreaManager plotAreaManager) { @@ -90,22 +92,27 @@ public class ChunkListener implements Listener { } try { RefClass classCraftWorld = getRefClass("{cb}.CraftWorld"); - this.methodGetHandleWorld = classCraftWorld.getMethod("getHandle"); RefClass classCraftChunk = getRefClass("{cb}.CraftChunk"); - this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle"); + ReflectionUtils.RefClass classChunkAccess = getRefClass("net.minecraft.world.level.chunk.IChunkAccess"); + this.methodSetUnsaved = classChunkAccess.getMethod("a", boolean.class); + try { + this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle"); + } catch (NoSuchMethodException ignored) { + try { + RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus"); + this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null); + this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass()); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } try { if (version < 17) { RefClass classChunk = getRefClass("{nms}.Chunk"); - if (version == 13) { - this.mustSave = classChunk.getField("mustSave"); - this.isTrueForNotSave = false; - } else { - this.mustSave = classChunk.getField("mustNotSave"); - } + this.mustNotSave = classChunk.getField("mustNotSave"); } else { RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.Chunk"); - this.mustSave = classChunk.getField("mustNotSave"); - + this.mustNotSave = classChunk.getField("mustNotSave"); } } catch (NoSuchFieldException e) { e.printStackTrace(); @@ -167,10 +174,13 @@ public class ChunkListener implements Listener { if (safe && shouldSave(world, chunk.getX(), chunk.getZ())) { return false; } - Object c = this.methodGetHandleChunk.of(chunk).call(); - RefField.RefExecutor field = this.mustSave.of(c); - if ((Boolean) field.get() != isTrueForNotSave) { - field.set(isTrueForNotSave); + Object c = objChunkStatusFull != null + ? this.methodGetHandleChunk.of(chunk).call(objChunkStatusFull) + : this.methodGetHandleChunk.of(chunk).call(); + RefField.RefExecutor field = this.mustNotSave.of(c); + methodSetUnsaved.of(c).call(false); + if (!((Boolean) field.get())) { + field.set(true); if (chunk.isLoaded()) { ignoreUnload = true; chunk.unload(false); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java index deb14ed7b..34184659e 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java @@ -31,45 +31,39 @@ import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkEvent; import org.bukkit.event.world.ChunkLoadEvent; -import java.lang.reflect.Field; import java.lang.reflect.Method; import static com.plotsquared.core.util.ReflectionUtils.getRefClass; public class SingleWorldListener implements Listener { - private final Method methodGetHandleChunk; - private Field shouldSave = null; + private final Method methodSetUnsaved; + private Method methodGetHandleChunk; + private Object objChunkStatusFull = null; public SingleWorldListener() throws Exception { ReflectionUtils.RefClass classCraftChunk = getRefClass("{cb}.CraftChunk"); - this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod(); + ReflectionUtils.RefClass classChunkAccess = getRefClass("net.minecraft.world.level.chunk.IChunkAccess"); + this.methodSetUnsaved = classChunkAccess.getMethod("a", boolean.class).getRealMethod(); try { - if (PlotSquared.platform().serverVersion()[1] < 17) { - ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk"); - if (PlotSquared.platform().serverVersion()[1] == 13) { - this.shouldSave = classChunk.getField("mustSave").getRealField(); - } else { - this.shouldSave = classChunk.getField("s").getRealField(); - } - } else if (PlotSquared.platform().serverVersion()[1] == 17) { - ReflectionUtils.RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.Chunk"); - this.shouldSave = classChunk.getField("r").getRealField(); - } else if (PlotSquared.platform().serverVersion()[1] == 18) { - ReflectionUtils.RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.IChunkAccess"); - this.shouldSave = classChunk.getField("b").getRealField(); + this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod(); + } catch (NoSuchMethodException ignored) { + try { + ReflectionUtils.RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus"); + this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null); + this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass()).getRealMethod(); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); } - } catch (NoSuchFieldException e) { - e.printStackTrace(); } } public void markChunkAsClean(Chunk chunk) { try { - Object nmsChunk = methodGetHandleChunk.invoke(chunk); - if (shouldSave != null) { - this.shouldSave.set(nmsChunk, false); - } + Object nmsChunk = objChunkStatusFull != null + ? this.methodGetHandleChunk.invoke(chunk, objChunkStatusFull) + : this.methodGetHandleChunk.invoke(chunk); + methodSetUnsaved.invoke(nmsChunk, false); } catch (Throwable e) { e.printStackTrace(); } @@ -85,7 +79,12 @@ public class SingleWorldListener implements Listener { if (!SinglePlotArea.isSinglePlotWorld(name)) { return; } - + int x = event.getChunk().getX(); + int z = event.getChunk().getZ(); + if (x < 16 && x > -16 && z < 16 && z > -16) { + // Allow spawn to generate + return; + } markChunkAsClean(event.getChunk()); }