Files
CustomNPC-Plus/src/main/java/noppes/npcs/scripted/ScriptedActionManager.java
T
Kam 666504e0a3 Create better Action Handling
- Conditional Actions
- Action Manager on Player Data
2025-04-26 20:52:08 -04:00

299 lines
8.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package noppes.npcs.scripted;
import noppes.npcs.api.handler.IActionManager;
import noppes.npcs.api.handler.data.IAction;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* Full-featured ActionManager:
* - delayed start, max-duration, tick-interval
* - chaining (getNext, getPrevious, scheduleAfter/Before)
* - per-action data
* - conditional actions
* - cancellation & clearing
*/
public class ScriptedActionManager implements IActionManager {
private boolean isWorking = false;
private final Deque<IAction> actionQueue = new LinkedList<>();
@Override
public IAction create(String name, int maxDuration, int startAfterTicks, Consumer<IAction> task) {
return new Action(name, maxDuration, startAfterTicks, task);
}
@Override
public void start() {
isWorking = true;
}
@Override
public void stop() {
isWorking = false;
}
@Override
public void scheduleAction(IAction action) {
actionQueue.addLast(action);
}
@Override
public void scheduleAction(String name, int maxDuration, int startAfterTicks, Consumer<IAction> task) {
scheduleAction(create(name, maxDuration, startAfterTicks, task));
}
@Override
public void scheduleActionAt(int index, IAction action) {
if (index < 0 || index > actionQueue.size()) {
actionQueue.addLast(action);
} else {
((LinkedList<IAction>) actionQueue).add(index, action);
}
}
@Override
public int getIndex(IAction action) {
if (action == null) return -1;
return ((LinkedList<IAction>) actionQueue).indexOf(action);
}
@Override
public IAction getCurrentAction() {
return actionQueue.peekFirst();
}
@Override
public Queue<IAction> getActionQueue() {
return actionQueue;
}
@Override
public void clear() {
actionQueue.clear();
}
@Override
public boolean cancelAction(String name) {
for (IAction act : actionQueue) {
if (act.getName().equals(name)) {
((LinkedList<IAction>) actionQueue).remove(act);
return true;
}
}
return false;
}
@Override
public void scheduleConditionalAction(String name,
int checkIntervalTicks,
Supplier<Boolean> predicate,
Consumer<IAction> task) {
scheduleConditionalAction(name, checkIntervalTicks, predicate, task, -1);
}
@Override
public void scheduleConditionalAction(String name,
int checkIntervalTicks,
Supplier<Boolean> predicate,
Consumer<IAction> task,
int maxChecks) {
scheduleAction(new ConditionalAction(name, checkIntervalTicks, predicate, task, maxChecks));
}
/**
* Call once per tick from your main loop.
*
* @param ticksExisted the global tick count, used for modulo checks.
*/
public void tick(int ticksExisted) {
if (!isWorking) return;
IAction current = getCurrentAction();
if (current instanceof ActionBase) {
ActionBase cab = (ActionBase) current;
cab.tick(ticksExisted);
if (cab.isDone() || cab.getDuration() >= cab.getMaxDuration()) {
actionQueue.pollFirst();
}
}
}
// ──── base class for all custom actions ──────────────────────────────────
private abstract class ActionBase implements IAction {
protected final String name;
protected int startAfterTicks;
protected int count = 0;
protected int duration = 0;
protected final int maxDuration;
protected int updateEveryXTick = 5;
protected final Consumer<IAction> task;
private boolean done = false;
protected ActionBase(String name, int maxDuration, int startAfterTicks, Consumer<IAction> task) {
this.name = name;
this.maxDuration = maxDuration;
this.startAfterTicks = startAfterTicks;
this.task = task;
}
/**
* Called once per global tick; respects delay, interval, duration & done‐flag.
*/
public void tick(int ticksExisted) {
if (done) return;
if (startAfterTicks > 0) {
startAfterTicks--;
return;
}
// only run on our update tick
if (ticksExisted % updateEveryXTick == 0) {
task.accept(this);
count++;
}
duration++;
}
@Override
public int getCount() {
return count;
}
@Override
public int getDuration() {
return duration;
}
@Override
public String getName() {
return name;
}
@Override
public int getMaxDuration() {
return maxDuration;
}
@Override
public void markDone() {
done = true;
}
@Override
public boolean isDone() {
return done;
}
@Override
public Object getData(String key) {
return dataStore.get(key);
}
@Override
public void addData(String key, Object v) {
dataStore.put(key, v);
}
@Override
public int getUpdateEveryXTick() {
return updateEveryXTick;
}
@Override
public void setUpdateEveryXTick(int x) {
updateEveryXTick = x;
}
@Override
public int getStartAfterTicks() {
return startAfterTicks;
}
@Override
public IAction create(String n, int md, int sat, Consumer<IAction> t) {
return ScriptedActionManager.this.create(n, md, sat, t);
}
@Override
public IAction getNext() {
int idx = getIndex(this);
return (idx >= 0 && idx + 1 < actionQueue.size())
? ((LinkedList<IAction>) actionQueue).get(idx + 1)
: null;
}
@Override
public IAction getPrevious() {
int idx = getIndex(this);
return (idx > 0)
? ((LinkedList<IAction>) actionQueue).get(idx - 1)
: null;
}
@Override
public void scheduleAfter(IAction after) {
int idx = getIndex(this);
if (idx >= 0) scheduleActionAt(idx + 1, after);
}
@Override
public void scheduleBefore(IAction before) {
int idx = getIndex(this);
if (idx >= 0) scheduleActionAt(Math.max(0, idx), before);
}
private final java.util.Map<String, Object> dataStore = new java.util.HashMap<>();
}
private class Action extends ActionBase {
public Action(String name, int maxDuration, int startAfterTicks, Consumer<IAction> task) {
super(name, maxDuration, startAfterTicks, task);
}
@Override public int getCheckCount() { return 0; }
@Override public int getMaxChecks() { return 0; }
}
private class ConditionalAction extends ActionBase {
private final Supplier<Boolean> predicate;
private final int maxChecks;
private int checkCount = 0;
public ConditionalAction(String name,
int checkIntervalTicks,
Supplier<Boolean> predicate,
Consumer<IAction> task,
int maxChecks) {
super(name, Integer.MAX_VALUE, 0, task);
this.predicate = predicate;
this.updateEveryXTick = checkIntervalTicks;
this.maxChecks = maxChecks;
}
@Override
public void tick(int ticksExisted) {
if (isDone()) return;
if (ticksExisted % updateEveryXTick == 0) {
checkCount++;
if (maxChecks >= 0 && checkCount > maxChecks) {
markDone();
return;
}
if (predicate.get()) {
task.accept(this);
markDone();
}
}
}
@Override public int getCheckCount() { return checkCount; }
@Override public int getMaxChecks() { return maxChecks; }
}
}