mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-06-25 22:24:54 +02:00
JavaScript-API Allow command replacing Tweak primary thread checks Tab completion Schematic resolving help tweaks optimize change set fix color brush
429 lines
12 KiB
Java
429 lines
12 KiB
Java
package com.boydti.fawe.util;
|
|
|
|
import com.boydti.fawe.Fawe;
|
|
import com.boydti.fawe.config.Settings;
|
|
import com.boydti.fawe.object.FaweQueue;
|
|
import com.boydti.fawe.object.RunnableVal;
|
|
import java.util.Collection;
|
|
import java.util.Iterator;
|
|
import java.util.concurrent.ForkJoinPool;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.function.Supplier;
|
|
import javax.annotation.Nullable;
|
|
|
|
public abstract class TaskManager {
|
|
|
|
public static TaskManager IMP;
|
|
|
|
private ForkJoinPool pool = new ForkJoinPool();
|
|
|
|
/**
|
|
* Run a repeating task on the main thread
|
|
*
|
|
* @param r
|
|
* @param interval in ticks
|
|
* @return
|
|
*/
|
|
public abstract int repeat(final Runnable r, final int interval);
|
|
|
|
/**
|
|
* Run a repeating task asynchronously
|
|
*
|
|
* @param r
|
|
* @param interval in ticks
|
|
* @return
|
|
*/
|
|
public abstract int repeatAsync(final Runnable r, final int interval);
|
|
|
|
/**
|
|
* Run a task asynchronously
|
|
*
|
|
* @param r
|
|
*/
|
|
public abstract void async(final Runnable r);
|
|
|
|
/**
|
|
* Run a task on the main thread
|
|
*
|
|
* @param r
|
|
*/
|
|
public abstract void task(final Runnable r);
|
|
|
|
/**
|
|
* Get the public ForkJoinPool<br>
|
|
* - ONLY SUBMIT SHORT LIVED TASKS<br>
|
|
* - DO NOT USE SLEEP/WAIT/LOCKS IN ANY SUBMITTED TASKS<br>
|
|
*
|
|
* @return
|
|
*/
|
|
public ForkJoinPool getPublicForkJoinPool() {
|
|
return pool;
|
|
}
|
|
|
|
/**
|
|
* Run a buch of tasks in parallel using the shared thread pool
|
|
*
|
|
* @param runnables
|
|
*/
|
|
public void parallel(Collection<Runnable> runnables) {
|
|
// if (!Fawe.get().isJava8()) {
|
|
// ExecutorCompletionService c = new ExecutorCompletionService(pool);
|
|
// for (Runnable run : runnables) {
|
|
// c.submit(run, null);
|
|
// }
|
|
// try {
|
|
// for (int i = 0; i < runnables.size(); i++) {
|
|
// c.take();
|
|
// }
|
|
// } catch (Exception e) {
|
|
// e.printStackTrace();
|
|
// }
|
|
// return;
|
|
// }
|
|
for (Runnable run : runnables) {
|
|
pool.submit(run);
|
|
}
|
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
}
|
|
|
|
/**
|
|
* Run a bunch of tasks in parallel
|
|
*
|
|
* @param runnables The tasks to run
|
|
* @param numThreads Number of threads (null = config.yml parallel threads)
|
|
*/
|
|
@Deprecated
|
|
public void parallel(Collection<Runnable> runnables, @Nullable Integer numThreads) {
|
|
if (runnables == null) {
|
|
return;
|
|
}
|
|
if (numThreads == null) {
|
|
numThreads = Settings.IMP.QUEUE.PARALLEL_THREADS;
|
|
}
|
|
if (numThreads <= 1) {
|
|
for (Runnable run : runnables) {
|
|
if (run != null) {
|
|
run.run();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
int numRuns = runnables.size();
|
|
int amountPerThread = 1 + numRuns / numThreads;
|
|
final Runnable[][] split = new Runnable[numThreads][amountPerThread];
|
|
Thread[] threads = new Thread[numThreads];
|
|
int i = 0;
|
|
int j = 0;
|
|
for (Runnable run : runnables) {
|
|
split[i][j] = run;
|
|
if (++i >= numThreads) {
|
|
i = 0;
|
|
j++;
|
|
}
|
|
}
|
|
for (i = 0; i < threads.length; i++) {
|
|
final Runnable[] toRun = split[i];
|
|
Thread thread = threads[i] = new Thread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
for (int j = 0; j < toRun.length; j++) {
|
|
Runnable run = toRun[j];
|
|
if (run != null) {
|
|
run.run();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
thread.start();
|
|
}
|
|
for (Thread thread : threads) {
|
|
try {
|
|
thread.join();
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Disable async catching for a specific task
|
|
*
|
|
* @param queue
|
|
* @param run
|
|
*/
|
|
public void runUnsafe(FaweQueue queue, Runnable run) {
|
|
queue.startSet(true);
|
|
try {
|
|
run.run();
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
}
|
|
queue.endSet(true);
|
|
}
|
|
|
|
/**
|
|
* Run a task on the current thread or asynchronously
|
|
* - If it's already the main thread, it will jst call run()
|
|
*
|
|
* @param r
|
|
* @param async
|
|
*/
|
|
public void taskNow(final Runnable r, boolean async) {
|
|
if (async) {
|
|
async(r);
|
|
} else if (r != null) {
|
|
r.run();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run a task as soon as possible on the main thread
|
|
* - Non blocking if not calling from the main thread
|
|
*
|
|
* @param r
|
|
*/
|
|
public void taskNowMain(final Runnable r) {
|
|
if (r == null) {
|
|
return;
|
|
}
|
|
if (Fawe.isMainThread()) {
|
|
r.run();
|
|
} else {
|
|
task(r);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run a task as soon as possible not on the main thread
|
|
*
|
|
* @param r
|
|
* @see com.boydti.fawe.Fawe#isMainThread()
|
|
*/
|
|
public void taskNowAsync(final Runnable r) {
|
|
taskNow(r, Fawe.isMainThread());
|
|
}
|
|
|
|
/**
|
|
* Run a task on the main thread at the next tick or now async
|
|
*
|
|
* @param r
|
|
* @param async
|
|
*/
|
|
public void taskSoonMain(final Runnable r, boolean async) {
|
|
if (async) {
|
|
async(r);
|
|
} else {
|
|
task(r);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Run a task later on the main thread
|
|
*
|
|
* @param r
|
|
* @param delay in ticks
|
|
*/
|
|
public abstract void later(final Runnable r, final int delay);
|
|
|
|
/**
|
|
* Run a task later asynchronously
|
|
*
|
|
* @param r
|
|
* @param delay in ticks
|
|
*/
|
|
public abstract void laterAsync(final Runnable r, final int delay);
|
|
|
|
/**
|
|
* Cancel a task
|
|
*
|
|
* @param task
|
|
*/
|
|
public abstract void cancel(final int task);
|
|
|
|
/**
|
|
* Break up a task and run it in fragments of 5ms.<br>
|
|
* - Each task will run on the main thread.<br>
|
|
*
|
|
* @param objects - The list of objects to run the task for
|
|
* @param task - The task to run on each object
|
|
* @param whenDone - When the object task completes
|
|
* @param <T>
|
|
*/
|
|
public <T> void objectTask(Collection<T> objects, final RunnableVal<T> task, final Runnable whenDone) {
|
|
final Iterator<T> iterator = objects.iterator();
|
|
task(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
long start = System.currentTimeMillis();
|
|
boolean hasNext;
|
|
while ((hasNext = iterator.hasNext()) && System.currentTimeMillis() - start < 5) {
|
|
task.value = iterator.next();
|
|
task.run();
|
|
}
|
|
if (!hasNext) {
|
|
later(whenDone, 1);
|
|
} else {
|
|
later(this, 1);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Quickly run a task on the main thread, and wait for execution to finish:<br>
|
|
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
|
* - Usualy wait time is around 25ms<br>
|
|
*
|
|
* @param function
|
|
* @param <T>
|
|
* @return
|
|
*/
|
|
public <T> T sync(final RunnableVal<T> function) {
|
|
return sync(function, Integer.MAX_VALUE);
|
|
}
|
|
|
|
public <T> T sync(final Supplier<T> function) {
|
|
return sync(function, Integer.MAX_VALUE);
|
|
}
|
|
|
|
public void wait(AtomicBoolean running, int timout) {
|
|
try {
|
|
long start = System.currentTimeMillis();
|
|
synchronized (running) {
|
|
while (running.get()) {
|
|
running.wait(timout);
|
|
if (running.get() && System.currentTimeMillis() - start > Settings.IMP.QUEUE.DISCARD_AFTER_MS) {
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
} catch (InterruptedException e) {
|
|
MainUtil.handleError(e);
|
|
}
|
|
}
|
|
|
|
public void notify(AtomicBoolean running) {
|
|
running.set(false);
|
|
synchronized (running) {
|
|
running.notifyAll();
|
|
}
|
|
}
|
|
|
|
public <T> T syncWhenFree(final RunnableVal<T> function) {
|
|
return syncWhenFree(function, Integer.MAX_VALUE);
|
|
}
|
|
|
|
public void taskWhenFree(Runnable run) {
|
|
if (Fawe.isMainThread()) {
|
|
run.run();
|
|
} else {
|
|
SetQueue.IMP.addTask(run);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run a task on the main thread when the TPS is high enough, and wait for execution to finish:<br>
|
|
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
|
* - Usualy wait time is around 25ms<br>
|
|
*
|
|
* @param function
|
|
* @param timeout - How long to wait for execution
|
|
* @param <T>
|
|
* @return
|
|
*/
|
|
public <T> T syncWhenFree(final RunnableVal<T> function, int timeout) {
|
|
if (Fawe.isMainThread()) {
|
|
function.run();
|
|
return function.value;
|
|
}
|
|
final AtomicBoolean running = new AtomicBoolean(true);
|
|
RunnableVal<RuntimeException> run = new RunnableVal<RuntimeException>() {
|
|
@Override
|
|
public void run(RuntimeException value) {
|
|
try {
|
|
function.run();
|
|
} catch (RuntimeException e) {
|
|
this.value = e;
|
|
} catch (Throwable neverHappens) {
|
|
MainUtil.handleError(neverHappens);
|
|
} finally {
|
|
running.set(false);
|
|
}
|
|
synchronized (function) {
|
|
function.notifyAll();
|
|
}
|
|
}
|
|
};
|
|
SetQueue.IMP.addTask(run);
|
|
try {
|
|
synchronized (function) {
|
|
while (running.get()) {
|
|
function.wait(timeout);
|
|
}
|
|
}
|
|
} catch (InterruptedException e) {
|
|
MainUtil.handleError(e);
|
|
}
|
|
if (run.value != null) {
|
|
throw run.value;
|
|
}
|
|
return function.value;
|
|
}
|
|
|
|
/**
|
|
* Quickly run a task on the main thread, and wait for execution to finish:<br>
|
|
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
|
* - Usualy wait time is around 25ms<br>
|
|
*
|
|
* @param function
|
|
* @param timeout - How long to wait for execution
|
|
* @param <T>
|
|
* @return
|
|
*/
|
|
public <T> T sync(final RunnableVal<T> function, int timeout) {
|
|
return sync((Supplier<T>) function, timeout);
|
|
}
|
|
|
|
public <T> T sync(final Supplier<T> function, int timeout) {
|
|
if (Fawe.isMainThread()) {
|
|
return function.get();
|
|
}
|
|
final AtomicBoolean running = new AtomicBoolean(true);
|
|
RunnableVal<Object> run = new RunnableVal<Object>() {
|
|
@Override
|
|
public void run(Object value) {
|
|
try {
|
|
this.value = function.get();
|
|
} catch (RuntimeException e) {
|
|
this.value = e;
|
|
} catch (Throwable neverHappens) {
|
|
MainUtil.handleError(neverHappens);
|
|
} finally {
|
|
running.set(false);
|
|
}
|
|
synchronized (function) {
|
|
function.notifyAll();
|
|
}
|
|
}
|
|
};
|
|
SetQueue.IMP.addTask(run);
|
|
try {
|
|
synchronized (function) {
|
|
while (running.get()) {
|
|
function.wait(timeout);
|
|
}
|
|
}
|
|
} catch (InterruptedException e) {
|
|
MainUtil.handleError(e);
|
|
}
|
|
if (run.value != null && run.value instanceof RuntimeException) {
|
|
throw (RuntimeException) run.value;
|
|
}
|
|
return (T) run.value;
|
|
}
|
|
}
|