diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 956d874a1..39361de84 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -54,6 +54,7 @@ public class BukkitChunkHolder> extends ChunkHolder { int Z = getZ(); Chunk nmsChunk = extent.ensureLoaded(X, Z); + int bitMask = 0; try { synchronized (nmsChunk) { ChunkSection[] sections = nmsChunk.getSections(); @@ -62,6 +63,9 @@ public class BukkitChunkHolder> extends ChunkHolder { for (int layer = 0; layer < 16; layer++) { if (!set.hasSection(layer)) continue; + + bitMask |= 1 << layer; + char[] setArr = set.blocks[layer]; ChunkSection newSection; ChunkSection existingSection = sections[layer]; @@ -84,10 +88,10 @@ public class BukkitChunkHolder> extends ChunkHolder { synchronized (get) { ChunkSection getSection; if (get.nmsChunk != nmsChunk) { + if (get.nmsChunk != null) System.out.println("chunk doesn't match"); get.nmsChunk = nmsChunk; get.sections = null; get.reset(); - System.out.println("chunk doesn't match"); } else { getSection = get.getSections()[layer]; if (getSection != existingSection) { @@ -118,6 +122,15 @@ public class BukkitChunkHolder> extends ChunkHolder { } } } finally { + if (bitMask != 0) { + // Set Modified + nmsChunk.f(true); + nmsChunk.mustSave = true; + nmsChunk.markDirty(); + // send to player + extent.sendChunk(X, Z, bitMask); + } + extent.returnToPool(this); } /* diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 70971042c..debf5283c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -29,6 +29,8 @@ import net.minecraft.server.v1_13_R2.DataPaletteBlock; import net.minecraft.server.v1_13_R2.DataPaletteLinear; import net.minecraft.server.v1_13_R2.GameProfileSerializer; import net.minecraft.server.v1_13_R2.IBlockData; +import net.minecraft.server.v1_13_R2.PlayerChunk; +import net.minecraft.server.v1_13_R2.PlayerChunkMap; import net.minecraft.server.v1_13_R2.WorldServer; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; @@ -42,6 +44,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Supplier; import sun.misc.Unsafe; @@ -106,6 +109,9 @@ public class BukkitQueue extends SimpleCharQueueExtent { public final static Field fieldTickingBlockCount; public final static Field fieldNonEmptyBlockCount; + private final static Field fieldDirtyCount; + private final static Field fieldDirtyBits; + private static final int CHUNKSECTION_BASE; private static final int CHUNKSECTION_SHIFT; @@ -127,6 +133,11 @@ public class BukkitQueue extends SimpleCharQueueExtent { fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount.setAccessible(true); + fieldDirtyCount = PlayerChunk.class.getDeclaredField("dirtyCount"); + fieldDirtyCount.setAccessible(true); + fieldDirtyBits = PlayerChunk.class.getDeclaredField("h"); + fieldDirtyBits.setAccessible(true); + { Field tmp = null; try { @@ -217,6 +228,50 @@ public class BukkitQueue extends SimpleCharQueueExtent { return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); } + private PlayerChunk getPlayerChunk(final int cx, final int cz) { + final PlayerChunkMap chunkMap = nmsWorld.getPlayerChunkMap(); + final PlayerChunk playerChunk = chunkMap.getChunk(cx, cz); + if (playerChunk == null) { + return null; + } + if (playerChunk.players.isEmpty()) { + return null; + } + return playerChunk; + } + + public boolean sendChunk(final int X, final int Z, final int mask) { + PlayerChunk playerChunk = getPlayerChunk(X, Z); + if (playerChunk == null) { + return false; + } + if (playerChunk.e()) { + TaskManager.IMP.sync(new Supplier() { + @Override + public Object get() { + try { + int dirtyBits = fieldDirtyBits.getInt(playerChunk); + if (dirtyBits == 0) { + nmsWorld.getPlayerChunkMap().a(playerChunk); + } + if (mask == 0) { + dirtyBits = 65535; + } else { + dirtyBits |= mask; + } + + fieldDirtyBits.set(playerChunk, dirtyBits); + fieldDirtyCount.set(playerChunk, 64); + } catch (final IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + }); + } + return true; + } + /* NMS conversion */