diff --git a/core/src/main/java/tc/oc/pgm/action/ActionParser.java b/core/src/main/java/tc/oc/pgm/action/ActionParser.java index 641bcfafef..6d66e74db7 100644 --- a/core/src/main/java/tc/oc/pgm/action/ActionParser.java +++ b/core/src/main/java/tc/oc/pgm/action/ActionParser.java @@ -32,7 +32,6 @@ import tc.oc.pgm.api.filter.Filter; import tc.oc.pgm.api.filter.Filterables; import tc.oc.pgm.api.map.factory.MapFactory; -import tc.oc.pgm.api.match.Match; import tc.oc.pgm.features.FeatureDefinitionContext; import tc.oc.pgm.features.XMLFeatureReference; import tc.oc.pgm.filters.Filterable; @@ -87,16 +86,10 @@ public > Action parse(Element el, @Nullable C if (bound != null) validate(result, ActionScopeValidation.of(bound), node); if (result instanceof ActionDefinition) { if (XMLUtils.parseBoolean(Node.fromAttr(el, "expose"), false)) { - if (id == null) throw new InvalidXMLException("Attribute 'id' is required for exposed actions", el); - if (!result.getScope().isAssignableFrom(Match.class)) - throw new InvalidXMLException("Match scope is required for exposed actions", el); - - result = - (ActionDefinition) - new ExposedAction(id, (ActionDefinition) result); + result = new ExposedAction(id, (ActionDefinition>) result); } features.addFeature(el, (ActionDefinition) result); diff --git a/core/src/main/java/tc/oc/pgm/action/actions/ExposedAction.java b/core/src/main/java/tc/oc/pgm/action/actions/ExposedAction.java index 3eb9401d69..22a5edc5bf 100644 --- a/core/src/main/java/tc/oc/pgm/action/actions/ExposedAction.java +++ b/core/src/main/java/tc/oc/pgm/action/actions/ExposedAction.java @@ -2,40 +2,55 @@ import tc.oc.pgm.action.ActionDefinition; import tc.oc.pgm.api.feature.Feature; -import tc.oc.pgm.api.match.Match; import tc.oc.pgm.features.SelfIdentifyingFeatureDefinition; +import tc.oc.pgm.filters.Filterable; /** * Wraps an action definition to consider it exposed. This is an easy way to avoid needing each * specialized action to implement a way to expose itself or not. */ public class ExposedAction extends SelfIdentifyingFeatureDefinition - implements ActionDefinition, Feature> { + implements ActionFeature> { - private final ActionDefinition delegate; + private final ActionDefinition> delegate; - public ExposedAction(String id, ActionDefinition delegate) { + public ExposedAction(String id, ActionDefinition> delegate) { super(id); this.delegate = delegate; } @Override - public ActionDefinition getDefinition() { + public ActionDefinition> getDefinition() { return delegate; } @Override - public Class getScope() { - return Match.class; + public Class> getScope() { + return delegate.getScope(); } @Override - public void trigger(Match m) { - delegate.trigger(m); + public void trigger(Filterable scope) { + delegate.trigger(getAncestor(scope)); } @Override - public void untrigger(Match m) { - delegate.untrigger(m); + public void untrigger(Filterable scope) { + delegate.untrigger(getAncestor(scope)); + } + + protected Filterable getAncestor(Filterable context) { + Filterable filterable = context.getFilterableAncestor(delegate.getScope()); + if (filterable != null) return filterable; + + throw new IllegalStateException( + "Wrong exposed scope for '" + + getId() + + "', expected " + + delegate.getScope().getSimpleName() + + " which cannot be found in " + + context.getClass().getSimpleName()); } } + +interface ActionFeature extends Feature>, ActionDefinition {} diff --git a/core/src/main/java/tc/oc/pgm/command/ActionCommand.java b/core/src/main/java/tc/oc/pgm/command/ActionCommand.java index c74e9adf8e..c95bf01df3 100644 --- a/core/src/main/java/tc/oc/pgm/command/ActionCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/ActionCommand.java @@ -1,6 +1,7 @@ package tc.oc.pgm.command; import static net.kyori.adventure.text.Component.text; +import static tc.oc.pgm.command.util.ParserConstants.CURRENT; import cloud.commandframework.annotations.Argument; import cloud.commandframework.annotations.CommandDescription; @@ -17,7 +18,8 @@ import tc.oc.pgm.action.ActionMatchModule; import tc.oc.pgm.action.actions.ExposedAction; import tc.oc.pgm.api.Permissions; -import tc.oc.pgm.api.match.Match; +import tc.oc.pgm.api.player.MatchPlayer; +import tc.oc.pgm.filters.Filterable; import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.PrettyPaginatedComponentResults; import tc.oc.pgm.util.text.TextFormatter; @@ -25,10 +27,23 @@ @CommandMethod("action|actions") public class ActionCommand { + @CommandMethod("[page]") + @CommandDescription("List available exposed actions") + @CommandPermission(Permissions.GAMEPLAY) + public void fallback( + Audience audience, + CommandSender sender, + ActionMatchModule amm, + @Argument(value = "page", defaultValue = "1") int page, + @Flag(value = "query", aliases = "q") String query, + @Flag(value = "all", aliases = "a") boolean all) { + list(audience, sender, amm, page, query, all); + } + @CommandMethod("list|page [page]") - @CommandDescription("Inspect variables for a player") + @CommandDescription("List available exposed actions") @CommandPermission(Permissions.GAMEPLAY) - public void showActions( + public void list( Audience audience, CommandSender sender, ActionMatchModule amm, @@ -59,21 +74,25 @@ public void showActions( (v, i) -> text((i + 1) + ". ").append(text(v.getId(), NamedTextColor.AQUA))); } - @CommandMethod("trigger [action]") + @CommandMethod("trigger [target]") @CommandDescription("Trigger a specific action") @CommandPermission(Permissions.GAMEPLAY) - public void triggerAction( - Audience audience, Match match, @Argument("action") @Greedy ExposedAction action) { - action.trigger(match); + public > void triggerAction( + Audience audience, + @Argument("action") @Greedy ExposedAction action, + @Argument(value = "target", defaultValue = CURRENT) MatchPlayer target) { + action.trigger(target); audience.sendMessage(text("Triggered " + action.getId())); } - @CommandMethod("untrigger [action]") + @CommandMethod("untrigger [target]") @CommandDescription("Untrigger a specific action") @CommandPermission(Permissions.GAMEPLAY) - public void untriggerAction( - Audience audience, Match match, @Argument("action") @Greedy ExposedAction action) { - action.untrigger(match); + public > void untriggerAction( + Audience audience, + @Argument("action") @Greedy ExposedAction action, + @Argument(value = "target", defaultValue = CURRENT) MatchPlayer target) { + action.untrigger(target); audience.sendMessage(text("Untriggered " + action.getId())); } }