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

708 lines
19 KiB
Java
Raw Normal View History

2025-04-28 03:25:01 -04:00
package noppes.npcs.controllers.data.action;
2025-07-03 23:17:25 +03:00
import noppes.npcs.api.handler.IActionManager;
2025-04-28 03:25:01 -04:00
import noppes.npcs.api.handler.data.IAction;
2025-07-08 21:31:55 +03:00
import noppes.npcs.api.handler.data.IActionListener;
2025-07-02 21:14:58 +03:00
import noppes.npcs.api.handler.data.IActionQueue;
2025-06-30 07:15:34 +03:00
import noppes.npcs.api.handler.data.actions.IConditionalAction;
import noppes.npcs.controllers.ScriptContainer;
import noppes.npcs.scripted.CustomNPCsException;
2025-04-28 03:25:01 -04:00
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
2025-04-28 03:25:01 -04:00
public class Action implements IAction {
protected final ActionManager manager;
2025-07-02 21:14:58 +03:00
protected IActionQueue queue;
protected boolean isScheduled;
2025-04-28 03:25:01 -04:00
protected final String name;
protected int startAfterTicks;
protected int count, maxCount = -1;
protected int duration, maxDuration = -1;
2025-04-28 03:25:01 -04:00
protected int updateEveryXTick = 5;
protected Consumer<IAction> task, onStart, onDone;
2025-06-28 09:30:21 +03:00
protected boolean done;
protected final Map<String, Object> dataStore = new HashMap<>();
protected boolean isThreaded;
2025-06-29 20:59:43 +03:00
protected ActionThread actionThread;
protected ScriptContainer reportTo;
//allows chaining .before() and .after() on unscheduled actions
protected ActionList unscheduledList;
public Action(ActionManager manager, String name) {
2025-04-28 03:25:01 -04:00
this.manager = manager;
this.name = name;
if (ScriptContainer.Current != null)
reportTo = ScriptContainer.Current;
2025-04-28 03:25:01 -04:00
}
public Action(ActionManager manager, Consumer<IAction> task) {
this(manager, Integer.toHexString(task.hashCode()), task);
2025-04-28 03:25:01 -04:00
}
public Action(ActionManager manager, String name, Consumer<IAction> task) {
this(manager, name);
this.task = task;
2025-04-28 03:25:01 -04:00
}
public Action(ActionManager manager, int startAfterTicks, Consumer<IAction> task) {
2025-04-28 03:25:01 -04:00
this(manager, task);
this.startAfterTicks = startAfterTicks;
}
public Action(ActionManager manager, String name, int startAfterTicks, Consumer<IAction> task) {
this(manager, name, task);
this.startAfterTicks = startAfterTicks;
}
public Action(ActionManager manager, int maxDuration, int startAfterTicks, Consumer<IAction> task) {
2025-06-30 07:15:34 +03:00
this(manager, startAfterTicks, task);
this.maxDuration = maxDuration;
}
public Action(ActionManager manager, String name, int maxDuration, int startAfterTicks, Consumer<IAction> task) {
this(manager, name, startAfterTicks, task);
this.maxDuration = maxDuration;
}
2025-07-02 21:25:58 +03:00
@Override
2025-07-03 23:17:25 +03:00
public IActionManager getManager() {
2025-07-02 21:25:58 +03:00
return manager;
}
@Override
public String getName() {
return name;
}
2025-07-02 21:14:58 +03:00
@Override
public IActionQueue getQueue() {
return queue;
}
2025-07-07 13:08:51 +03:00
public String getQueueName() {
return queue != null ? queue.getName() : "null";
}
2025-07-02 21:14:58 +03:00
@Override
public IAction setQueue(IActionQueue queue) {
if (this.queue == queue)
return this;
if (this.queue != null)
this.queue.getQueue().remove(this);
this.queue = queue;
queue.schedule(this);
return this;
}
2025-07-06 23:57:20 +03:00
protected void schedule(IActionQueue queue) {
queue.getQueue().add(this);
this.queue = queue;
this.isScheduled = true;
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-08 12:00:37 +03:00
manager.LOGGER.log(String.format("Scheduled %s", getIdentifier()), queue);
2025-07-06 23:57:20 +03:00
}
2025-07-02 21:25:58 +03:00
@Override
public boolean isScheduled() {
return isScheduled;
}
2025-04-28 03:25:01 -04:00
@Override
public IAction setTask(Consumer<IAction> task) {
this.task = task;
return this;
}
@Override
public IAction onStart(Consumer<IAction> task) {
this.onStart = task;
return this;
}
@Override
public IAction onDone(Consumer<IAction> task) {
this.onDone = task;
return this;
}
2025-07-02 21:25:58 +03:00
@Override
public int getDuration() {
return duration;
2025-06-29 21:06:15 +03:00
}
2025-07-02 21:25:58 +03:00
@Override
public int getMaxDuration() {
return maxDuration;
}
2025-07-02 21:25:58 +03:00
@Override
public IAction setMaxDuration(int ticks) {
this.maxDuration = Math.max(-1, ticks);
return this;
2025-04-28 03:25:01 -04:00
}
2025-04-28 10:42:47 +03:00
@Override
2025-07-02 21:25:58 +03:00
public int getStartAfterTicks() {
return startAfterTicks;
2025-04-28 10:42:47 +03:00
}
@Override
2025-07-02 21:25:58 +03:00
public int getUpdateEvery() {
return updateEveryXTick;
}
2025-07-02 21:25:58 +03:00
@Override
public IAction updateEvery(int x) {
this.updateEveryXTick = Math.max(1, x);
return this;
}
2025-07-05 10:19:11 +03:00
@Override
public IAction everyTick() {
this.updateEveryXTick = 1;
return this;
}
@Override
public IAction everySecond() {
this.updateEveryXTick = 20;
return this;
}
2025-04-28 03:25:01 -04:00
@Override
public int getCount() {
return count;
}
@Override
2025-07-02 21:25:58 +03:00
public int getMaxCount() {
return maxCount;
2025-04-28 03:25:01 -04:00
}
@Override
2025-07-02 21:25:58 +03:00
public IAction times(int n) {
this.maxCount = Math.max(-1, n);
return this;
2025-04-28 03:25:01 -04:00
}
@Override
2025-07-02 21:25:58 +03:00
public IAction once() {
this.maxCount = 1;
return this;
2025-04-28 03:25:01 -04:00
}
@Override
2025-07-02 21:25:58 +03:00
public Object getData(String key) {
return dataStore.get(key);
2025-04-28 03:25:01 -04:00
}
@Override
2025-07-02 21:25:58 +03:00
public IAction setData(String key, Object v) {
dataStore.put(key, v);
return this;
}
@Override
2025-07-02 21:25:58 +03:00
public IAction removeData(String key) {
dataStore.remove(key);
return this;
}
2025-07-07 00:21:51 +03:00
@Override
public IAction copyDataTo(IAction to) {
((Action) to).dataStore.putAll(dataStore);
return this;
}
@Override
public String printData() {
if (dataStore.isEmpty()) {
return String.format("Action[name=%s] dataStore is empty", name);
}
StringBuilder sb = new StringBuilder();
sb.append(String.format("Action[name=%s] dataStore contents:\n", name));
for (Map.Entry<String, Object> entry : dataStore.entrySet()) {
sb.append(String.format(" %s = %s\n", entry.getKey(), entry.getValue()));
}
return sb.toString();
}
@Override
2025-07-02 21:25:58 +03:00
public boolean hasData(String key) {
return dataStore.containsKey(key);
}
2025-04-28 03:25:01 -04:00
@Override
public void markDone() {
done = true;
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 21:22:34 +03:00
manager.LOGGER.log("Marked done!", this);
2025-04-28 03:25:01 -04:00
}
@Override
public boolean isDone() {
return done;
}
2025-07-02 21:25:58 +03:00
///////////////////////////////////////////////////
//////////////////////////////////////////////////
2025-07-08 21:31:55 +03:00
// Listener
public IAction listenTo(String hook, Object object) {
return listenTo(hook, manager.getOrCreateListener(object));
}
public IAction listenTo(String hook, IActionListener listener) {
return listenTo(listener.getOrCreateHook(hook));
}
public IAction listenTo(ActionListener.Hook hook) {
hook.schedule(this);
return this;
}
///////////////////////////////////////////////////
//////////////////////////////////////////////////
2025-07-02 21:25:58 +03:00
// Handling
@Override
public IAction start() {
manager.start();
return this;
}
public void tick() {
2025-07-02 21:25:58 +03:00
if (done)
return;
2025-07-07 22:41:58 +03:00
if (startAfterTicks > 0) {
manager.LOGGER.log(String.format("Starts after %s ticks...", startAfterTicks), this);
startAfterTicks--;
return;
}
if (duration == 0 && onStart != null)
2025-07-08 12:00:37 +03:00
execute("onStart", this::executeOnStart);
2025-07-07 12:23:34 +03:00
if (done)
return;
duration++;
2025-07-07 22:41:58 +03:00
inheritedTick();
2025-07-07 13:08:51 +03:00
2025-07-02 21:25:58 +03:00
if (maxDuration > -1 && duration >= maxDuration || maxCount == 0) {
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 21:22:34 +03:00
manager.LOGGER.log("Reached max duration", this);
2025-07-07 13:08:51 +03:00
2025-07-02 21:25:58 +03:00
markDone();
return;
}
2025-07-02 21:25:58 +03:00
2025-07-07 13:08:51 +03:00
if (maxCount > -1 && count >= maxCount) {
if (manager.debug)
2025-07-07 22:41:58 +03:00
manager.LOGGER.log("Reached max count", this);
2025-07-07 13:08:51 +03:00
2025-07-02 21:25:58 +03:00
markDone();
2025-07-07 13:08:51 +03:00
}
2025-07-02 21:25:58 +03:00
}
2025-07-07 22:41:58 +03:00
public void inheritedTick() {
if (manager.debug)
manager.LOGGER.log(String.format("Ticking... (duration = %s/%s, count = %s/%s)", duration, maxDuration, count, maxCount), this);
if (duration % updateEveryXTick == 0 && task != null)
execute("task", this::executeTask);
}
2025-07-06 23:57:20 +03:00
public void execute(String taskName, Runnable task) {
if (isThreaded)
actionThread.execute(taskName, task);
else
task.run();
}
protected void executeOnStart() {
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 21:22:34 +03:00
manager.LOGGER.log("Executing onStart task...", this);
try {
onStart.accept(this);
} catch (Throwable t) {
2025-07-07 21:22:34 +03:00
manager.LOGGER.error("onStart Task of " + this + " threw an exception:", t);
}
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 21:22:34 +03:00
manager.LOGGER.log("Finished executing onStart task", this);
}
2025-07-02 21:25:58 +03:00
protected void executeTask() {
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 21:22:34 +03:00
manager.LOGGER.log("Executing task...", this);
2025-07-07 13:08:51 +03:00
2025-07-02 21:25:58 +03:00
try {
task.accept(this);
count++;
} catch (Throwable t) {
2025-07-07 21:22:34 +03:00
manager.LOGGER.error("Task of " + this + " threw an exception:", t);
2025-07-02 21:25:58 +03:00
markDone();
}
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 22:41:58 +03:00
manager.LOGGER.log(String.format("Finished executing task (count = %s/%s)", count, maxCount), this);
2025-07-02 21:25:58 +03:00
}
protected void executeOnDone() {
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 21:22:34 +03:00
manager.LOGGER.log("Executing onDone task...", this);
2025-07-07 13:08:51 +03:00
try {
onDone.accept(this);
} catch (Throwable t) {
2025-07-07 21:22:34 +03:00
manager.LOGGER.error("onDone Task of " + this + " threw an exception:", t);
}
2025-07-07 13:08:51 +03:00
if (manager.debug)
2025-07-07 21:22:34 +03:00
manager.LOGGER.log("Finished executing onDone task", this);
}
2025-06-30 08:59:51 +03:00
@Override
2025-06-29 09:44:20 +03:00
public void kill() {
if (manager.debug)
2025-07-08 12:00:37 +03:00
manager.LOGGER.log(String.format("Killing %s...", getIdentifier()), queue);
2025-06-29 20:59:43 +03:00
if (actionThread != null)
actionThread.stop();
2025-06-30 08:59:51 +03:00
dataStore.clear();
isScheduled = false;
2025-06-30 08:59:51 +03:00
done = true;
2025-07-06 23:57:20 +03:00
}
2025-07-08 12:00:37 +03:00
@Override
public String getIdentifier() {
return String.format("%s '%s'", getClass().getSimpleName(), name);
}
public String toString() {
2025-07-08 12:00:37 +03:00
return String.format("%s [queue='%s', scheduled=%s, done=%s, paused=%s, updateEvery=%s, duration=%d/%d, count=%d/%d, threaded=%s]", getIdentifier(), getQueueName(), isScheduled, done, isPaused(), updateEveryXTick, duration, maxDuration, count, maxCount, isThreaded);
}
2025-07-02 21:25:58 +03:00
///////////////////////////////////////////////////
//////////////////////////////////////////////////
// Thread
2025-04-28 03:25:01 -04:00
@Override
2025-07-02 21:25:58 +03:00
public IAction threadify() {
if (!isThreaded) {
isThreaded = true;
actionThread = new ActionThread(this);
}
2025-04-28 03:25:01 -04:00
return this;
}
2025-05-30 04:07:56 +03:00
@Override
2025-07-02 21:25:58 +03:00
public void resume() {
if (isThreaded)
actionThread.resume();
2025-04-28 03:25:01 -04:00
}
@Override
2025-07-02 21:25:58 +03:00
public void pause() {
if (isThreaded)
actionThread.pause();
else
throw new CustomNPCsException("Must threadify() IAction before pausing!");
2025-04-28 03:25:01 -04:00
}
@Override
public IAction pauseFor(int ticks) {
2025-06-28 09:30:21 +03:00
if (isThreaded)
2025-06-29 20:59:43 +03:00
actionThread.pauseFor(ticks);
else
this.startAfterTicks = ticks;
2025-06-28 09:30:21 +03:00
2025-04-28 03:25:01 -04:00
return this;
}
2025-06-28 09:30:21 +03:00
@Override
public IAction pauseFor(long millis) {
if (isThreaded) {
2025-06-29 20:59:43 +03:00
actionThread.pauseFor(millis);
return this;
}
2025-06-28 09:30:21 +03:00
return pauseFor((int) (millis / 50));
}
@Override
public void pauseUntil(Function<IAction, Boolean> until) {
if (isThreaded)
2025-06-29 20:59:43 +03:00
actionThread.pauseUntil(until);
else
throw new CustomNPCsException("Must threadify() IAction before pausing!");
}
2025-06-28 09:30:21 +03:00
@Override
public boolean isPaused() {
if (isThreaded)
2025-06-29 20:59:43 +03:00
return actionThread.isPaused();
2025-06-28 09:30:21 +03:00
return startAfterTicks > 0;
}
2025-07-02 21:14:58 +03:00
///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Sequential
2025-04-28 03:25:01 -04:00
2025-07-02 21:14:58 +03:00
@Override
public IAction getNext() {
if (queue == null)
return null;
boolean seenMe = false;
for (IAction a : queue.getQueue()) {
if (seenMe) {
return a;
}
if (a == this) {
seenMe = true;
}
}
return null;
}
@Override
public IAction getPrevious() {
if (queue == null)
return null;
IAction prev = null;
for (IAction a : queue.getQueue()) {
if (a == this) {
return prev;
}
prev = a;
}
return null;
}
2025-04-28 03:25:01 -04:00
@Override
public IAction after(IAction after) {
if (after instanceof IConditionalAction)
return conditional((IConditionalAction) after);
2025-07-02 21:14:58 +03:00
int idx = queue == null ? -1 : queue.getIndex(this);
if (idx >= 0 && !queue.isParallel())
2025-07-02 21:14:58 +03:00
queue.scheduleActionAt(idx + 1, after);
else {
if (unscheduledList == null)
unscheduledList = new ActionList(this);
unscheduledList.after(this, (Action) after);
}
2025-04-28 03:25:01 -04:00
return after;
}
2025-07-02 11:51:00 +03:00
@Override
public void after(IAction... actions) {
for (int i = 0; i < actions.length - 1; i++)
actions[i].after(actions[i + 1]);
}
@Override
public void after(Consumer<IAction>... tasks) {
IAction[] actions = new IAction[tasks.length];
for (int i = 0; i < tasks.length; i++)
actions[i] = manager.create(tasks[i]);
after(actions);
}
2025-04-28 03:25:01 -04:00
@Override
public IAction after(String name, int maxDuration, int delay, Consumer<IAction> t) {
return after(manager.create(name, maxDuration, delay, t));
}
@Override
public IAction after(String name, int delay, Consumer<IAction> t) {
return after(manager.create(name, delay, t));
}
@Override
public IAction after(int delay, Consumer<IAction> t) {
return after(manager.create(delay, t));
}
@Override
public IAction after(String name, Consumer<IAction> t) {
return after(manager.create(name, t));
}
@Override
public IAction after(Consumer<IAction> t) {
return after(manager.create(t));
}
@Override
public IAction before(IAction before) {
if (before instanceof IConditionalAction)
return conditional((IConditionalAction) before);
2025-07-02 21:14:58 +03:00
int idx = queue == null ? -1 : queue.getIndex(this);
if (idx >= 0 && !queue.isParallel())
2025-07-02 21:14:58 +03:00
queue.scheduleActionAt(Math.max(0, idx), before);
else {
if (unscheduledList == null)
unscheduledList = new ActionList(this);
unscheduledList.before(this, (Action) before);
}
2025-04-28 03:25:01 -04:00
return before;
}
@Override
public IAction before(String name, int maxDuration, int delay, Consumer<IAction> t) {
return before(manager.create(name, maxDuration, delay, t));
}
@Override
public IAction before(String name, int delay, Consumer<IAction> t) {
return before(manager.create(name, delay, t));
}
@Override
public IAction before(int delay, Consumer<IAction> t) {
return before(manager.create(delay, t));
}
@Override
public IAction before(String name, Consumer<IAction> t) {
return before(manager.create(name, t));
}
@Override
public IAction before(Consumer<IAction> t) {
return before(manager.create(t));
}
2025-06-30 07:15:34 +03:00
2025-07-02 21:14:58 +03:00
///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Parallels
2025-06-30 07:15:34 +03:00
@Override
2025-07-02 21:14:58 +03:00
public IAction parallel(IAction act) {
if (unscheduledList != null)
((Action) act).unscheduledList = unscheduledList;
2025-07-02 21:14:58 +03:00
if (queue != null && queue.isParallel() && queue != manager.conditionalQueue)
return queue.schedule(act);
return manager.scheduleParallel(act);
2025-06-30 07:15:34 +03:00
}
2025-07-02 11:51:00 +03:00
@Override
public void parallel(IAction... actions) {
for (IAction act : actions)
parallel(act);
}
2025-06-30 07:15:34 +03:00
@Override
public IAction parallel(Consumer<IAction> task) {
return parallel(manager.create(task));
}
2025-07-02 11:51:00 +03:00
@Override
public void parallel(Consumer<IAction>... tasks) {
for (Consumer<IAction> task : tasks)
parallel(task);
}
2025-06-30 07:15:34 +03:00
@Override
public IAction parallel(int delay, Consumer<IAction> task) {
return parallel(manager.create(delay, task));
}
@Override
public IAction parallel(String name, Consumer<IAction> task) {
return parallel(manager.create(name, task));
}
@Override
public IAction parallel(String name, int startAfterTicks, Consumer<IAction> task) {
return parallel(manager.create(name, startAfterTicks, task));
}
@Override
public IAction parallel(String name, int maxDuration, int delay, Consumer<IAction> t) {
return parallel(manager.create(name, maxDuration, delay, t));
}
2025-07-02 21:25:58 +03:00
///////////////////////////////////////////////////
///////////////////////////////////////////////////
// Conditionals
2025-07-04 00:10:12 +03:00
@Override
public IConditionalAction conditional(IConditionalAction after) {
if (unscheduledList != null)
((Action) after).unscheduledList = unscheduledList;
2025-07-04 00:10:12 +03:00
return manager.schedule(after);
}
2025-07-02 21:25:58 +03:00
@Override
public void conditional(IConditionalAction... actions) {
for (IConditionalAction act : actions)
conditional(act);
}
@Override
public IConditionalAction conditional(Function<IAction, Boolean> condition, Consumer<IAction> task) {
return conditional(manager.create(condition, task));
}
@Override
public IConditionalAction conditional(String name, Function<IAction, Boolean> condition, Consumer<IAction> task) {
return conditional(manager.create(name, condition, task));
}
@Override
public IConditionalAction conditional(Function<IAction, Boolean> condition, Consumer<IAction> task, Function<IAction, Boolean> terminateWhen) {
return conditional(manager.create(condition, task, terminateWhen));
}
@Override
public IConditionalAction conditional(String name, Function<IAction, Boolean> condition, Consumer<IAction> task, Function<IAction, Boolean> terminateWhen) {
return conditional(manager.create(name, condition, task, terminateWhen));
}
@Override
public IConditionalAction conditional(Function<IAction, Boolean> condition, Consumer<IAction> task, Function<IAction, Boolean> terminateWhen, Consumer<IAction> onTermination) {
return conditional(manager.create(condition, task, terminateWhen, onTermination));
}
@Override
public IConditionalAction conditional(String name, Function<IAction, Boolean> condition, Consumer<IAction> task, Function<IAction, Boolean> terminateWhen, Consumer<IAction> onTermination) {
return conditional(manager.create(name, condition, task, terminateWhen, onTermination));
}
2025-04-28 03:25:01 -04:00
}