From 1be014565b3d57d48e9ad57939ad98ccbd722a5e Mon Sep 17 00:00:00 2001 From: Pablo Herrera Date: Sun, 19 Jan 2025 23:59:03 +0100 Subject: [PATCH] Add new player variable components Signed-off-by: Pablo Herrera --- .../tc/oc/pgm/variables/VariableParser.java | 6 +- .../tc/oc/pgm/variables/VariablesModule.java | 8 +- .../types/PlayerLocationVariable.java | 97 -------------- .../pgm/variables/types/PlayerVariable.java | 119 ++++++++++++++++++ 4 files changed, 126 insertions(+), 104 deletions(-) delete mode 100644 core/src/main/java/tc/oc/pgm/variables/types/PlayerLocationVariable.java create mode 100644 core/src/main/java/tc/oc/pgm/variables/types/PlayerVariable.java diff --git a/core/src/main/java/tc/oc/pgm/variables/VariableParser.java b/core/src/main/java/tc/oc/pgm/variables/VariableParser.java index 985ec26c08..87c9b8c84f 100644 --- a/core/src/main/java/tc/oc/pgm/variables/VariableParser.java +++ b/core/src/main/java/tc/oc/pgm/variables/VariableParser.java @@ -24,7 +24,7 @@ import tc.oc.pgm.variables.types.DummyVariable; import tc.oc.pgm.variables.types.LivesVariable; import tc.oc.pgm.variables.types.MaxBuildVariable; -import tc.oc.pgm.variables.types.PlayerLocationVariable; +import tc.oc.pgm.variables.types.PlayerVariable; import tc.oc.pgm.variables.types.ScoreVariable; import tc.oc.pgm.variables.types.TeamVariableAdapter; import tc.oc.pgm.variables.types.TimeLimitVariable; @@ -117,8 +117,8 @@ public Variable parseMaxBuild(Element el) { @MethodParser("player-location") public Variable parsePlayerLocation(Element el) throws InvalidXMLException { var component = - XMLUtils.parseEnum(Node.fromAttr(el, "component"), PlayerLocationVariable.Component.class); - return PlayerLocationVariable.INSTANCES.get(component); + XMLUtils.parseEnum(Node.fromAttr(el, "component"), PlayerVariable.Component.class); + return PlayerVariable.of(component); } @MethodParser("cuboid") diff --git a/core/src/main/java/tc/oc/pgm/variables/VariablesModule.java b/core/src/main/java/tc/oc/pgm/variables/VariablesModule.java index 6764f4e6bb..fc548a9be4 100644 --- a/core/src/main/java/tc/oc/pgm/variables/VariablesModule.java +++ b/core/src/main/java/tc/oc/pgm/variables/VariablesModule.java @@ -26,7 +26,7 @@ import tc.oc.pgm.util.xml.XMLUtils; import tc.oc.pgm.variables.types.LivesVariable; import tc.oc.pgm.variables.types.MaxBuildVariable; -import tc.oc.pgm.variables.types.PlayerLocationVariable; +import tc.oc.pgm.variables.types.PlayerVariable; import tc.oc.pgm.variables.types.ScoreVariable; import tc.oc.pgm.variables.types.TimeLimitVariable; @@ -142,9 +142,9 @@ public VariablesModule parse(MapFactory factory, Logger logger, Document doc) features.addFeature(null, "score", ScoreVariable.INSTANCE); features.addFeature(null, "timelimit", TimeLimitVariable.INSTANCE); features.addFeature(null, "maxbuildheight", MaxBuildVariable.INSTANCE); - for (var entry : PlayerLocationVariable.INSTANCES.entrySet()) { - String key = "player." + entry.getKey().name().toLowerCase(Locale.ROOT); - features.addFeature(null, key, entry.getValue()); + for (var component : PlayerVariable.Component.values()) { + String key = "player." + component.name().toLowerCase(Locale.ROOT); + features.addFeature(null, key, PlayerVariable.of(component)); } } diff --git a/core/src/main/java/tc/oc/pgm/variables/types/PlayerLocationVariable.java b/core/src/main/java/tc/oc/pgm/variables/types/PlayerLocationVariable.java deleted file mode 100644 index 565e46577b..0000000000 --- a/core/src/main/java/tc/oc/pgm/variables/types/PlayerLocationVariable.java +++ /dev/null @@ -1,97 +0,0 @@ -package tc.oc.pgm.variables.types; - -import static java.lang.Math.toRadians; -import static tc.oc.pgm.util.nms.PlayerUtils.PLAYER_UTILS; - -import java.util.Collections; -import java.util.EnumMap; -import java.util.Map; -import java.util.function.ToDoubleFunction; -import org.bukkit.Location; -import tc.oc.pgm.api.player.MatchPlayer; -import tc.oc.pgm.util.block.RayBlockIntersection; - -public class PlayerLocationVariable extends AbstractVariable { - - public static final Map INSTANCES; - - static { - var values = new EnumMap(Component.class); - for (Component component : Component.values()) { - values.put(component, new PlayerLocationVariable(component)); - } - INSTANCES = Collections.unmodifiableMap(values); - } - - private static final double NULL_VALUE = -1; - private static RayCastCache lastRaytrace; - - record RayCastCache(Location location, RayBlockIntersection rayCast) {} - - private final Component component; - - public PlayerLocationVariable(Component component) { - super(MatchPlayer.class); - this.component = component; - } - - @Override - public boolean isReadonly() { - return true; - } - - @Override - protected double getValueImpl(MatchPlayer player) { - return component.getter.applyAsDouble(player); - } - - @Override - protected void setValueImpl(MatchPlayer obj, double value) { - throw new UnsupportedOperationException(); - } - - public enum Component { - X(p -> p.getLocation().getX()), - Y(p -> p.getLocation().getY()), - Z(p -> p.getLocation().getZ()), - PITCH(p -> p.getLocation().getPitch()), - YAW(p -> p.getLocation().getYaw()), - DIR_X(p -> -Math.cos(toRadians(p.getLocation().getPitch())) - * Math.sin(toRadians(p.getLocation().getYaw()))), - DIR_Y(p -> -Math.sin(toRadians(p.getLocation().getPitch()))), - DIR_Z(p -> Math.cos(toRadians(p.getLocation().getPitch())) - * Math.cos(toRadians(p.getLocation().getYaw()))), - VEL_X(p -> p.getBukkit().getVelocity().getX()), - VEL_Y(p -> p.getBukkit().getVelocity().getY()), - VEL_Z(p -> p.getBukkit().getVelocity().getZ()), - TARGET_X(p -> intersection(p, i -> i.getBlock().getX())), - TARGET_Y(p -> intersection(p, i -> i.getBlock().getY())), - TARGET_Z(p -> intersection(p, i -> i.getBlock().getZ())), - PLACE_X(p -> intersection(p, i -> i.getPlaceAt().getX())), - PLACE_Y(p -> intersection(p, i -> i.getPlaceAt().getY())), - PLACE_Z(p -> intersection(p, i -> i.getPlaceAt().getZ())), - HAS_TARGET(p -> intersection(p) == null ? 0 : 1); - - private final ToDoubleFunction getter; - - Component(ToDoubleFunction getter) { - this.getter = getter; - } - } - - private static RayBlockIntersection intersection(MatchPlayer player) { - RayCastCache cache = lastRaytrace; - if (cache != null && player.getLocation().equals(cache.location)) { - return cache.rayCast; - } - lastRaytrace = cache = new RayCastCache( - player.getLocation().clone(), PLAYER_UTILS.getTargetedBlock(player.getBukkit())); - return cache.rayCast; - } - - private static double intersection( - MatchPlayer player, ToDoubleFunction toDouble) { - var intersection = intersection(player); - return intersection == null ? NULL_VALUE : toDouble.applyAsDouble(intersection); - } -} diff --git a/core/src/main/java/tc/oc/pgm/variables/types/PlayerVariable.java b/core/src/main/java/tc/oc/pgm/variables/types/PlayerVariable.java new file mode 100644 index 0000000000..25e4cb149b --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/variables/types/PlayerVariable.java @@ -0,0 +1,119 @@ +package tc.oc.pgm.variables.types; + +import static java.lang.Math.toRadians; +import static tc.oc.pgm.util.nms.PlayerUtils.PLAYER_UTILS; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.ObjDoubleConsumer; +import java.util.function.ToDoubleFunction; +import org.bukkit.Location; +import org.bukkit.entity.Damageable; +import org.bukkit.entity.Player; +import tc.oc.pgm.api.player.MatchPlayer; +import tc.oc.pgm.util.block.RayBlockIntersection; + +public class PlayerVariable extends AbstractVariable { + + private static final Map INSTANCES; + + static { + var values = new EnumMap(Component.class); + for (Component component : Component.values()) { + values.put(component, new PlayerVariable(component.getter, component.setter)); + } + INSTANCES = Collections.unmodifiableMap(values); + } + + private static final double NULL_VALUE = -1; + private static RayCastCache lastRaytrace; + + record RayCastCache(Location location, RayBlockIntersection rayCast) {} + + private final ToDoubleFunction getter; + private final ObjDoubleConsumer setter; + + private PlayerVariable(ToDoubleFunction getter, ObjDoubleConsumer setter) { + super(MatchPlayer.class); + this.getter = getter; + this.setter = setter; + } + + public static PlayerVariable of(Component component) { + return INSTANCES.get(component); + } + + @Override + public boolean isReadonly() { + return setter == null; + } + + @Override + protected double getValueImpl(MatchPlayer player) { + return getter.applyAsDouble(player.getBukkit()); + } + + @Override + protected void setValueImpl(MatchPlayer obj, double value) { + if (setter == null) throw new UnsupportedOperationException(); + setter.accept(obj.getBukkit(), value); + } + + public enum Component { + X(p -> p.getLocation().getX()), + Y(p -> p.getLocation().getY()), + Z(p -> p.getLocation().getZ()), + PITCH(p -> p.getLocation().getPitch()), + YAW(p -> p.getLocation().getYaw()), + DIR_X(p -> -Math.cos(toRadians(p.getLocation().getPitch())) + * Math.sin(toRadians(p.getLocation().getYaw()))), + DIR_Y(p -> -Math.sin(toRadians(p.getLocation().getPitch()))), + DIR_Z(p -> Math.cos(toRadians(p.getLocation().getPitch())) + * Math.cos(toRadians(p.getLocation().getYaw()))), + VEL_X(p -> p.getVelocity().getX()), + VEL_Y(p -> p.getVelocity().getY()), + VEL_Z(p -> p.getVelocity().getZ()), + TARGET_X(p -> intersection(p, i -> i.getBlock().getX())), + TARGET_Y(p -> intersection(p, i -> i.getBlock().getY())), + TARGET_Z(p -> intersection(p, i -> i.getBlock().getZ())), + PLACE_X(p -> intersection(p, i -> i.getPlaceAt().getX())), + PLACE_Y(p -> intersection(p, i -> i.getPlaceAt().getY())), + PLACE_Z(p -> intersection(p, i -> i.getPlaceAt().getZ())), + HAS_TARGET(p -> intersection(p) == null ? 0 : 1), + HEALTH( + Damageable::getHealth, (p, h) -> p.setHealth(Math.max(0, Math.min(p.getMaxHealth(), h)))), + MAX_HEALTH(Damageable::getMaxHealth, (p, h) -> p.setMaxHealth(Math.max(0.1f, h))), + FOOD(Player::getFoodLevel, (p, f) -> p.setFoodLevel((int) f)), + SATURATION(Player::getSaturation, (p, s) -> p.setSaturation((float) s)), + EXPERIENCE(Player::getTotalExperience, (p, ex) -> p.setTotalExperience((int) ex)), + EXP_PROGRESS(Player::getExp, (p, ex) -> p.setExp((float) ex)), + LEVEL(Player::getLevel, (p, l) -> p.setLevel((int) l)); + + private final ToDoubleFunction getter; + private final ObjDoubleConsumer setter; + + Component(ToDoubleFunction getter, ObjDoubleConsumer setter) { + this.getter = getter; + this.setter = setter; + } + + Component(ToDoubleFunction getter) { + this(getter, null); + } + } + + private static RayBlockIntersection intersection(Player player) { + RayCastCache cache = lastRaytrace; + var loc = player.getLocation(); + if (cache != null && loc.equals(cache.location)) return cache.rayCast; + lastRaytrace = cache = new RayCastCache(loc, PLAYER_UTILS.getTargetedBlock(player)); + return cache.rayCast; + } + + private static double intersection( + Player player, ToDoubleFunction toDouble) { + var intersection = intersection(player); + return intersection == null ? NULL_VALUE : toDouble.applyAsDouble(intersection); + } +}