From 60152a5b1fc6b177c6d4caccc4b32cecb02f4fe1 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Tue, 1 Nov 2016 23:35:23 +1100 Subject: [PATCH] Various Fix some brush stuff Fix issue with editing on main thread FIx error from misusing AsyncBlock Tweak some messages Add TaskBuilder API --- .../boydti/fawe/bukkit/v0/BukkitQueue_0.java | 57 +- .../fawe/bukkit/wrapper/AsyncBlock.java | 2 +- .../com/boydti/fawe/object/FawePlayer.java | 65 +-- .../com/boydti/fawe/object/Metadatable.java | 60 +++ .../com/boydti/fawe/object/RunnableVal.java | 4 +- .../object/changeset/DiskStorageHistory.java | 7 +- .../fawe/object/changeset/FaweChangeSet.java | 4 +- .../java/com/boydti/fawe/util/ByteArrays.java | 47 -- .../java/com/boydti/fawe/util/MainUtil.java | 6 +- .../com/boydti/fawe/util/TaskManager.java | 3 +- .../boydti/fawe/util/task/DelayedTask.java | 5 + .../boydti/fawe/util/task/ReceiveTask.java | 5 + .../com/boydti/fawe/util/task/ReturnTask.java | 5 + .../java/com/boydti/fawe/util/task/Task.java | 5 + .../boydti/fawe/util/task/TaskBuilder.java | 491 ++++++++++++++++++ .../extension/platform/CommandManager.java | 32 +- .../extension/platform/PlatformManager.java | 3 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 2 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 2 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 2 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 2 +- 21 files changed, 633 insertions(+), 176 deletions(-) create mode 100644 core/src/main/java/com/boydti/fawe/object/Metadatable.java delete mode 100644 core/src/main/java/com/boydti/fawe/util/ByteArrays.java create mode 100644 core/src/main/java/com/boydti/fawe/util/task/DelayedTask.java create mode 100644 core/src/main/java/com/boydti/fawe/util/task/ReceiveTask.java create mode 100644 core/src/main/java/com/boydti/fawe/util/task/ReturnTask.java create mode 100644 core/src/main/java/com/boydti/fawe/util/task/Task.java create mode 100644 core/src/main/java/com/boydti/fawe/util/task/TaskBuilder.java diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index 79a5eb68..a1646046 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -153,7 +153,7 @@ public abstract class BukkitQueue_0 extends NMSMa @Override public World getImpWorld() { - return Bukkit.getWorld(getWorldName()); + return getWorldName() != null ? Bukkit.getWorld(getWorldName()) : null; } @Override @@ -190,23 +190,45 @@ public abstract class BukkitQueue_0 extends NMSMa } private volatile boolean timingsEnabled; + private static boolean alertTimingsChange = true; + private static Field fieldTimingsEnabled; + private static Field fieldAsyncCatcherEnabled; + private static Method methodCheck; + static { + try { + fieldAsyncCatcherEnabled = Class.forName("org.spigotmc.AsyncCatcher").getField("enabled"); + fieldAsyncCatcherEnabled.setAccessible(true); + } catch (Throwable ignore) {} + try { + fieldTimingsEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled"); + fieldTimingsEnabled.setAccessible(true); + methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled"); + methodCheck.setAccessible(true); + } catch (Throwable ignore){} + } @Override public void startSet(boolean parallel) { ChunkListener.physicsFreeze = true; if (parallel) { try { - Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled"); - fieldEnabled.setAccessible(true); - timingsEnabled = (boolean) fieldEnabled.get(null); - if (timingsEnabled) { - fieldEnabled.set(null, false); - Method methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled"); - methodCheck.setAccessible(true); - methodCheck.invoke(null); + if (fieldAsyncCatcherEnabled != null) { + fieldAsyncCatcherEnabled.set(null, false); } - } catch (Throwable ignore) {} - try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, false); } catch (Throwable ignore) {} + if (fieldTimingsEnabled != null) { + timingsEnabled = (boolean) fieldTimingsEnabled.get(null); + if (timingsEnabled) { + if (alertTimingsChange) { + alertTimingsChange = false; + Fawe.debug("Having `parallel-threads` > 1 interferes with the timings."); + } + fieldTimingsEnabled.set(null, false); + methodCheck.invoke(null); + } + } + } catch (Throwable e) { + e.printStackTrace(); + } } } @@ -214,9 +236,16 @@ public abstract class BukkitQueue_0 extends NMSMa public void endSet(boolean parallel) { ChunkListener.physicsFreeze = false; if (parallel) { - try {Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");fieldEnabled.setAccessible(true);fieldEnabled.set(null, timingsEnabled); - } catch (Throwable ignore) {} - try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, true); } catch (Throwable ignore) {} + try { + if (fieldAsyncCatcherEnabled != null) { + fieldAsyncCatcherEnabled.set(null, true); + } + if (fieldTimingsEnabled != null && timingsEnabled) { + fieldTimingsEnabled.set(null, true); + } + } catch (Throwable e) { + e.printStackTrace(); + } } } } 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 92f1ec37..f9688c34 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 @@ -28,7 +28,7 @@ public class AsyncBlock implements Block { this.world = world; this.queue = queue; this.x = x; - this.y = y; + this.y = y & 0xFF; this.z = z; } 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 1a782f50..e8af4a24 100644 --- a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -37,16 +37,11 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicInteger; -public abstract class FawePlayer { +public abstract class FawePlayer extends Metadatable { public final T parent; private LocalSession session; - /** - * The metadata map. - */ - private volatile ConcurrentHashMap meta; - /** * Wrap some object into a FawePlayer
* - org.bukkit.entity.Player @@ -396,64 +391,6 @@ public abstract class FawePlayer { return this.hasPermission("fawe.bypass"); } - /** - * Set some session only metadata for the player - * @param key - * @param value - * @return previous value - */ - public void setMeta(String key, Object value) { - if (this.meta == null) { - this.meta = new ConcurrentHashMap<>(8, 0.9f, 1); - } - this.meta.put(key, value); - } - - public T getAndSetMeta(String key, T value) { - if (this.meta == null) { - this.meta = new ConcurrentHashMap<>(8, 0.9f, 1); - } - return (T) this.meta.put(key, value); - } - - /** - * Get the metadata for a key. - * @param - * @param key - * @return - */ - public V getMeta(String key) { - if (this.meta != null) { - return (V) this.meta.get(key); - } - return null; - } - - /** - * Get the metadata for a specific key (or return the default provided) - * @param key - * @param def - * @param - * @return - */ - public V getMeta(String key, V def) { - if (this.meta != null) { - V value = (V) this.meta.get(key); - return value == null ? def : value; - } - return def; - } - - /** - * Delete the metadata for a key. - * - metadata is session only - * - deleting other plugin's metadata may cause issues - * @param key - */ - public Object deleteMeta(String key) { - return this.meta == null ? null : this.meta.remove(key); - } - /** * Unregister this player (delets all metadata etc) * - Usually called on logout diff --git a/core/src/main/java/com/boydti/fawe/object/Metadatable.java b/core/src/main/java/com/boydti/fawe/object/Metadatable.java new file mode 100644 index 00000000..0b8f910b --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/Metadatable.java @@ -0,0 +1,60 @@ +package com.boydti.fawe.object; + +import java.util.concurrent.ConcurrentHashMap; + +public class Metadatable { + + private final ConcurrentHashMap meta = new ConcurrentHashMap<>(); + + /** + * Set some session only metadata for the player + * @param key + * @param value + * @return previous value + */ + public void setMeta(String key, Object value) { + this.meta.put(key, value); + } + + public T getAndSetMeta(String key, T value) { + return (T) this.meta.put(key, value); + } + + /** + * Get the metadata for a key. + * @param + * @param key + * @return + */ + public V getMeta(String key) { + if (this.meta != null) { + return (V) this.meta.get(key); + } + return null; + } + + /** + * Get the metadata for a specific key (or return the default provided) + * @param key + * @param def + * @param + * @return + */ + public V getMeta(String key, V def) { + if (this.meta != null) { + V value = (V) this.meta.get(key); + return value == null ? def : value; + } + return def; + } + + /** + * Delete the metadata for a key. + * - metadata is session only + * - deleting other plugin's metadata may cause issues + * @param key + */ + public Object deleteMeta(String key) { + return this.meta == null ? null : this.meta.remove(key); + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/RunnableVal.java b/core/src/main/java/com/boydti/fawe/object/RunnableVal.java index c6862bfe..40d7694c 100644 --- a/core/src/main/java/com/boydti/fawe/object/RunnableVal.java +++ b/core/src/main/java/com/boydti/fawe/object/RunnableVal.java @@ -10,11 +10,11 @@ public abstract class RunnableVal implements Runnable { } @Override - public void run() { + public final void run() { run(this.value); } - public T runAndGet() { + public final T runAndGet() { run(); return value; } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java index a5b84935..5e2e3a32 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java @@ -11,12 +11,7 @@ import com.boydti.fawe.util.MainUtil; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.worldedit.world.World; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.util.HashMap; import java.util.Map; import java.util.UUID; diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java index 0b14337a..02a06acf 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java @@ -296,11 +296,11 @@ public abstract class FaweChangeSet implements ChangeSet { } }; if (mainThread) { - new Thread(run).start(); + run.run(); } else { TaskManager.IMP.async(run); } } }); } -} +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/util/ByteArrays.java b/core/src/main/java/com/boydti/fawe/util/ByteArrays.java deleted file mode 100644 index 85d314eb..00000000 --- a/core/src/main/java/com/boydti/fawe/util/ByteArrays.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.boydti.fawe.util; - -public class ByteArrays { - - public static final byte[] EMPTY_ARRAY = new byte[0]; - - public static void ensureOffsetLength(byte[] a, int offset, int length) - { - ensureOffsetLength(a.length, offset, length); - } - - public static void ensureOffsetLength(int arrayLength, int offset, int length) - { - if (offset < 0) { - throw new ArrayIndexOutOfBoundsException("Offset (" + offset + ") is negative"); - } - if (length < 0) { - throw new IllegalArgumentException("Length (" + length + ") is negative"); - } - if (offset + length > arrayLength) { - throw new ArrayIndexOutOfBoundsException("Last index (" + (offset + length) + ") is greater than array length (" + arrayLength + ")"); - } - } - - public static byte[] grow(byte[] array, int length, int preserve) - { - if (length > array.length) - { - int newLength = (int)Math.max( - Math.min(2L * array.length, 2147483639L), length); - byte[] t = new byte[newLength]; - System.arraycopy(array, 0, t, 0, preserve); - return t; - } - return array; - } - - public static byte[] trim(byte[] array, int length) - { - if (length >= array.length) { - return array; - } - byte[] t = length == 0 ? EMPTY_ARRAY : new byte[length]; - System.arraycopy(array, 0, t, 0, length); - return t; - } -} diff --git a/core/src/main/java/com/boydti/fawe/util/MainUtil.java b/core/src/main/java/com/boydti/fawe/util/MainUtil.java index 15ff1756..65f6db17 100644 --- a/core/src/main/java/com/boydti/fawe/util/MainUtil.java +++ b/core/src/main/java/com/boydti/fawe/util/MainUtil.java @@ -74,11 +74,7 @@ public class MainUtil { } public static void stacktrace() { - try { - int i = 1/0; - } catch (Exception e) { - e.printStackTrace(); - } + new Exception().printStackTrace(); } public static void traverse(Path path, final RunnableVal2 onEach) { diff --git a/core/src/main/java/com/boydti/fawe/util/TaskManager.java b/core/src/main/java/com/boydti/fawe/util/TaskManager.java index 8a78ab80..66226f0b 100644 --- a/core/src/main/java/com/boydti/fawe/util/TaskManager.java +++ b/core/src/main/java/com/boydti/fawe/util/TaskManager.java @@ -275,7 +275,8 @@ public abstract class TaskManager { while (running.get()) { running.wait(timout); if (running.get() && System.currentTimeMillis() - start > Settings.QUEUE.DISCARD_AFTER_MS) { - MainUtil.stacktrace(); + new RuntimeException("FAWE is taking a long time to execute a task (might just be a symptom): ").printStackTrace(); + Fawe.debug("For full debug information use: /fawe threads"); } } } diff --git a/core/src/main/java/com/boydti/fawe/util/task/DelayedTask.java b/core/src/main/java/com/boydti/fawe/util/task/DelayedTask.java new file mode 100644 index 00000000..315349b2 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/task/DelayedTask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.util.task; + +public interface DelayedTask { + int getDelay(T previousResult); +} diff --git a/core/src/main/java/com/boydti/fawe/util/task/ReceiveTask.java b/core/src/main/java/com/boydti/fawe/util/task/ReceiveTask.java new file mode 100644 index 00000000..81268f51 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/task/ReceiveTask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.util.task; + +public interface ReceiveTask { + void run(T previous); +} diff --git a/core/src/main/java/com/boydti/fawe/util/task/ReturnTask.java b/core/src/main/java/com/boydti/fawe/util/task/ReturnTask.java new file mode 100644 index 00000000..4a8f256e --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/task/ReturnTask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.util.task; + +public interface ReturnTask { + T run(); +} diff --git a/core/src/main/java/com/boydti/fawe/util/task/Task.java b/core/src/main/java/com/boydti/fawe/util/task/Task.java new file mode 100644 index 00000000..615237e0 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/task/Task.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.util.task; + +public interface Task { + T run(V previousResult); +} diff --git a/core/src/main/java/com/boydti/fawe/util/task/TaskBuilder.java b/core/src/main/java/com/boydti/fawe/util/task/TaskBuilder.java new file mode 100644 index 00000000..b60aecc5 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/task/TaskBuilder.java @@ -0,0 +1,491 @@ +package com.boydti.fawe.util.task; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.Metadatable; +import com.boydti.fawe.object.RunnableVal; +import com.boydti.fawe.util.SetQueue; +import com.boydti.fawe.util.TaskManager; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; + +public class TaskBuilder extends Metadatable { + + private final ForkJoinPool pool = new ForkJoinPool(); + private final ArrayDeque tasks; + private Object result = null; + private Thread.UncaughtExceptionHandler handler; + + public TaskBuilder() { + this(null); + } + + public TaskBuilder(Thread.UncaughtExceptionHandler handler) { + tasks = new ArrayDeque<>(); + this.handler = handler; + } + + public TaskBuilder async(Task task) { + tasks.add(RunnableTask.adapt(task, TaskType.ASYNC)); + return this; + } + + public TaskBuilder async(ReceiveTask task) { + tasks.add(RunnableTask.adapt(task, TaskType.ASYNC)); + return this; + } + + public TaskBuilder async(ReturnTask task) { + tasks.add(RunnableTask.adapt(task, TaskType.ASYNC)); + return this; + } + + public TaskBuilder async(Runnable task) { + tasks.add(RunnableTask.adapt(task, TaskType.ASYNC)); + return this; + } + + public TaskBuilder sync(Task task) { + tasks.add(RunnableTask.adapt(task, TaskType.SYNC)); + return this; + } + + public TaskBuilder sync(ReceiveTask task) { + tasks.add(RunnableTask.adapt(task, TaskType.SYNC)); + return this; + } + + public TaskBuilder sync(ReturnTask task) { + tasks.add(RunnableTask.adapt(task, TaskType.SYNC)); + return this; + } + + public TaskBuilder sync(Runnable task) { + tasks.add(RunnableTask.adapt(task, TaskType.SYNC)); + return this; + } + + public TaskBuilder delay(int ticks) { + tasks.add(RunnableDelayedTask.adapt(ticks)); + return this; + } + + public TaskBuilder delay(DelayedTask task) { + tasks.add(RunnableDelayedTask.adapt(task)); + return this; + } + + /** + * Run some sync tasks in parallel
+ * - All sync parallel tasks which occur directly after each other will be run at the same time + * @param run + * @return this + */ + public TaskBuilder syncParallel(Runnable run) { + tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL)); + return this; + } + + public TaskBuilder syncParallel(Task run) { + tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL)); + return this; + } + + public TaskBuilder syncParallel(ReceiveTask run) { + tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL)); + return this; + } + + public TaskBuilder syncParallel(ReturnTask run) { + tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL)); + return this; + } + + /** + * Run some async tasks in parallel
+ * - All async parallel tasks which occur directly after each other will be run at the same time + * @param run + * @return this + */ + public TaskBuilder asyncParallel(Runnable run) { + tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL)); + return this; + } + + public TaskBuilder asyncParallel(Task run) { + tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL)); + return this; + } + + public TaskBuilder asyncParallel(ReceiveTask run) { + tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL)); + return this; + } + + public TaskBuilder asyncParallel(ReturnTask run) { + tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL)); + return this; + } + + /** + * Run a split task when the server has free time
+ * - i.e. To maintain high tps + * - Use the split() method within task execution + * - FAWE will be able to pause execution at these points + * @param run + * @return this + */ + public TaskBuilder syncWhenFree(SplitTask run) { + tasks.add(run); + return this; + } + + public TaskBuilder syncWhenFree(Task run) { + tasks.add(RunnableTask.adapt(run, TaskType.SYNC_WHEN_FREE)); + return this; + } + + public TaskBuilder syncWhenFree(ReceiveTask run) { + tasks.add(RunnableTask.adapt(run, TaskType.SYNC_WHEN_FREE)); + return this; + } + + public TaskBuilder syncWhenFree(ReturnTask run) { + tasks.add(RunnableTask.adapt(run, TaskType.SYNC_WHEN_FREE)); + return this; + } + + public TaskBuilder abortIfTrue(Task run) { + tasks.add(RunnableTask.adapt(run, TaskType.ABORT)); + return this; + } + + /** + * Have all async tasks run on a new thread
+ * - As opposed to trying to using the current thread + */ + public void buildAsync() { + TaskManager.IMP.async(new Runnable() { + @Override + public void run() { + build(); + } + }); + } + + /** + * Begins execution of the tasks
+ * - The builder will attempt to run on the current thread if possible + */ + public void build() { + RunnableTask peek; + while ((peek = tasks.peek()) != null) { + try { + switch (peek.type) { + case DELAY: + DelayedTask task = (DelayedTask) tasks.poll(); + RunnableTask next = tasks.peek(); + if (next != null) { + switch (next.type) { + case SYNC: + case ABORT: + case SYNC_PARALLEL: + TaskManager.IMP.later(new Runnable() { + @Override + public void run() { + build(); + } + }, task.getDelay(result)); + return; + default: + TaskManager.IMP.laterAsync(new Runnable() { + @Override + public void run() { + build(); + } + }, task.getDelay(result)); + return; + } + } + return; + case SYNC: + case SYNC_PARALLEL: + if (!Fawe.get().isMainThread()) { + TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Object value) { + build(); + } + }); + return; + } + break; + case SYNC_WHEN_FREE: + case ASYNC: + case ASYNC_PARALLEL: + if (Fawe.get().isMainThread()) { + TaskManager.IMP.async(new Runnable() { + @Override + public void run() { + build(); + } + }); + return; + } + break; + } + RunnableTask task = tasks.poll(); + task.value = result; + switch (task.type) { + case ABORT: + if (((Task) task).run(result)) { + return; + } + break; + case SYNC: + result = task.exec(result); + break; + case SYNC_WHEN_FREE: + if (task instanceof SplitTask) { + SplitTask splitTask = (SplitTask) task; + result = splitTask.execSplit(result); + } else { + result = TaskManager.IMP.syncWhenFree(task); + } + break; + case ASYNC: + result = task.exec(result); + continue; + case SYNC_PARALLEL: + case ASYNC_PARALLEL: + final ArrayList parallel = new ArrayList(); + parallel.add(task); + RunnableTask next = tasks.peek(); + while (next != null && next.type == task.type) { + parallel.add(next); + tasks.poll(); + next = tasks.peek(); + } + for (RunnableTask current : parallel) { + pool.submit(current); + } + pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); + result = null; + for (RunnableTask current : parallel) { + if (current.value != null) { + result = current.value; + } + } + break; + } + if (task.isAborted()) { + return; + } + } catch (Throwable e) { + if (handler != null) { + handler.uncaughtException(Thread.currentThread(), e); + } + return; + } + } + } + + private FaweQueue queue; + private long last; + private long start; + private Object asyncWaitLock = new Object(); + private Object syncWaitLock = new Object(); + private boolean finished; + + private static abstract class RunnableTask extends RunnableVal { + public final TaskType type; + private boolean aborted; + + public RunnableTask(TaskType type) { + this.type = type; + } + + public void abortNextTasks() { + this.aborted = true; + } + + public boolean isAborted() { + return aborted; + } + + public static RunnableTask adapt(final Task task, TaskType type) { + return new RunnableTask(type) { + @Override + public Object exec(Object previous) { + return task.run(previous); + } + }; + } + + public static RunnableTask adapt(final ReturnTask task, TaskType type) { + return new RunnableTask(type) { + @Override + public Object exec(Object previous) { + return task.run(); + } + }; + } + + public static RunnableTask adapt(final ReceiveTask task, TaskType type) { + return new RunnableTask(type) { + @Override + public Object exec(Object previous) { + task.run(previous); + return null; + } + }; + } + + public static RunnableTask adapt(final Runnable run, TaskType type) { + return new RunnableTask(type) { + @Override + public Object exec(Object previous) { + if (run instanceof RunnableVal) { + ((RunnableVal) run).value = this.value; + return this.value = ((RunnableVal) run).runAndGet(); + } + run.run(); + return null; + } + }; + } + + public abstract T exec(Object previous); + + @Override + public final void run(T value) { + this.value = exec(value); + } + } + + private static abstract class RunnableDelayedTask extends RunnableTask { + + public RunnableDelayedTask(TaskType type) { + super(type); + } + + @Override + public Object exec(Object previous) { + return previous; + } + + public abstract int delay(Object previous); + + public static RunnableDelayedTask adapt(final DelayedTask task) { + return new RunnableDelayedTask(TaskType.DELAY) { + @Override + public int delay(Object previous) { + return task.getDelay(previous); + } + }; + } + + public static RunnableDelayedTask adapt(final int time) { + return new RunnableDelayedTask(TaskType.DELAY) { + @Override + public int delay(Object previous) { + return time; + } + }; + } + } + + public static abstract class SplitTask extends RunnableTask { + + private final long allocation; + private final FaweQueue queue; + private long last; + private long start; + private Object asyncWaitLock = new Object(); + private Object syncWaitLock = new Object(); + private boolean finished; + + public SplitTask() { + this(20); + } + + public SplitTask(long allocation) { + super(TaskType.SYNC_WHEN_FREE); + this.allocation = allocation; + this.queue = SetQueue.IMP.getNewQueue((String) null, true, false); + } + + public Object execSplit(final Object previous) { + this.value = previous; + final Thread thread = new Thread(new Runnable() { + @Override + public void run() { + try { + synchronized (asyncWaitLock) { + asyncWaitLock.wait(Long.MAX_VALUE); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + exec(previous); + finished = true; + synchronized (syncWaitLock) { + syncWaitLock.notifyAll(); + } + } + }); + thread.start(); + while (thread.isAlive()) { + TaskManager.IMP.syncWhenFree(new RunnableVal() { + @Override + public void run(Object ignore) { + queue.startSet(true); + start = System.currentTimeMillis(); + synchronized (asyncWaitLock) { + asyncWaitLock.notifyAll(); + } + synchronized (syncWaitLock) { + if (!finished) { + try { + syncWaitLock.wait(Long.MAX_VALUE); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + queue.endSet(true); + } + }); + } + return this.value; + } + + public void split() { + long now = System.currentTimeMillis(); + if (now - start > allocation) { + try { + synchronized (syncWaitLock) { + syncWaitLock.notifyAll(); + } + synchronized (asyncWaitLock) { + asyncWaitLock.wait(Long.MAX_VALUE); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + private enum TaskType { + SYNC, + ASYNC, + SYNC_PARALLEL, + ASYNC_PARALLEL, + SYNC_WHEN_FREE, + DELAY, + ABORT + } +} \ No newline at end of file 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 ed2931f2..fcdac0d7 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 @@ -39,43 +39,17 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.command.BiomeCommands; -import com.sk89q.worldedit.command.BrushCommands; -import com.sk89q.worldedit.command.ChunkCommands; -import com.sk89q.worldedit.command.ClipboardCommands; -import com.sk89q.worldedit.command.GeneralCommands; -import com.sk89q.worldedit.command.GenerationCommands; -import com.sk89q.worldedit.command.HistoryCommands; -import com.sk89q.worldedit.command.NavigationCommands; -import com.sk89q.worldedit.command.RegionCommands; -import com.sk89q.worldedit.command.SchematicCommands; -import com.sk89q.worldedit.command.ScriptingCommands; -import com.sk89q.worldedit.command.SelectionCommands; -import com.sk89q.worldedit.command.SnapshotCommands; -import com.sk89q.worldedit.command.SnapshotUtilCommands; -import com.sk89q.worldedit.command.SuperPickaxeCommands; -import com.sk89q.worldedit.command.ToolCommands; -import com.sk89q.worldedit.command.ToolUtilCommands; -import com.sk89q.worldedit.command.UtilityCommands; -import com.sk89q.worldedit.command.WorldEditCommands; +import com.sk89q.worldedit.command.*; import com.sk89q.worldedit.command.argument.ReplaceParser; import com.sk89q.worldedit.command.argument.TreeGeneratorParser; -import com.sk89q.worldedit.command.composition.ApplyCommand; -import com.sk89q.worldedit.command.composition.DeformCommand; -import com.sk89q.worldedit.command.composition.PaintCommand; -import com.sk89q.worldedit.command.composition.SelectionCommand; -import com.sk89q.worldedit.command.composition.ShapedBrushCommand; +import com.sk89q.worldedit.command.composition.*; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.function.factory.Deform; import com.sk89q.worldedit.function.factory.Deform.Mode; import com.sk89q.worldedit.history.changeset.ChangeSet; -import com.sk89q.worldedit.internal.command.ActorAuthorizer; -import com.sk89q.worldedit.internal.command.CommandLoggingHandler; -import com.sk89q.worldedit.internal.command.UserCommandCompleter; -import com.sk89q.worldedit.internal.command.WorldEditBinding; -import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; +import com.sk89q.worldedit.internal.command.*; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.InvalidUsageException; 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 1bda1041..c584c91b 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 @@ -449,7 +449,8 @@ public class PlatformManager { public void handlePlayerInput(PlayerInputEvent event) { // Create a proxy actor with a potentially different world for // making changes to the world - final Player player = PlayerWrapper.wrap(createProxyActor(event.getPlayer())); + Player actor = createProxyActor(event.getPlayer()); + final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap(actor), actor.getLocation()); try { switch (event.getInputType()) { diff --git a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 303b7d95..fd1a708e 100644 --- a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -414,7 +414,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue