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
|
||||
public World getImpWorld() {
|
||||
return Bukkit.getWorld(getWorldName());
|
||||
return getWorldName() != null ? Bukkit.getWorld(getWorldName()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -190,23 +190,45 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> 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 (fieldAsyncCatcherEnabled != null) {
|
||||
fieldAsyncCatcherEnabled.set(null, false);
|
||||
}
|
||||
if (fieldTimingsEnabled != null) {
|
||||
timingsEnabled = (boolean) fieldTimingsEnabled.get(null);
|
||||
if (timingsEnabled) {
|
||||
fieldEnabled.set(null, false);
|
||||
Method methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
|
||||
methodCheck.setAccessible(true);
|
||||
if (alertTimingsChange) {
|
||||
alertTimingsChange = false;
|
||||
Fawe.debug("Having `parallel-threads` > 1 interferes with the timings.");
|
||||
}
|
||||
fieldTimingsEnabled.set(null, false);
|
||||
methodCheck.invoke(null);
|
||||
}
|
||||
} catch (Throwable ignore) {}
|
||||
try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, false); } catch (Throwable ignore) {}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,9 +236,16 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -37,16 +37,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public abstract class FawePlayer<T> {
|
||||
public abstract class FawePlayer<T> extends Metadatable {
|
||||
|
||||
public final T parent;
|
||||
private LocalSession session;
|
||||
|
||||
/**
|
||||
* The metadata map.
|
||||
*/
|
||||
private volatile ConcurrentHashMap<String, Object> meta;
|
||||
|
||||
/**
|
||||
* Wrap some object into a FawePlayer<br>
|
||||
* - org.bukkit.entity.Player
|
||||
@ -396,64 +391,6 @@ public abstract class FawePlayer<T> {
|
||||
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)
|
||||
* - 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
|
||||
public void run() {
|
||||
public final void run() {
|
||||
run(this.value);
|
||||
}
|
||||
|
||||
public T runAndGet() {
|
||||
public final T runAndGet() {
|
||||
run();
|
||||
return value;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -296,7 +296,7 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
}
|
||||
};
|
||||
if (mainThread) {
|
||||
new Thread(run).start();
|
||||
run.run();
|
||||
} else {
|
||||
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() {
|
||||
try {
|
||||
int i = 1/0;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
new Exception().printStackTrace();
|
||||
}
|
||||
|
||||
public static void traverse(Path path, final RunnableVal2<Path, BasicFileAttributes> onEach) {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.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;
|
||||
|
@ -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()) {
|
||||
|
@ -414,7 +414,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
|
||||
@Override
|
||||
public World getImpWorld() {
|
||||
if (nmsWorld != null) {
|
||||
if (nmsWorld != null || getWorldName() == null) {
|
||||
return nmsWorld;
|
||||
}
|
||||
String[] split = getWorldName().split(";");
|
||||
|
@ -403,7 +403,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
|
||||
@Override
|
||||
public World getImpWorld() {
|
||||
if (nmsWorld != null) {
|
||||
if (nmsWorld != null || getWorldName() == null) {
|
||||
return nmsWorld;
|
||||
}
|
||||
String[] split = getWorldName().split(";");
|
||||
|
@ -377,7 +377,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
|
||||
@Override
|
||||
public World getImpWorld() {
|
||||
if (nmsWorld != null) {
|
||||
if (nmsWorld != null || getWorldName() == null) {
|
||||
return nmsWorld;
|
||||
}
|
||||
String[] split = getWorldName().split(";");
|
||||
|
@ -412,7 +412,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
|
||||
@Override
|
||||
public World getImpWorld() {
|
||||
if (nmsWorld != null) {
|
||||
if (nmsWorld != null || getWorldName() == null) {
|
||||
return nmsWorld;
|
||||
}
|
||||
String[] split = getWorldName().split(";");
|
||||
|
Loading…
Reference in New Issue
Block a user