2025-06-28 09:30:21 +03:00
|
|
|
package noppes.npcs.controllers.data.action;
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
|
import java.util.concurrent.Future;
|
2025-06-28 19:07:19 +03:00
|
|
|
import java.util.function.Supplier;
|
2025-06-28 09:30:21 +03:00
|
|
|
|
|
|
|
|
public class ActionThread {
|
2025-06-28 19:07:19 +03:00
|
|
|
private final Action action;
|
|
|
|
|
|
|
|
|
|
private final Object lock = new Object();
|
2025-06-28 09:30:21 +03:00
|
|
|
private Thread thread;
|
2025-06-29 09:47:07 +03:00
|
|
|
ExecutorService executor;
|
|
|
|
|
private Future<?> currentExecution;
|
2025-06-28 19:07:19 +03:00
|
|
|
private volatile boolean threadPaused, threadSleeping;
|
2025-06-28 09:30:21 +03:00
|
|
|
|
2025-06-28 19:07:19 +03:00
|
|
|
private Supplier<Boolean> pauseUntil;
|
|
|
|
|
|
2025-06-28 09:30:21 +03:00
|
|
|
public ActionThread(Action action) {
|
|
|
|
|
this.action = action;
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
executor = Executors.newSingleThreadExecutor(r -> {
|
|
|
|
|
thread = new Thread(r);
|
|
|
|
|
thread.setName(String.format("ActionThread (%s)", action.getName()));
|
|
|
|
|
return thread;
|
2025-06-28 09:30:21 +03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
public void stop() {
|
|
|
|
|
if (isThreadRunning())
|
|
|
|
|
currentExecution.cancel(true);
|
|
|
|
|
|
|
|
|
|
executor.shutdown();
|
|
|
|
|
}
|
2025-06-28 19:07:19 +03:00
|
|
|
|
|
|
|
|
public void pauseFor(long millis) {
|
2025-06-29 09:47:07 +03:00
|
|
|
if (isPaused() || !inActionThread())
|
2025-06-28 19:07:19 +03:00
|
|
|
return;
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
try {
|
|
|
|
|
threadSleeping = true;
|
|
|
|
|
Thread.sleep(millis);
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
} finally {
|
|
|
|
|
threadSleeping = false;
|
|
|
|
|
}
|
2025-06-28 09:30:21 +03:00
|
|
|
}
|
|
|
|
|
|
2025-06-28 19:07:19 +03:00
|
|
|
public void pauseFor(int ticks) {
|
|
|
|
|
pauseFor(ticks * 50L);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void pause() {
|
|
|
|
|
if (!inActionThread() || isPaused())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
threadPaused = true;
|
|
|
|
|
synchronized (lock) {
|
|
|
|
|
while (threadPaused) {
|
|
|
|
|
try {
|
|
|
|
|
lock.wait(); // Wait until notified
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void pauseUntil(Supplier<Boolean> until) {
|
|
|
|
|
this.pauseUntil = until;
|
|
|
|
|
pause();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void resume() {
|
|
|
|
|
synchronized (lock) {
|
|
|
|
|
if (threadPaused) {
|
2025-06-28 09:30:21 +03:00
|
|
|
threadPaused = false;
|
2025-06-28 19:07:19 +03:00
|
|
|
lock.notify();
|
2025-06-28 09:30:21 +03:00
|
|
|
}
|
2025-06-28 19:07:19 +03:00
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
if (threadSleeping && currentExecution != null)
|
|
|
|
|
currentExecution.cancel(true);
|
2025-06-28 19:07:19 +03:00
|
|
|
}
|
2025-06-28 09:30:21 +03:00
|
|
|
}
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
public boolean inActionThread() {
|
|
|
|
|
return Thread.currentThread() == thread;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-28 09:30:21 +03:00
|
|
|
public boolean isPaused() {
|
2025-06-28 19:07:19 +03:00
|
|
|
return threadPaused || threadSleeping;
|
2025-06-28 09:30:21 +03:00
|
|
|
}
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
public boolean isThreadRunning() {
|
|
|
|
|
return currentExecution != null && !currentExecution.isDone();
|
2025-06-28 19:07:19 +03:00
|
|
|
}
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
|
2025-06-28 19:07:19 +03:00
|
|
|
protected void run() {
|
|
|
|
|
if (threadPaused && pauseUntil != null && pauseUntil.get())
|
|
|
|
|
resume();
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
if (isThreadRunning())
|
2025-06-28 09:30:21 +03:00
|
|
|
return;
|
|
|
|
|
|
2025-06-29 09:47:07 +03:00
|
|
|
currentExecution = executor.submit(() -> {
|
|
|
|
|
try {
|
|
|
|
|
action.task.accept(action);
|
|
|
|
|
action.count++;
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
System.err.println("Scripted threaded action '" + action.name + "' threw an exception:");
|
|
|
|
|
t.printStackTrace();
|
|
|
|
|
action.markDone();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-06-28 09:30:21 +03:00
|
|
|
}
|
|
|
|
|
}
|