From 3a050fba3b5ad28ab5539ecc18a2e94aab4bcabd Mon Sep 17 00:00:00 2001 From: IronApollo Date: Fri, 21 Feb 2020 18:26:43 -0500 Subject: [PATCH 1/4] Fix immediate crash for some users --- worldedit-core/src/main/java/com/boydti/fawe/Fawe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index a394cf03c..ec7b9fd35 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -360,7 +360,7 @@ public class Fawe { } String arch = System.getenv("PROCESSOR_ARCHITECTURE"); String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432"); - boolean x86OS = !(arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64")); + boolean x86OS = arch == null ? true : !(arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64")); boolean x86JVM = System.getProperty("sun.arch.data.model").equals("32"); if (x86OS != x86JVM) { debug("====== UPGRADE TO 64-BIT JAVA ======"); From 0d18b153933291178929caabd1218c77827415f4 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Sat, 22 Feb 2020 07:07:40 -0800 Subject: [PATCH 2/4] Workaround for replacing PlayerChunkMap#visibleChunks field I run a fork of paper which replaces the visibleChunks and updatingChunks field for gc performance reasons - visibleChunks is updated via cloning updatingChunks, and at high chunk counts this causes gc issues due to the humongous allocation. Unfortunately the only solution is to not clone the map - which is why the field is removed. Instead of BukkitAdapter#getPlayerChunk using the visibleChunks field, it now uses a MethodHandle for PlayerChunkMap#getVisibleChunk. This method is present on spigot & paper (only protected on spigot - which is why reflection is required), and I preserve the same thread-safety it provides in my fork - so this solution will not break compatibility with craftbukkit, spigot, and paper. --- .../adapter/mc1_15_2/BukkitAdapter_1_15_2.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java index e42b624fd..4e67ef329 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java @@ -12,6 +12,10 @@ import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; import java.util.concurrent.locks.ReentrantLock; import net.jpountz.util.UnsafeUtils; import net.minecraft.server.v1_15_R1.*; @@ -40,6 +44,8 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter { private final static Field fieldDirtyCount; private final static Field fieldDirtyBits; + private final static MethodHandle methodGetVisibleChunk; + private static final int CHUNKSECTION_BASE; private static final int CHUNKSECTION_SHIFT; @@ -66,6 +72,10 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter { fieldDirtyBits = PlayerChunk.class.getDeclaredField("r"); fieldDirtyBits.setAccessible(true); + Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class); + declaredGetVisibleChunk.setAccessible(true); + methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk); + Field tmp = DataPaletteBlock.class.getDeclaredField("j"); ReflectionUtils.setAccessibleNonFinal(tmp); fieldLock = tmp; @@ -136,8 +146,11 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter { public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int cx, final int cz) { PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap; - PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz)); - return playerChunk; + try { + return (PlayerChunk)methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz)); + } catch (Throwable thr) { + throw new RuntimeException(thr); + } } public static void sendChunk(WorldServer nmsWorld, int X, int Z, int mask) { From 14ac3205ce3ce81f7ebedf5b8b0b39ee13d1e275 Mon Sep 17 00:00:00 2001 From: IronApollo Date: Sat, 22 Feb 2020 21:02:12 -0500 Subject: [PATCH 3/4] Check for PlotSquared before initializing the feature class Some users are experiencing issues during startup with FAWE not finding PlotSquared resulting in errors. --- .../src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java | 1 + 1 file changed, 1 insertion(+) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index fb72c84de..31eb2c686 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -325,6 +325,7 @@ public class FaweBukkit implements IFawe, Listener { } private void setupPlotSquared() { + if(this.plugin.getServer().getPluginManager().getPlugin("PlotSquared") == null) return; WEManager.IMP.managers.add(new com.boydti.fawe.bukkit.regions.plotsquared.PlotSquaredFeature()); log.debug("Plugin 'PlotSquared' found. Using it now."); } From f6675160f176e2d8bbcdf54bed832c6608c36058 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Sat, 22 Feb 2020 20:11:23 -0800 Subject: [PATCH 4/4] Also target 1.15 & 1.14 adapters --- .../adapter/mc1_14/BukkitAdapter_1_14.java | 17 +++++++++++++---- .../adapter/mc1_15/BukkitAdapter_1_15.java | 16 ++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java index 09f174e1d..841525974 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java @@ -12,6 +12,9 @@ import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; import java.util.concurrent.locks.ReentrantLock; import net.jpountz.util.UnsafeUtils; import net.minecraft.server.v1_14_R1.Block; @@ -52,6 +55,8 @@ public final class BukkitAdapter_1_14 extends NMSAdapter { private final static Field fieldDirtyCount; private final static Field fieldDirtyBits; + private final static MethodHandle methodGetVisibleChunk; + private static final int CHUNKSECTION_BASE; private static final int CHUNKSECTION_SHIFT; @@ -78,6 +83,10 @@ public final class BukkitAdapter_1_14 extends NMSAdapter { fieldDirtyBits = PlayerChunk.class.getDeclaredField("r"); fieldDirtyBits.setAccessible(true); + Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class); + declaredGetVisibleChunk.setAccessible(true); + methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk); + { Field tmp; try { @@ -154,11 +163,11 @@ public final class BukkitAdapter_1_14 extends NMSAdapter { public static PlayerChunk getPlayerChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, final int cx, final int cz) { PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap; - PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz)); - if (playerChunk == null) { - return null; + try { + return (PlayerChunk)methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz)); + } catch (Throwable thr) { + throw new RuntimeException(thr); } - return playerChunk; } public static void sendChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, int X, int Z, int mask) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java index 0496cc979..98c8acac2 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java @@ -12,6 +12,9 @@ import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; import java.util.concurrent.locks.ReentrantLock; import net.jpountz.util.UnsafeUtils; import net.minecraft.server.v1_15_R1.*; @@ -40,6 +43,8 @@ public final class BukkitAdapter_1_15 extends NMSAdapter { private final static Field fieldDirtyCount; private final static Field fieldDirtyBits; + private final static MethodHandle methodGetVisibleChunk; + private static final int CHUNKSECTION_BASE; private static final int CHUNKSECTION_SHIFT; @@ -66,6 +71,10 @@ public final class BukkitAdapter_1_15 extends NMSAdapter { fieldDirtyBits = PlayerChunk.class.getDeclaredField("r"); fieldDirtyBits.setAccessible(true); + Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class); + declaredGetVisibleChunk.setAccessible(true); + methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk); + Field tmp = DataPaletteBlock.class.getDeclaredField("j"); ReflectionUtils.setAccessibleNonFinal(tmp); fieldLock = tmp; @@ -135,8 +144,11 @@ public final class BukkitAdapter_1_15 extends NMSAdapter { public static PlayerChunk getPlayerChunk(net.minecraft.server.v1_15_R1.WorldServer nmsWorld, final int cx, final int cz) { PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap; - PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz)); - return playerChunk; + try { + return (PlayerChunk)methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz)); + } catch (Throwable thr) { + throw new RuntimeException(thr); + } } public static void sendChunk(net.minecraft.server.v1_15_R1.WorldServer nmsWorld, int X, int Z, int mask) {