diff --git a/src/main/java/me/retrodaredevil/action/Actions.java b/src/main/java/me/retrodaredevil/action/Actions.java index f9c6e5f..70d5d34 100644 --- a/src/main/java/me/retrodaredevil/action/Actions.java +++ b/src/main/java/me/retrodaredevil/action/Actions.java @@ -71,6 +71,28 @@ public static ActionChooser createActionChooser(WhenDone whenDone){ public static ActionChooser createActionChooserRecyclable(WhenDone whenDone){ return new DefaultActionChooser(true, whenDone); } + + // region Linked Actions + + /** + * @param action The action to run while the returned action is running + * @param nextAction The next action + * @return A LinkedAction that runs the passed action that will have nextAction as its next action. + */ + public static LinkedAction createLinkedAction(Action action, Action nextAction){ + return new LinkedActionWrapper(action, nextAction); + } + + /** + * Creates an {@link Action} that will update the passed action. When the action is done, if it is a {@link LinkedAction}, + * it will be replaced by the {@link Action} from {@link LinkedAction#getNextAction()} + * @param action The action or linked action to update + * @return An {@link Action} that will update the passed action. Cannot be recycled + */ + public static Action createLinkedActionRunner(Action action, WhenDone whenDone, boolean immediatelyDoNextWhenDone){ + return new LinkedActionRunner(whenDone, immediatelyDoNextWhenDone, action); + } + // endregion static abstract class Builder { diff --git a/src/main/java/me/retrodaredevil/action/LinkedAction.java b/src/main/java/me/retrodaredevil/action/LinkedAction.java new file mode 100644 index 0000000..3694f8b --- /dev/null +++ b/src/main/java/me/retrodaredevil/action/LinkedAction.java @@ -0,0 +1,5 @@ +package me.retrodaredevil.action; + +public interface LinkedAction extends Action { + Action getNextAction(); +} diff --git a/src/main/java/me/retrodaredevil/action/LinkedActionRunner.java b/src/main/java/me/retrodaredevil/action/LinkedActionRunner.java new file mode 100644 index 0000000..2ac3059 --- /dev/null +++ b/src/main/java/me/retrodaredevil/action/LinkedActionRunner.java @@ -0,0 +1,83 @@ +package me.retrodaredevil.action; + +import java.util.Collection; +import java.util.Collections; + +class LinkedActionRunner extends SimpleAction implements SingleActiveActionHolder { + + private Action action; + private final WhenDone whenDone; + private final boolean immediatelyDoNextWhenDone; + + public LinkedActionRunner(WhenDone whenDone, boolean immediatelyDoNextWhenDone, Action action) { + super(false); + this.action = action; + this.whenDone = whenDone; + this.immediatelyDoNextWhenDone = immediatelyDoNextWhenDone; + } + + @Override + public Action getActiveAction() { + return action; + } + + @Override + public Collection getActiveActions() { + final Action action = this.action; + if(action == null){ + return Collections.emptySet(); + } + return Collections.singleton(action); + } + + @Override + protected void onUpdate() { + super.onUpdate(); + updateAction(); + } + private void updateAction(){ + boolean done = false; + if(action != null){ + action.update(); + if(action.isDone()){ + final Action nextAction; + if(action instanceof LinkedAction){ + nextAction = ((LinkedAction) action).getNextAction(); + } else { + nextAction = null; + } + if(nextAction == null){ + if(whenDone.isClearActiveWhenActiveDone()){ + endCurrent(); + } + done = true; + } else { + action.end(); + action = nextAction; + if(immediatelyDoNextWhenDone){ + updateAction(); + } + } + } + } else { + done = true; + } + if(whenDone.isBeDoneWhenActiveDone()) { + setDone(done); + } else { + setDone(false); + } + } + + @Override + protected void onEnd(boolean peacefullyEnded) { + super.onEnd(peacefullyEnded); + endCurrent(); + } + private void endCurrent(){ + if(action != null && action.isActive()){ + action.end(); + action = null; + } + } +} diff --git a/src/main/java/me/retrodaredevil/action/LinkedActionWrapper.java b/src/main/java/me/retrodaredevil/action/LinkedActionWrapper.java new file mode 100644 index 0000000..5b339eb --- /dev/null +++ b/src/main/java/me/retrodaredevil/action/LinkedActionWrapper.java @@ -0,0 +1,42 @@ +package me.retrodaredevil.action; + +import java.util.Objects; + +class LinkedActionWrapper implements LinkedAction { + + private final Action action; + private final Action nextAction; + + LinkedActionWrapper(Action action, Action nextAction) { + this.action = Objects.requireNonNull(action); + this.nextAction = nextAction; + if(action.isActive()){ + throw new IllegalArgumentException("action cannot be active!"); + } + } + + @Override + public Action getNextAction() { + return nextAction; + } + + @Override + public void update() { + action.update(); + } + + @Override + public void end() { + action.end(); + } + + @Override + public boolean isDone() { + return action.isDone(); + } + + @Override + public boolean isActive() { + return action.isActive(); + } +} diff --git a/src/main/java/me/retrodaredevil/action/WhenDone.java b/src/main/java/me/retrodaredevil/action/WhenDone.java index fd39ff1..dd14222 100644 --- a/src/main/java/me/retrodaredevil/action/WhenDone.java +++ b/src/main/java/me/retrodaredevil/action/WhenDone.java @@ -4,7 +4,7 @@ * Can be used with the factory methods {@link Actions#createActionChooser(WhenDone)} and {@link Actions#createActionChooserRecyclable(WhenDone)} */ public enum WhenDone { - /** When the active action is done, this will keep going like nothing happened*/ + /** When the active action is done, this will keep going like nothing happened. NOT RECOMMENDED*/ DO_NOTHING(false, false), /** When the active action is done, it will be ended and cleared*/ diff --git a/src/test/java/me/retrodaredevil/action/test/LinkedActionTest.java b/src/test/java/me/retrodaredevil/action/test/LinkedActionTest.java new file mode 100644 index 0000000..cf1cd3f --- /dev/null +++ b/src/test/java/me/retrodaredevil/action/test/LinkedActionTest.java @@ -0,0 +1,48 @@ +package me.retrodaredevil.action.test; + +import me.retrodaredevil.action.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +final class LinkedActionTest { + @Test + void testLinkedActionRunner(){ + final int[] value = {0}; + final Action set1 = Actions.createRunOnce(() -> value[0] = 1); + final Action set2 = Actions.createRunOnce(() -> value[0] = 2); + final Action set3 = Actions.createRunOnce(() -> value[0] = 3); + + final Action runner = Actions.createLinkedActionRunner( + Actions.createLinkedAction(set1, Actions.createLinkedAction(set2, set3)), + WhenDone.CLEAR_ACTIVE_AND_BE_DONE, + false + ); + + assertEquals(0, value[0]); + assertFalse(runner.isActive()); + + runner.update(); + assertEquals(1, value[0]); + assertFalse(set1.isActive()); + assertTrue(runner.isActive()); + assertFalse(runner.isDone()); + + runner.update(); + assertEquals(2, value[0]); + assertFalse(set1.isActive()); + assertFalse(set2.isActive()); // it should have started and ended + assertTrue(runner.isActive()); + assertFalse(runner.isDone()); + + runner.update(); + assertEquals(3, value[0]); + assertFalse(set2.isActive()); + assertFalse(set3.isActive()); + assertTrue(runner.isActive()); + + assertTrue(runner.isDone()); + runner.end(); + } + +}