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

Add support for variables acting on Blitz Lives #1214

Merged
merged 1 commit into from
Aug 23, 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
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
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