Skip to content

Commit

Permalink
Implement array variable type (#1274)
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Herrera <[email protected]>
  • Loading branch information
Pablete1234 authored Nov 22, 2023
1 parent 4bb14ae commit a9b3762
Show file tree
Hide file tree
Showing 19 changed files with 496 additions and 154 deletions.
10 changes: 7 additions & 3 deletions core/src/main/java/tc/oc/pgm/action/ActionParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,14 @@ public <T extends Filterable<?>> SetVariableAction<T> parseSetVariable(Element e
+ scope.getSimpleName(),
el);

String expression = Node.fromRequiredAttr(el, "value").getValue();
Formula<T> formula =
Formula.of(
expression, variables.getVariableNames(scope), variables.getContextBuilder(scope));
Formula.of(Node.fromRequiredAttr(el, "value").getValue(), variables.getContext(scope));

if (var.isIndexed()) {
Formula<T> idx =
Formula.of(Node.fromRequiredAttr(el, "index").getValue(), variables.getContext(scope));
return new SetVariableAction.Indexed<>(scope, var, idx, formula);
}

return new SetVariableAction<>(scope, var, formula);
}
Expand Down
23 changes: 21 additions & 2 deletions core/src/main/java/tc/oc/pgm/action/actions/SetVariableAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import tc.oc.pgm.filters.Filterable;
import tc.oc.pgm.util.math.Formula;
import tc.oc.pgm.variables.VariableDefinition;
import tc.oc.pgm.variables.types.IndexedVariable;

public class SetVariableAction<T extends Filterable<?>> extends AbstractAction<T> {

private final VariableDefinition<?> variable;
private final Formula<T> formula;
protected final VariableDefinition<?> variable;
protected final Formula<T> formula;

public SetVariableAction(Class<T> scope, VariableDefinition<?> variable, Formula<T> formula) {
super(scope);
Expand All @@ -19,4 +20,22 @@ public SetVariableAction(Class<T> scope, VariableDefinition<?> variable, Formula
public void trigger(T t) {
variable.getVariable(t.getMatch()).setValue(t, formula.applyAsDouble(t));
}

public static class Indexed<T extends Filterable<?>> extends SetVariableAction<T> {

private final Formula<T> idx;

public Indexed(
Class<T> scope, VariableDefinition<?> variable, Formula<T> idx, Formula<T> formula) {
super(scope, variable, formula);
this.idx = idx;
}

@Override
@SuppressWarnings("unchecked")
public void trigger(T t) {
((IndexedVariable<T>) variable.getVariable(t.getMatch()))
.setValue(t, (int) idx.applyAsDouble(t), formula.applyAsDouble(t));
}
}
}
26 changes: 24 additions & 2 deletions core/src/main/java/tc/oc/pgm/command/MapDevCommand.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tc.oc.pgm.command;

import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static tc.oc.pgm.command.util.ParserConstants.CURRENT;

Expand All @@ -11,7 +12,9 @@
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.CommandSender;
import tc.oc.pgm.api.Permissions;
Expand All @@ -22,9 +25,13 @@
import tc.oc.pgm.util.PrettyPaginatedComponentResults;
import tc.oc.pgm.util.text.TextFormatter;
import tc.oc.pgm.variables.Variable;
import tc.oc.pgm.variables.types.IndexedVariable;

public class MapDevCommand {

// Avoid showing too many values. Messages that are too long kick the client.
private static final int ARRAY_CAP = 16;

@CommandMethod("variables [target] [page]")
@CommandDescription("Inspect variables for a player")
@CommandPermission(Permissions.DEBUG)
Expand Down Expand Up @@ -64,8 +71,23 @@ public void showVariables(
page,
resultsPerPage,
header,
(v, i) ->
text().append(text(v.getId() + ": ", NamedTextColor.AQUA), text(v.getValue(target))));
(v, pageIndex) -> {
Component value;
if (v.isIndexed()) {
IndexedVariable<?> idx = (IndexedVariable<?>) v;
value =
join(
JoinConfiguration.commas(true),
IntStream.range(0, Math.min(ARRAY_CAP, idx.size()))
.mapToObj(i -> text(idx.getValue(target, i)))
.collect(Collectors.toList()));
if (idx.size() > ARRAY_CAP) value = value.append(text(" ..."));
} else {
value = text(v.getValue(target));
}

return text().append(text(v.getId() + ": ", NamedTextColor.AQUA), value);
});
}

@CommandMethod("variable set <variable> <value> [target]")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,58 @@
package tc.oc.pgm.filters.matcher.match;

import com.google.common.collect.Range;
import tc.oc.pgm.api.filter.FilterDefinition;
import tc.oc.pgm.api.filter.Filterables;
import tc.oc.pgm.api.filter.query.MatchQuery;
import tc.oc.pgm.api.filter.query.PartyQuery;
import tc.oc.pgm.api.filter.query.Query;
import tc.oc.pgm.api.party.Competitor;
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.filters.Filterable;
import tc.oc.pgm.filters.matcher.WeakTypedFilter;
import tc.oc.pgm.filters.matcher.party.CompetitorFilter;
import tc.oc.pgm.util.xml.InvalidXMLException;
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.variables.Variable;
import tc.oc.pgm.variables.VariableDefinition;
import tc.oc.pgm.variables.types.IndexedVariable;

public class VariableFilter implements FilterDefinition {
public abstract class VariableFilter<Q extends MatchQuery> implements WeakTypedFilter<Q> {

private final VariableDefinition<?> variable;
private final Range<Double> values;

public VariableFilter(VariableDefinition<?> variable, Range<Double> values) {
private VariableFilter(VariableDefinition<?> variable, Range<Double> values) {
this.variable = variable;
this.values = values;
}

public static VariableFilter<?> of(
VariableDefinition<?> var, Integer idx, Range<Double> range, Node node)
throws InvalidXMLException {
if (var.isIndexed()) {
if (idx == null)
throw new InvalidXMLException("Array variables must contain an index.", node);
return var.getScope() == Party.class
? new TeamIndexed(var, idx, range)
: new Indexed(var, idx, range);
} else {
if (idx != null)
throw new InvalidXMLException("Non-array variables cannot contain an index.", node);
return var.getScope() == Party.class ? new Team(var, range) : new Generic(var, range);
}
}

@Override
public QueryResponse query(Query query) {
Filterable<?> filterable =
query instanceof MatchQuery ? ((MatchQuery) query).extractFilterable() : null;
public QueryResponse queryTyped(Q query) {
Filterable<?> filterable = query.extractFilterable();
if (!Filterables.isAssignable(filterable, variable.getScope())) return QueryResponse.ABSTAIN;

return QueryResponse.fromBoolean(
values.contains(variable.getVariable(filterable.getMatch()).getValue(filterable)));
values.contains(getValue(variable.getVariable(filterable.getMatch()), filterable)));
}

protected double getValue(Variable<?> variable, Filterable<?> filterable) {
return variable.getValue(filterable);
}

@Override
Expand All @@ -44,4 +71,64 @@ public boolean isDynamic() {
public String toString() {
return "VariableFilter{" + "variable=" + variable + ", values=" + values + '}';
}

public static class Generic extends VariableFilter<MatchQuery> {

public Generic(VariableDefinition<?> variable, Range<Double> values) {
super(variable, values);
}

@Override
public Class<? extends MatchQuery> queryType() {
return MatchQuery.class;
}
}

/**
* Specialization for team variables implementing CompetitorFilter. Allows team to be set to a
* specific one.
*/
public static class Team extends VariableFilter<PartyQuery> implements CompetitorFilter {

public Team(VariableDefinition<?> variable, Range<Double> values) {
super(variable, values);
}

@Override
public boolean matches(MatchQuery query, Competitor competitor) {
QueryResponse response = super.query(competitor);
if (!response.isPresent())
throw new UnsupportedOperationException(
"Filter " + this + " did not respond to the query " + query);
return response.isAllowed();
}
}

public static class Indexed extends Generic {
private final int idx;

public Indexed(VariableDefinition<?> variable, int idx, Range<Double> values) {
super(variable, values);
this.idx = idx;
}

@Override
protected double getValue(Variable<?> variable, Filterable<?> filterable) {
return ((IndexedVariable<?>) variable).getValue(filterable, idx);
}
}

public static class TeamIndexed extends Team {
private final int idx;

public TeamIndexed(VariableDefinition<?> variable, int idx, Range<Double> values) {
super(variable, values);
this.idx = idx;
}

@Override
protected double getValue(Variable<?> variable, Filterable<?> filterable) {
return ((IndexedVariable<?>) variable).getValue(filterable, idx);
}
}
}

This file was deleted.

21 changes: 11 additions & 10 deletions core/src/main/java/tc/oc/pgm/filters/parse/FeatureFilterParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,10 @@ public Filter parseNot(Element el) throws InvalidXMLException {

private static final Pattern INLINE_VARIABLE =
Pattern.compile(
"("
+ VariablesModule.Factory.VARIABLE_ID.pattern()
+ ")\\s*=\\s*("
+ XMLUtils.RANGE_DOTTED.pattern()
+ "|-?\\d*\\.?\\d+)");
"(%VAR%)(?:\\[(\\d+)])?\\s*=\\s*(%RANGE%|%NUM%)"
.replace("%VAR%", VariablesModule.Factory.VARIABLE_ID.pattern())
.replace("%RANGE%", XMLUtils.RANGE_DOTTED.pattern())
.replace("%NUM%", "-?\\d*\\.?\\d+"));

private @Nullable Filter parseInlineFilter(Node node, String text) throws InvalidXMLException {
// Formula-style inline filter
Expand All @@ -114,12 +113,14 @@ public Filter parseNot(Element el) throws InvalidXMLException {
}

// Parse variable filter
Matcher varMatch = INLINE_VARIABLE.matcher(text);
if (varMatch.matches()) {
Matcher match = INLINE_VARIABLE.matcher(text);
if (match.matches()) {
VariableDefinition<?> variable =
features.resolve(node, varMatch.group(1), VariableDefinition.class);
Range<Double> range = XMLUtils.parseNumericRange(node, varMatch.group(2), Double.class);
return new VariableFilter(variable, range);
features.resolve(node, match.group(1), VariableDefinition.class);
Integer index =
match.group(2) == null ? null : XMLUtils.parseNumber(node, match.group(2), Integer.class);
Range<Double> range = XMLUtils.parseNumericRange(node, match.group(3), Double.class);
return VariableFilter.of(variable, index, range, node);
}

return null;
Expand Down
12 changes: 7 additions & 5 deletions core/src/main/java/tc/oc/pgm/filters/parse/FilterParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import tc.oc.pgm.api.filter.Filter;
import tc.oc.pgm.api.filter.FilterDefinition;
import tc.oc.pgm.api.map.factory.MapFactory;
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.api.player.PlayerRelation;
import tc.oc.pgm.api.region.Region;
import tc.oc.pgm.classes.ClassModule;
Expand Down Expand Up @@ -48,7 +47,6 @@
import tc.oc.pgm.filters.matcher.party.RankFilter;
import tc.oc.pgm.filters.matcher.party.ScoreFilter;
import tc.oc.pgm.filters.matcher.party.TeamFilter;
import tc.oc.pgm.filters.matcher.party.TeamVariableFilter;
import tc.oc.pgm.filters.matcher.player.CanFlyFilter;
import tc.oc.pgm.filters.matcher.player.CarryingFlagFilter;
import tc.oc.pgm.filters.matcher.player.CarryingItemFilter;
Expand Down Expand Up @@ -633,11 +631,15 @@ public PlayerCountFilter parsePlayerCountFilter(Element el) throws InvalidXMLExc
public Filter parseVariableFilter(Element el) throws InvalidXMLException {
VariableDefinition<?> varDef =
features.resolve(Node.fromRequiredAttr(el, "var"), VariableDefinition.class);
Integer index = null;
if (varDef.isIndexed())
index = XMLUtils.parseNumber(Node.fromRequiredAttr(el, "index"), Integer.class);
Range<Double> range = XMLUtils.parseNumericRange(new Node(el), Double.class);

if (varDef.getScope() == Party.class)
return parseExplicitTeam(el, new TeamVariableFilter(varDef, range));
else return new VariableFilter(varDef, range);
VariableFilter<?> filter = VariableFilter.of(varDef, index, range, new Node(el));
return filter instanceof CompetitorFilter
? parseExplicitTeam(el, (CompetitorFilter) filter)
: filter;
}

@MethodParser("blocks")
Expand Down
Loading

0 comments on commit a9b3762

Please sign in to comment.