Skip to content

Commit

Permalink
Support arbitrary scopes in exposed actions (#1279)
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Herrera <[email protected]>
  • Loading branch information
Pablete1234 authored Dec 18, 2023
1 parent 516f1d6 commit 3b3ae70
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 30 deletions.
9 changes: 1 addition & 8 deletions core/src/main/java/tc/oc/pgm/action/ActionParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -87,16 +86,10 @@ public <B extends Filterable<?>> Action<? super B> 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<? super B>)
new ExposedAction(id, (ActionDefinition<? super Match>) result);
result = new ExposedAction(id, (ActionDefinition<Filterable<?>>) result);
}

features.addFeature(el, (ActionDefinition<? super B>) result);
Expand Down
37 changes: 26 additions & 11 deletions core/src/main/java/tc/oc/pgm/action/actions/ExposedAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Match>, Feature<ActionDefinition<? super Match>> {
implements ActionFeature<Filterable<?>> {

private final ActionDefinition<? super Match> delegate;
private final ActionDefinition<Filterable<?>> delegate;

public ExposedAction(String id, ActionDefinition<? super Match> delegate) {
public ExposedAction(String id, ActionDefinition<Filterable<?>> delegate) {
super(id);
this.delegate = delegate;
}

@Override
public ActionDefinition<? super Match> getDefinition() {
public ActionDefinition<Filterable<?>> getDefinition() {
return delegate;
}

@Override
public Class<Match> getScope() {
return Match.class;
public Class<Filterable<?>> 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<S> extends Feature<ActionDefinition<S>>, ActionDefinition<S> {}
41 changes: 30 additions & 11 deletions core/src/main/java/tc/oc/pgm/command/ActionCommand.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -17,18 +18,32 @@
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;

@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,
Expand Down Expand Up @@ -59,21 +74,25 @@ public void showActions(
(v, i) -> text((i + 1) + ". ").append(text(v.getId(), NamedTextColor.AQUA)));
}

@CommandMethod("trigger [action]")
@CommandMethod("trigger <action> [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 <T extends Filterable<?>> 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 <action> [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 <T extends Filterable<?>> 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()));
}
}

0 comments on commit 3b3ae70

Please sign in to comment.