Files
CustomNPC-Plus/src/main/java/noppes/npcs/controllers/data/action/ActionThread.java
T

126 lines
3.3 KiB
Java
Raw Normal View History

2025-06-28 09:30:21 +03:00
package noppes.npcs.controllers.data.action;
import noppes.npcs.api.handler.data.IAction;
2025-06-29 21:06:15 +03:00
import java.util.Queue;
2025-06-29 21:56:15 +03:00
import java.util.Set;
import java.util.concurrent.*;
2025-06-29 21:06:15 +03:00
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;
2025-06-28 09:30:21 +03:00
public class ActionThread {
private 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;
2025-06-29 21:56:15 +03:00
2025-06-29 21:06:15 +03:00
private final Queue<Future<?>> runningTasks = new ConcurrentLinkedQueue<>();
2025-06-29 21:56:15 +03:00
private final Set<Object> runningKeys = ConcurrentHashMap.newKeySet();
2025-06-29 21:06:15 +03:00
private volatile boolean threadPaused, threadSleeping;
2025-06-28 09:30:21 +03:00
private Function<IAction, 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() {
2025-06-29 21:06:15 +03:00
runningTasks.forEach((task) -> {
if (!task.isDone())
task.cancel(true);
});
2025-06-29 09:47:07 +03:00
executor.shutdown();
}
public void pauseFor(long millis) {
2025-06-29 09:47:07 +03:00
if (isPaused() || !inActionThread())
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
}
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(Function<IAction, Boolean> until) {
this.pauseUntil = until;
pause();
}
public void resume() {
synchronized (lock) {
if (threadPaused) {
2025-06-28 09:30:21 +03:00
threadPaused = false;
lock.notify();
2025-06-28 09:30:21 +03:00
}
2025-06-29 21:06:15 +03:00
if (threadSleeping)
thread.interrupt();
}
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() {
return threadPaused || threadSleeping;
2025-06-28 09:30:21 +03:00
}
2025-06-29 09:47:07 +03:00
public boolean isThreadRunning() {
2025-06-29 21:06:15 +03:00
return runningTasks.stream().anyMatch(task -> !task.isDone());
}
2025-06-29 21:56:15 +03:00
protected void execute(String taskKey, Runnable task) {
if (threadPaused && pauseUntil != null && pauseUntil.apply(action))
resume();
2025-06-29 21:56:15 +03:00
if (runningKeys.contains(taskKey))
2025-06-28 09:30:21 +03:00
return;
2025-06-29 21:06:15 +03:00
final AtomicReference<Future<?>> taskRef = new AtomicReference<>();
taskRef.set(executor.submit(() -> {
runningTasks.add(taskRef.get());
2025-06-29 21:56:15 +03:00
runningKeys.add(taskKey);
2025-06-29 09:47:07 +03:00
try {
2025-06-29 21:06:15 +03:00
task.run();
} finally {
runningTasks.remove(taskRef.get());
2025-06-29 21:56:15 +03:00
runningKeys.remove(taskKey);
2025-06-29 09:47:07 +03:00
}
2025-06-29 21:06:15 +03:00
}));
2025-06-28 09:30:21 +03:00
}
}