Skip to content

Commit

Permalink
Add support for variables acting on Blitz Lives (#1214)
Browse files Browse the repository at this point in the history
Signed-off-by: Christopher White <[email protected]>
  • Loading branch information
cswhite2000 authored Aug 23, 2023
1 parent 4c442f1 commit 87278fe
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 58 deletions.
39 changes: 25 additions & 14 deletions core/src/main/java/tc/oc/pgm/blitz/BlitzMatchModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ public int getNumOfLives(UUID id) {
return lifeManager.getLives(id);
}

public void setLives(MatchPlayer matchPlayer, int lives) {
UUID id = matchPlayer.getId();
if (lives == lifeManager.getLives(id)) return;

lifeManager.setLives(id, lives);
if (this.config.getBroadcastLives()) {
this.showLivesTitle(matchPlayer);
}
}

@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void handleDeath(final MatchPlayerDeathEvent event) {
MatchPlayer victim = event.getVictim();
Expand Down Expand Up @@ -123,23 +133,24 @@ public void handleJoin(final PlayerParticipationStartEvent event) {
@EventHandler
public void handleSpawn(final ParticipantSpawnEvent event) {
if (this.config.getBroadcastLives()) {
int lives = this.lifeManager.getLives(event.getPlayer().getId());
event
.getPlayer()
.showTitle(
title(
empty(),
translatable(
"blitz.livesRemaining",
NamedTextColor.RED,
translatable(
lives == 1 ? "misc.life" : "misc.lives",
NamedTextColor.AQUA,
text(lives))),
Title.Times.times(Duration.ZERO, fromTicks(60), fromTicks(20))));
MatchPlayer matchPlayer = event.getPlayer();
showLivesTitle(matchPlayer);
}
}

public void showLivesTitle(MatchPlayer matchPlayer) {
int lives = this.lifeManager.getLives(matchPlayer.getId());
matchPlayer.showTitle(
title(
empty(),
translatable(
"blitz.livesRemaining",
NamedTextColor.RED,
translatable(
lives == 1 ? "misc.life" : "misc.lives", NamedTextColor.AQUA, text(lives))),
Title.Times.times(Duration.ZERO, fromTicks(60), fromTicks(20))));
}

@EventHandler(priority = EventPriority.MONITOR)
public void onBlitzPlayerEliminated(final BlitzPlayerEliminatedEvent event) {
this.eliminatedPlayers.add(event.getPlayer().getId());
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/tc/oc/pgm/blitz/LifeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@ public int addLives(UUID player, int dlives) {

return lives;
}

public void setLives(UUID player, int lives) {
assertNotNull(player, "player id");

this.livesLeft.put(player, Math.max(0, lives));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.util.xml.XMLUtils;
import tc.oc.pgm.variables.VariableDefinition;
import tc.oc.pgm.variables.VariableType;
import tc.oc.pgm.variables.VariablesModule;

public class FeatureFilterParser extends FilterParser {
Expand Down Expand Up @@ -99,6 +100,9 @@ public Filter parseNot(Element el) throws InvalidXMLException {
if (varMatch.matches()) {
VariableDefinition<?> variable =
features.resolve(node, varMatch.group(1), VariableDefinition.class);
if (!variable.getVariableType().equals(VariableType.DUMMY)) {
throw new InvalidXMLException("Variable filters only support dummy variables!", node);
}
Range<Double> range = XMLUtils.parseNumericRange(node, varMatch.group(2), Double.class);
return new VariableFilter(variable, range);
}
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/tc/oc/pgm/filters/parse/FilterParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.util.xml.XMLUtils;
import tc.oc.pgm.variables.VariableDefinition;
import tc.oc.pgm.variables.VariableType;

public abstract class FilterParser implements XMLParser<Filter, FilterDefinition> {

Expand Down Expand Up @@ -661,6 +662,9 @@ public PlayerCountFilter parsePlayerCountFilter(Element el) throws InvalidXMLExc
public Filter parseVariableFilter(Element el) throws InvalidXMLException {
VariableDefinition<?> varDef =
features.resolve(Node.fromRequiredAttr(el, "var"), VariableDefinition.class);
if (!varDef.getVariableType().equals(VariableType.DUMMY)) {
throw new InvalidXMLException("Variable filters only support dummy variables!", el);
}
Range<Double> range = XMLUtils.parseNumericRange(new Node(el), Double.class);

if (varDef.getScope() == Party.class)
Expand Down
33 changes: 33 additions & 0 deletions core/src/main/java/tc/oc/pgm/variables/BlitzVariable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package tc.oc.pgm.variables;

import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.blitz.BlitzMatchModule;
import tc.oc.pgm.filters.Filterable;

public class BlitzVariable implements Variable<MatchPlayer> {

private final VariableDefinition<MatchPlayer> definition;

public BlitzVariable(VariableDefinition<? extends Filterable<?>> definition) {
this.definition = (VariableDefinition<MatchPlayer>) definition;
}

@Override
public VariableDefinition<MatchPlayer> getDefinition() {
return definition;
}

@Override
public double getValue(Filterable<?> context) {
MatchPlayer matchPlayer = context.getFilterableAncestor(MatchPlayer.class);
BlitzMatchModule blitzMatchModule = matchPlayer.moduleRequire(BlitzMatchModule.class);
return blitzMatchModule.getNumOfLives(matchPlayer.getId());
}

@Override
public void setValue(Filterable<?> context, double value) {
MatchPlayer matchPlayer = context.getFilterableAncestor(MatchPlayer.class);
BlitzMatchModule blitzMatchModule = matchPlayer.moduleRequire(BlitzMatchModule.class);
blitzMatchModule.setLives(matchPlayer, Math.max((int) value, 0));
}
}
48 changes: 48 additions & 0 deletions core/src/main/java/tc/oc/pgm/variables/DummyVariable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tc.oc.pgm.variables;

import java.util.HashMap;
import java.util.Map;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.Filterable;

public class DummyVariable<T extends Filterable<?>> implements Variable<T> {

private final VariableDefinition<T> definition;
private final Map<T, Double> values;

public DummyVariable(VariableDefinition<T> definition) {
this.definition = definition;
this.values = new HashMap<>();
}

@Override
public VariableDefinition<T> getDefinition() {
return definition;
}

@Override
public double getValue(Filterable<?> context) {
return values.computeIfAbsent(getAncestor(context), k -> definition.getDefault());
}

@Override
public void setValue(Filterable<?> context, double value) {
T ctx = getAncestor(context);
values.put(ctx, value);
// For performance reasons, let's avoid launching an event for every variable change
context.getMatch().needModule(FilterMatchModule.class).invalidate(ctx);
}

private T getAncestor(Filterable<?> context) {
T filterable = context.getFilterableAncestor(definition.getScope());
if (filterable != null) return filterable;

throw new IllegalStateException(
"Wrong variable scope for '"
+ getId()
+ "', expected "
+ definition.getScope().getSimpleName()
+ " which cannot be found in "
+ context.getClass().getSimpleName());
}
}
46 changes: 5 additions & 41 deletions core/src/main/java/tc/oc/pgm/variables/Variable.java
Original file line number Diff line number Diff line change
@@ -1,52 +1,16 @@
package tc.oc.pgm.variables;

import java.util.HashMap;
import java.util.Map;
import tc.oc.pgm.api.feature.Feature;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.Filterable;

public class Variable<T extends Filterable<?>> implements Feature<VariableDefinition<T>> {

private final VariableDefinition<T> definition;
private final Map<T, Double> values;

public Variable(VariableDefinition<T> definition) {
this.definition = definition;
this.values = new HashMap<>();
}
public interface Variable<T extends Filterable<?>> extends Feature<VariableDefinition<T>> {

@Override
public String getId() {
return definition.getId();
default String getId() {
return getDefinition().getId();
}

@Override
public VariableDefinition<T> getDefinition() {
return definition;
}
double getValue(Filterable<?> context);

public double getValue(Filterable<?> context) {
return values.computeIfAbsent(getAncestor(context), k -> definition.getDefault());
}

public void setValue(Filterable<?> context, double value) {
T ctx = getAncestor(context);
values.put(ctx, value);
// For performance reasons, let's avoid launching an event for every variable change
context.getMatch().needModule(FilterMatchModule.class).invalidate(ctx);
}

private T getAncestor(Filterable<?> context) {
T filterable = context.getFilterableAncestor(definition.getScope());
if (filterable != null) return filterable;

throw new IllegalStateException(
"Wrong variable scope for '"
+ getId()
+ "', expected "
+ definition.getScope().getSimpleName()
+ " which cannot be found in "
+ context.getClass().getSimpleName());
}
void setValue(Filterable<?> context, double value);
}
12 changes: 11 additions & 1 deletion core/src/main/java/tc/oc/pgm/variables/VariableDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ public class VariableDefinition<T extends Filterable<?>> extends SelfIdentifying

private final Class<T> scope;
private final double def;
private final VariableType variableType;

public VariableDefinition(String id, Class<T> scope, double def) {
public VariableDefinition(String id, Class<T> scope, double def, VariableType variableType) {
super(id);
this.scope = scope;
this.def = def;
this.variableType = variableType;
}

public Class<T> getScope() {
Expand All @@ -23,6 +25,14 @@ public double getDefault() {
return def;
}

public Variable<?> buildInstance() {
return getVariableType().buildInstance(this);
}

public VariableType getVariableType() {
return variableType;
}

@SuppressWarnings("unchecked")
public Variable<T> getVariable(Match match) {
return (Variable<T>) match.getFeatureContext().get(this.getId());
Expand Down
33 changes: 33 additions & 0 deletions core/src/main/java/tc/oc/pgm/variables/VariableType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package tc.oc.pgm.variables;

import java.util.function.Function;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.filters.Filterable;

public enum VariableType {
DUMMY(DummyVariable::new, Filterable.class),
LIVES(BlitzVariable::new, MatchPlayer.class);

private final Function<VariableDefinition<?>, Variable<?>> supplierFunction;
private final Class<?>[] supportedScopes;

VariableType(
Function<VariableDefinition<? extends Filterable>, Variable<?>> supplierFunction,
Class<?>... supportedScopes) {
this.supplierFunction = supplierFunction;
this.supportedScopes = supportedScopes;
}

public boolean supports(Class<?> cls) {
for (Class<?> supportedScope : supportedScopes) {
if (supportedScope.isAssignableFrom(cls)) {
return true;
}
}
return false;
}

public Variable<?> buildInstance(VariableDefinition<?> definition) {
return supplierFunction.apply(definition);
}
}
13 changes: 11 additions & 2 deletions core/src/main/java/tc/oc/pgm/variables/VariablesModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static <T extends Filterable<?>> VariableCache<T> of(
@Override
public VariablesMatchModule createMatchModule(Match match) throws ModuleLoadException {
for (VariableDefinition<?> varDef : this.variables) {
match.getFeatureContext().add(new Variable<>(varDef));
match.getFeatureContext().add(varDef.buildInstance());
}

return new VariablesMatchModule();
Expand Down Expand Up @@ -102,8 +102,17 @@ public VariablesModule parse(MapFactory factory, Logger logger, Document doc)
Class<? extends Filterable<?>> scope =
Filterables.parse(Node.fromRequiredAttr(variable, "scope"));
double def = XMLUtils.parseNumber(Node.fromAttr(variable, "default"), Double.class, 0d);
Node variableTypeNode = Node.fromAttr(variable, "type");
VariableType variableType =
XMLUtils.parseEnum(
variableTypeNode, VariableType.class, "variable type", VariableType.DUMMY);
if (!variableType.supports(scope)) {
throw new InvalidXMLException(
"VariableType: " + variableType + " Does not support scope: " + scope,
variableTypeNode);
}

VariableDefinition<?> varDef = new VariableDefinition<>(id, scope, def);
VariableDefinition<?> varDef = new VariableDefinition<>(id, scope, def, variableType);
factory.getFeatures().addFeature(variable, varDef);
variables.add(varDef);
}
Expand Down

0 comments on commit 87278fe

Please sign in to comment.