From a05ae2e550ee637554d8222872bbf70d41ee5f38 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 28 May 2016 08:37:16 +1000 Subject: [PATCH] Various fixes for VS / WE --- .../fawe/bukkit/wrapper/AsyncBlock.java | 6 +- .../fawe/bukkit/wrapper/AsyncBlockState.java | 2 +- .../fawe/bukkit/wrapper/AsyncWorld.java | 4 +- .../com/thevoxelbox/voxelsniper/Sniper.java | 4 ++ .../fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java | 25 ++++++++- core/src/main/java/com/boydti/fawe/Fawe.java | 4 ++ .../boydti/fawe/example/CharFaweChunk.java | 4 +- .../fawe/object/ChangeSetFaweQueue.java | 6 +- .../com/boydti/fawe/object/FawePlayer.java | 36 +++++++++++- .../com/boydti/fawe/object/FaweQueue.java | 23 ++++++++ .../regions/general/PlotSquaredFeature.java | 2 +- .../java/com/boydti/fawe/util/SetQueue.java | 39 +++++++++++++ .../java/com/sk89q/worldedit/EditSession.java | 32 +++++------ .../com/sk89q/worldedit/LocalSession.java | 2 + .../extension/platform/CommandManager.java | 14 +++-- .../extension/platform/PlatformManager.java | 56 +++++++++++++------ 16 files changed, 207 insertions(+), 52 deletions(-) diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java index 6891514e..dc5f856d 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java @@ -34,7 +34,7 @@ public class AsyncBlock implements Block { @Override public byte getData() { - return (byte) (queue.getCombinedId4Data(x, y, z) & 0xF); + return (byte) (queue.getCombinedId4Data(x, y, z, 0) & 0xF); } @Override @@ -54,12 +54,12 @@ public class AsyncBlock implements Block { @Override public Material getType() { - return Material.getMaterial(queue.getCombinedId4Data(x, y, z) >> 4); + return Material.getMaterial(queue.getCombinedId4Data(x, y, z, 0) >> 4); } @Override public int getTypeId() { - return queue.getCombinedId4Data(x, y, z) >> 4; + return queue.getCombinedId4Data(x, y, z, 0) >> 4; } @Override diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java index 97b07366..a147da51 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java @@ -22,7 +22,7 @@ public class AsyncBlockState implements BlockState { public AsyncBlockState(AsyncBlock block) { this.block = block; - int combined = block.queue.getCombinedId4Data(block.x, block.y, block.z); + int combined = block.queue.getCombinedId4Data(block.x, block.y, block.z, 0); this.id = (short) (combined >> 4); this.data = (byte) (combined & 0xF); if (FaweCache.hasNBT(id)) { diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java index 1bfc4f12..273766a5 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java @@ -113,7 +113,7 @@ public class AsyncWorld implements World { @Override @Deprecated public int getBlockTypeIdAt(int x, int y, int z) { - return queue.getCombinedId4Data(x, y, z) >> 4; + return queue.getCombinedId4Data(x, y, z, 0) >> 4; } @Override @@ -125,7 +125,7 @@ public class AsyncWorld implements World { @Override public int getHighestBlockYAt(int x, int z) { for (int y = 255; y >= 0; y--) { - if (queue.getCombinedId4Data(x, y, z) != 0) { + if (queue.getCombinedId4Data(x, y, z, 0) != 0) { return y; } } diff --git a/bukkit0/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java b/bukkit0/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java index 9610eadd..f4e34234 100644 --- a/bukkit0/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java +++ b/bukkit0/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java @@ -398,7 +398,11 @@ public class Sniper { FaweChangeSet changeSet = changeQueue.getChangeSet(); FawePlayer fp = FawePlayer.wrap(getPlayer()); LocalSession session = fp.getSession(); + baseQueue.enqueue(); session.remember(changeSet.toEditSession(fp.getPlayer())); + changeQueue.flush(); + com.sk89q.worldedit.world.World worldEditWorld = fp.getWorld(); + changeQueue.setChangeSet(Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(worldEditWorld, fp.getUUID()) : new MemoryOptimizedHistory(worldEditWorld)); } } diff --git a/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java b/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java index 3ebfad15..40f05ea5 100644 --- a/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java +++ b/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java @@ -210,7 +210,30 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0 0) { + ChunkSection section = sections[i1 >> 4]; + if (section != null) { + section.a(x, i1 & 15, z, l); + } + } + --i1; + } while (i1 > 0 && l > 0); + } + } + } if (((bc.getTotalRelight() == 0) && mode == RelightMode.MINIMAL)) { return true; } diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 88fe4e5b..26fec2ac 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -395,6 +395,10 @@ public class Fawe { return this.thread; } + public boolean isMainThread() { + return Thread.currentThread() == thread; + } + /** * Sets the main thread to the current thread * @return diff --git a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java index 385cc413..9767fe2e 100644 --- a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java @@ -188,8 +188,10 @@ public abstract class CharFaweChunk extends FaweChunk { char[] vs = this.ids[i]; if (vs == null) { vs = this.ids[i] = new char[4096]; + this.count[i]++; + } else if (vs[j] == 0) { + this.count[i]++; } - this.count[i]++; switch (id) { case 0: this.air[i]++; diff --git a/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java b/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java index 1d53dda7..96ccf7aa 100644 --- a/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java @@ -7,7 +7,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BaseBiome; public class ChangeSetFaweQueue extends DelegateFaweQueue { - private final FaweChangeSet set; + private FaweChangeSet set; public ChangeSetFaweQueue(FaweChangeSet set, FaweQueue parent) { super(parent); @@ -18,6 +18,10 @@ public class ChangeSetFaweQueue extends DelegateFaweQueue { return set; } + public void setChangeSet(FaweChangeSet set) { + this.set = set; + } + @Override public boolean setBlock(int x, int y, int z, short id, byte data) { if (super.setBlock(x, y, z, id, data)) { diff --git a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java index 070e05fe..3e4c2015 100644 --- a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -28,7 +28,6 @@ import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -394,4 +393,39 @@ public abstract class FawePlayer { public EditSession getNewEditSession() { return WorldEdit.getInstance().getEditSessionFactory().getEditSession(getWorld(), -1, getPlayer()); } + + public boolean runIfFree(Runnable run) { + if (getMeta("fawe_action") != null) { + return false; + } + setMeta("fawe_action", true); + try { + run.run(); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + deleteMeta("fawe_action"); + } + return true; + } + + public boolean runAsyncIfFree(final Runnable run) { + if (getMeta("fawe_action") != null) { + return false; + } + setMeta("fawe_action", true); + TaskManager.IMP.async(new Runnable() { + @Override + public void run() { + try { + run.run(); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + deleteMeta("fawe_action"); + } + } + }); + return true; + } } diff --git a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java index dcfac3bf..f9318242 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -2,10 +2,12 @@ package com.boydti.fawe.object; import com.boydti.fawe.Fawe; import com.boydti.fawe.config.BBC; +import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.SetQueue; +import com.boydti.fawe.util.TaskManager; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.world.biome.BaseBiome; @@ -13,6 +15,7 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.atomic.AtomicBoolean; public abstract class FaweQueue { @@ -189,6 +192,26 @@ public abstract class FaweQueue { public abstract int size(); + /** + * Lock the thread until the queue is empty + */ + public void flush() { + if (size() > 0) { + if (Fawe.get().isMainThread()) { + SetQueue.IMP.flush(this); + } else { + final AtomicBoolean running = new AtomicBoolean(true); + addNotifyTask(new Runnable() { + @Override + public void run() { + TaskManager.IMP.notify(running); + } + }); + TaskManager.IMP.wait(running, Settings.QUEUE_DISCARD_AFTER); + } + } + } + public void enqueue() { SetQueue.IMP.enqueue(this); } diff --git a/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java b/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java index 4226446c..64b82f43 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java @@ -24,7 +24,7 @@ public class PlotSquaredFeature extends FaweMaskManager { final HashSet regions = WEManager.getMask(pp); if (regions.size() == 0) { Plot plot = pp.getCurrentPlot(); - if (plot.isOwner(pp.getUUID())) { + if (plot != null && plot.isOwner(pp.getUUID())) { System.out.println("INVALID MASK? " + WEManager.getMask(pp) + " | " + plot + " | " + pp.getName()); } return null; diff --git a/core/src/main/java/com/boydti/fawe/util/SetQueue.java b/core/src/main/java/com/boydti/fawe/util/SetQueue.java index eb5e281a..f86382c4 100644 --- a/core/src/main/java/com/boydti/fawe/util/SetQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/SetQueue.java @@ -175,6 +175,45 @@ public class SetQueue { return queue; } + public void flush(FaweQueue queue) { + SET_TASK.value1 = Long.MAX_VALUE; + SET_TASK.value2 = queue; + if (SET_TASK.value2 == null) { + return; + } + if (Thread.currentThread() != Fawe.get().getMainThread()) { + throw new IllegalStateException("Must be flushed on the main thread!"); + } + // Disable the async catcher as it can't discern async vs parallel + SET_TASK.value2.startSet(true); + try { + if (Settings.PARALLEL_THREADS <= 1) { + SET_TASK.run(); + } else { + ArrayList threads = new ArrayList(); + for (int i = 0; i < Settings.PARALLEL_THREADS; i++) { + threads.add(new Thread(SET_TASK)); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + try { + thread.join(); + } catch (InterruptedException e) { + MainUtil.handleError(e); + } + } + } + } catch (Throwable e) { + MainUtil.handleError(e); + } finally { + // Enable it again (note that we are still on the main thread) + SET_TASK.value2.endSet(true); + dequeue(queue); + } + } + public FaweQueue getNextQueue() { while (activeQueues.size() > 0) { FaweQueue queue = activeQueues.peek(); diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index e156ea63..e0aba620 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -396,7 +396,6 @@ public class EditSession implements Extent { public boolean cancel() { // Cancel this if (primaryExtent != null && queue != null) { - System.out.println("CANCEL"); try { WEManager.IMP.cancelEdit(primaryExtent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); } catch (Throwable ignore) {} @@ -965,27 +964,24 @@ public class EditSession implements Extent { Operations.completeBlindly(commit()); // Enqueue it if (queue != null && queue.size() > 0) { - SetQueue.IMP.enqueue(queue); + queue.enqueue(); } if (changeSet != null) { if (Settings.COMBINE_HISTORY_STAGE && queue.size() > 0) { - final AtomicBoolean running = new AtomicBoolean(true); - queue.addNotifyTask(new Runnable() { - @Override - public void run() { - TaskManager.IMP.async(new Runnable() { - @Override - public void run() { - changeSet.flush(); - TaskManager.IMP.notify(running); - } - }); - } - }); - TaskManager.IMP.wait(running, Settings.QUEUE_DISCARD_AFTER); - } else { - changeSet.flush(); + if (Fawe.get().isMainThread()) { + SetQueue.IMP.flush(queue); + } else { + final AtomicBoolean running = new AtomicBoolean(true); + queue.addNotifyTask(new Runnable() { + @Override + public void run() { + TaskManager.IMP.notify(running); + } + }); + TaskManager.IMP.wait(running, Settings.QUEUE_DISCARD_AFTER); + } } + changeSet.flush(); } } diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index a418a340..0f5d8607 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -200,6 +200,8 @@ public class LocalSession { if (editSession == null || editSession.getChangeSet() == null) { return; } + // It should have already been flushed, but just in case! + editSession.flushQueue(); if (Settings.STORE_HISTORY_ON_DISK) { MAX_HISTORY_SIZE = Integer.MAX_VALUE; } diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index f7ee1f23..2494a980 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -295,12 +295,14 @@ public final class CommandManager { } if (fp != null) { fp.deleteMeta("fawe_action"); - final long time = System.currentTimeMillis() - start; - if (time > 0) { - BBC.ACTION_COMPLETE.send(actor, (time / 50d)); - ChangeSet fcs = editSession.getChangeSet(); - if (fcs != null && fcs instanceof FaweStreamChangeSet) { - MainUtil.sendCompressedMessage((FaweStreamChangeSet) fcs, editSession.getActor()); + if (editSession != null) { + final long time = System.currentTimeMillis() - start; + if (time > 0) { + BBC.ACTION_COMPLETE.send(actor, (time / 1000d)); + ChangeSet fcs = editSession.getChangeSet(); + if (fcs != null && fcs instanceof FaweStreamChangeSet) { + MainUtil.sendCompressedMessage((FaweStreamChangeSet) fcs, editSession.getActor()); + } } } } diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index a431975e..0a02c40f 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.platform; import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.MainUtil; import com.sk89q.worldedit.LocalConfiguration; @@ -335,13 +336,13 @@ public class PlatformManager { // making changes to the world Actor actor = createProxyActor(event.getCause()); try { - Location location = event.getLocation(); + final Location location = event.getLocation(); Vector vector = location.toVector(); // At this time, only handle interaction from players if (actor instanceof Player) { - Player player = (Player) actor; - LocalSession session = worldEdit.getSessionManager().get(actor); + final Player player = (Player) actor; + final LocalSession session = worldEdit.getSessionManager().get(actor); if (event.getType() == Interaction.HIT) { if (player.getItemInHand() == getConfiguration().wandItem) { @@ -362,7 +363,6 @@ public class PlatformManager { event.setCancelled(true); return; } - if (player.isHoldingPickAxe() && session.hasSuperPickAxe()) { final BlockTool superPickaxe = session.getSuperPickaxe(); if (superPickaxe != null && superPickaxe.canUse(player)) { @@ -370,15 +370,19 @@ public class PlatformManager { return; } } - - Tool tool = session.getTool(player.getItemInHand()); + final Tool tool = session.getTool(player.getItemInHand()); if (tool != null && tool instanceof DoubleActionBlockTool) { if (tool.canUse(player)) { - ((DoubleActionBlockTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); + FawePlayer fp = FawePlayer.wrap(player); + fp.runAsyncIfFree(new Runnable() { + @Override + public void run() { + ((DoubleActionBlockTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); + } + }); event.setCancelled(true); } } - } else if (event.getType() == Interaction.OPEN) { if (player.getItemInHand() == getConfiguration().wandItem) { if (!session.isToolControlEnabled()) { @@ -398,10 +402,16 @@ public class PlatformManager { return; } - Tool tool = session.getTool(player.getItemInHand()); + final Tool tool = session.getTool(player.getItemInHand()); if (tool != null && tool instanceof BlockTool) { if (tool.canUse(player)) { - ((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); + FawePlayer fp = FawePlayer.wrap(player); + fp.runAsyncIfFree(new Runnable() { + @Override + public void run() { + ((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); + } + }); event.setCancelled(true); } } @@ -424,7 +434,7 @@ public class PlatformManager { public void handlePlayerInput(PlayerInputEvent event) { // Create a proxy actor with a potentially different world for // making changes to the world - Player player = createProxyActor(event.getPlayer()); + final Player player = createProxyActor(event.getPlayer()); try { switch (event.getInputType()) { case PRIMARY: { @@ -448,12 +458,18 @@ public class PlatformManager { return; } - LocalSession session = worldEdit.getSessionManager().get(player); + final LocalSession session = worldEdit.getSessionManager().get(player); - Tool tool = session.getTool(player.getItemInHand()); + final Tool tool = session.getTool(player.getItemInHand()); if (tool != null && tool instanceof DoubleActionTraceTool) { if (tool.canUse(player)) { - ((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session); + FawePlayer fp = FawePlayer.wrap(player); + fp.runAsyncIfFree(new Runnable() { + @Override + public void run() { + ((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session); + } + }); event.setCancelled(true); return; } @@ -480,12 +496,18 @@ public class PlatformManager { return; } - LocalSession session = worldEdit.getSessionManager().get(player); + final LocalSession session = worldEdit.getSessionManager().get(player); - Tool tool = session.getTool(player.getItemInHand()); + final Tool tool = session.getTool(player.getItemInHand()); if (tool != null && tool instanceof TraceTool) { if (tool.canUse(player)) { - ((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session); + FawePlayer fp = FawePlayer.wrap(player); + fp.runAsyncIfFree(new Runnable() { + @Override + public void run() { + ((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session); + } + }); event.setCancelled(true); return; }