Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support arbitrary scopes in exposed actions #1279

Merged
merged 2 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()));
}
}