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 new player variable components #1483

Merged
merged 2 commits into from
Jan 20, 2025
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
6 changes: 3 additions & 3 deletions core/src/main/java/tc/oc/pgm/variables/VariableParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -117,8 +117,8 @@ public Variable<Match> parseMaxBuild(Element el) {
@MethodParser("player-location")
public Variable<MatchPlayer> 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")
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/java/tc/oc/pgm/variables/VariablesModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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));
}
}

Expand Down

This file was deleted.

119 changes: 119 additions & 0 deletions core/src/main/java/tc/oc/pgm/variables/types/PlayerVariable.java
Original file line number Diff line number Diff line change
@@ -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<MatchPlayer> {

private static final Map<Component, PlayerVariable> INSTANCES;

static {
var values = new EnumMap<Component, PlayerVariable>(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<Player> getter;
private final ObjDoubleConsumer<Player> setter;

private PlayerVariable(ToDoubleFunction<Player> getter, ObjDoubleConsumer<Player> 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<Player> getter;
private final ObjDoubleConsumer<Player> setter;

Component(ToDoubleFunction<Player> getter, ObjDoubleConsumer<Player> setter) {
this.getter = getter;
this.setter = setter;
}

Component(ToDoubleFunction<Player> 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<RayBlockIntersection> toDouble) {
var intersection = intersection(player);
return intersection == null ? NULL_VALUE : toDouble.applyAsDouble(intersection);
}
}
Loading