Various
Fix some brush stuff Fix issue with editing on main thread FIx error from misusing AsyncBlock Tweak some messages Add TaskBuilder API
This commit is contained in:
parent
a28e8b4069
commit
60152a5b1f
@ -153,7 +153,7 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public World getImpWorld() {
|
public World getImpWorld() {
|
||||||
return Bukkit.getWorld(getWorldName());
|
return getWorldName() != null ? Bukkit.getWorld(getWorldName()) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -190,23 +190,45 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private volatile boolean timingsEnabled;
|
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
|
@Override
|
||||||
public void startSet(boolean parallel) {
|
public void startSet(boolean parallel) {
|
||||||
ChunkListener.physicsFreeze = true;
|
ChunkListener.physicsFreeze = true;
|
||||||
if (parallel) {
|
if (parallel) {
|
||||||
try {
|
try {
|
||||||
Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");
|
if (fieldAsyncCatcherEnabled != null) {
|
||||||
fieldEnabled.setAccessible(true);
|
fieldAsyncCatcherEnabled.set(null, false);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
} catch (Throwable ignore) {}
|
if (fieldTimingsEnabled != null) {
|
||||||
try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, false); } catch (Throwable ignore) {}
|
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<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
|||||||
public void endSet(boolean parallel) {
|
public void endSet(boolean parallel) {
|
||||||
ChunkListener.physicsFreeze = false;
|
ChunkListener.physicsFreeze = false;
|
||||||
if (parallel) {
|
if (parallel) {
|
||||||
try {Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");fieldEnabled.setAccessible(true);fieldEnabled.set(null, timingsEnabled);
|
try {
|
||||||
} catch (Throwable ignore) {}
|
if (fieldAsyncCatcherEnabled != null) {
|
||||||
try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, true); } catch (Throwable ignore) {}
|
fieldAsyncCatcherEnabled.set(null, true);
|
||||||
|
}
|
||||||
|
if (fieldTimingsEnabled != null && timingsEnabled) {
|
||||||
|
fieldTimingsEnabled.set(null, true);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public class AsyncBlock implements Block {
|
|||||||
this.world = world;
|
this.world = world;
|
||||||
this.queue = queue;
|
this.queue = queue;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y & 0xFF;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,16 +37,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public abstract class FawePlayer<T> {
|
public abstract class FawePlayer<T> extends Metadatable {
|
||||||
|
|
||||||
public final T parent;
|
public final T parent;
|
||||||
private LocalSession session;
|
private LocalSession session;
|
||||||
|
|
||||||
/**
|
|
||||||
* The metadata map.
|
|
||||||
*/
|
|
||||||
private volatile ConcurrentHashMap<String, Object> meta;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap some object into a FawePlayer<br>
|
* Wrap some object into a FawePlayer<br>
|
||||||
* - org.bukkit.entity.Player
|
* - org.bukkit.entity.Player
|
||||||
@ -396,64 +391,6 @@ public abstract class FawePlayer<T> {
|
|||||||
return this.hasPermission("fawe.bypass");
|
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> 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 <V>
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public <V> 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 <V>
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public <V> 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)
|
* Unregister this player (delets all metadata etc)
|
||||||
* - Usually called on logout
|
* - Usually called on logout
|
||||||
|
60
core/src/main/java/com/boydti/fawe/object/Metadatable.java
Normal file
60
core/src/main/java/com/boydti/fawe/object/Metadatable.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package com.boydti.fawe.object;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class Metadatable {
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<String, Object> 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> T getAndSetMeta(String key, T value) {
|
||||||
|
return (T) this.meta.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the metadata for a key.
|
||||||
|
* @param <V>
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <V> 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 <V>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <V> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -10,11 +10,11 @@ public abstract class RunnableVal<T> implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public final void run() {
|
||||||
run(this.value);
|
run(this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T runAndGet() {
|
public final T runAndGet() {
|
||||||
run();
|
run();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,7 @@ import com.boydti.fawe.util.MainUtil;
|
|||||||
import com.sk89q.jnbt.NBTInputStream;
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
import com.sk89q.jnbt.NBTOutputStream;
|
import com.sk89q.jnbt.NBTOutputStream;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -296,7 +296,7 @@ public abstract class FaweChangeSet implements ChangeSet {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (mainThread) {
|
if (mainThread) {
|
||||||
new Thread(run).start();
|
run.run();
|
||||||
} else {
|
} else {
|
||||||
TaskManager.IMP.async(run);
|
TaskManager.IMP.async(run);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -74,11 +74,7 @@ public class MainUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void stacktrace() {
|
public static void stacktrace() {
|
||||||
try {
|
new Exception().printStackTrace();
|
||||||
int i = 1/0;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void traverse(Path path, final RunnableVal2<Path, BasicFileAttributes> onEach) {
|
public static void traverse(Path path, final RunnableVal2<Path, BasicFileAttributes> onEach) {
|
||||||
|
@ -275,7 +275,8 @@ public abstract class TaskManager {
|
|||||||
while (running.get()) {
|
while (running.get()) {
|
||||||
running.wait(timout);
|
running.wait(timout);
|
||||||
if (running.get() && System.currentTimeMillis() - start > Settings.QUEUE.DISCARD_AFTER_MS) {
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.boydti.fawe.util.task;
|
||||||
|
|
||||||
|
public interface DelayedTask<T> {
|
||||||
|
int getDelay(T previousResult);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.boydti.fawe.util.task;
|
||||||
|
|
||||||
|
public interface ReceiveTask<T> {
|
||||||
|
void run(T previous);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.boydti.fawe.util.task;
|
||||||
|
|
||||||
|
public interface ReturnTask<T> {
|
||||||
|
T run();
|
||||||
|
}
|
5
core/src/main/java/com/boydti/fawe/util/task/Task.java
Normal file
5
core/src/main/java/com/boydti/fawe/util/task/Task.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package com.boydti.fawe.util.task;
|
||||||
|
|
||||||
|
public interface Task<T, V> {
|
||||||
|
T run(V previousResult);
|
||||||
|
}
|
491
core/src/main/java/com/boydti/fawe/util/task/TaskBuilder.java
Normal file
491
core/src/main/java/com/boydti/fawe/util/task/TaskBuilder.java
Normal file
@ -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<RunnableTask> 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<br>
|
||||||
|
* - 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<br>
|
||||||
|
* - 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<br>
|
||||||
|
* - 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<Boolean, Object> run) {
|
||||||
|
tasks.add(RunnableTask.adapt(run, TaskType.ABORT));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have all async tasks run on a new thread<br>
|
||||||
|
* - 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<br>
|
||||||
|
* - 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<Boolean, Object>) 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<RunnableTask> parallel = new ArrayList<RunnableTask>();
|
||||||
|
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<T> extends RunnableVal<T> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -39,43 +39,17 @@ import com.sk89q.worldedit.EditSession;
|
|||||||
import com.sk89q.worldedit.LocalConfiguration;
|
import com.sk89q.worldedit.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.command.BiomeCommands;
|
import com.sk89q.worldedit.command.*;
|
||||||
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.argument.ReplaceParser;
|
import com.sk89q.worldedit.command.argument.ReplaceParser;
|
||||||
import com.sk89q.worldedit.command.argument.TreeGeneratorParser;
|
import com.sk89q.worldedit.command.argument.TreeGeneratorParser;
|
||||||
import com.sk89q.worldedit.command.composition.ApplyCommand;
|
import com.sk89q.worldedit.command.composition.*;
|
||||||
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.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||||
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||||
import com.sk89q.worldedit.function.factory.Deform;
|
import com.sk89q.worldedit.function.factory.Deform;
|
||||||
import com.sk89q.worldedit.function.factory.Deform.Mode;
|
import com.sk89q.worldedit.function.factory.Deform.Mode;
|
||||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||||
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
|
import com.sk89q.worldedit.internal.command.*;
|
||||||
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.session.request.Request;
|
import com.sk89q.worldedit.session.request.Request;
|
||||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||||
import com.sk89q.worldedit.util.command.InvalidUsageException;
|
import com.sk89q.worldedit.util.command.InvalidUsageException;
|
||||||
|
@ -449,7 +449,8 @@ public class PlatformManager {
|
|||||||
public void handlePlayerInput(PlayerInputEvent event) {
|
public void handlePlayerInput(PlayerInputEvent event) {
|
||||||
// Create a proxy actor with a potentially different world for
|
// Create a proxy actor with a potentially different world for
|
||||||
// making changes to the world
|
// 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 {
|
try {
|
||||||
switch (event.getInputType()) {
|
switch (event.getInputType()) {
|
||||||
|
@ -414,7 +414,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public World getImpWorld() {
|
public World getImpWorld() {
|
||||||
if (nmsWorld != null) {
|
if (nmsWorld != null || getWorldName() == null) {
|
||||||
return nmsWorld;
|
return nmsWorld;
|
||||||
}
|
}
|
||||||
String[] split = getWorldName().split(";");
|
String[] split = getWorldName().split(";");
|
||||||
|
@ -403,7 +403,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public World getImpWorld() {
|
public World getImpWorld() {
|
||||||
if (nmsWorld != null) {
|
if (nmsWorld != null || getWorldName() == null) {
|
||||||
return nmsWorld;
|
return nmsWorld;
|
||||||
}
|
}
|
||||||
String[] split = getWorldName().split(";");
|
String[] split = getWorldName().split(";");
|
||||||
|
@ -377,7 +377,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public World getImpWorld() {
|
public World getImpWorld() {
|
||||||
if (nmsWorld != null) {
|
if (nmsWorld != null || getWorldName() == null) {
|
||||||
return nmsWorld;
|
return nmsWorld;
|
||||||
}
|
}
|
||||||
String[] split = getWorldName().split(";");
|
String[] split = getWorldName().split(";");
|
||||||
|
@ -412,7 +412,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public World getImpWorld() {
|
public World getImpWorld() {
|
||||||
if (nmsWorld != null) {
|
if (nmsWorld != null || getWorldName() == null) {
|
||||||
return nmsWorld;
|
return nmsWorld;
|
||||||
}
|
}
|
||||||
String[] split = getWorldName().split(";");
|
String[] split = getWorldName().split(";");
|
||||||
|
Loading…
Reference in New Issue
Block a user