fix: correct reflected fields for chunk needs saving (#4111)

This commit is contained in:
Jordan 2023-07-24 16:56:46 +01:00 committed by GitHub
parent f6cbb3792f
commit 59be582c28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 40 deletions

View File

@ -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);

View File

@ -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());
}