Skip to content

Fix super entity changer with location #7394

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

Open
wants to merge 5 commits into
base: dev/feature
Choose a base branch
from
Open
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
76 changes: 67 additions & 9 deletions src/main/java/ch/njol/skript/classes/Changer.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package ch.njol.skript.classes;

import java.util.Arrays;

import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import ch.njol.skript.classes.data.DefaultChangers;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.registrations.Classes;
import ch.njol.util.coll.CollectionUtils;

/**
* An interface to declare changeable values. All Expressions implement something similar like this by default, but refuse any change if {@link Expression#acceptChange(ChangeMode)}
Expand All @@ -17,9 +21,11 @@
* @see Expression
*/
public interface Changer<T> {

enum ChangeMode {
ADD, SET, REMOVE, REMOVE_ALL, DELETE, RESET;
ADD, SET, REMOVE, REMOVE_ALL, DELETE, RESET,
/** Used for internal setting after a value has been modified, like within a change method */
INTERNAL;

public boolean supportsKeyedChange() {
return this == SET;
Expand All @@ -39,7 +45,7 @@ public boolean supportsKeyedChange() {
* mark them as supported.
*/
Class<?> @Nullable [] acceptChange(ChangeMode mode);

/**
* @param what The objects to change
* @param delta An array with one or more instances of one or more of the the classes returned by {@link #acceptChange(ChangeMode)} for the given change mode (null for
Expand All @@ -48,14 +54,50 @@ public boolean supportsKeyedChange() {
* @throws UnsupportedOperationException (optional) if this method was called on an unsupported ChangeMode.
*/
void change(T[] what, Object @Nullable [] delta, ChangeMode mode);

abstract class ChangerUtils {

public static <T> void change(@NotNull Changer<T> changer, Object[] what, Object @Nullable [] delta, ChangeMode mode) {
//noinspection unchecked
changer.change((T[]) what, delta, mode);
/**
* Changes the given objects using the given changer and delta. The first mode that is accepted by the changer is used.
*
* @param changer The changer to use
* @param what The objects to change
* @param delta The delta to apply
* @param modes The modes to test
* @param <T> The type of the objects
* @return Whether the changer accepted any of the given modes
* @throws UnsupportedOperationException If the changer does not accept any of the given modes
*/
public static <T> boolean change(@NotNull Changer<T> changer, Object[] what, Object @Nullable [] delta, ChangeMode... modes) {
for (ChangeMode mode : modes) {
// Asserts that the what array is of the correct type or inherits from it.
// what can't be T[] because of type erasure with expressions.
if (changer.acceptChange(mode) != null) {
//noinspection unchecked
changer.change((T[]) what, delta, mode);
return true;
}
}
return false;
}


/**
* Changes the given expression using the given delta. The first mode that is accepted by the expression is used.
*
* @param expression The expression to change
* @param event The event
* @param delta The delta to apply
* @param modes The modes to test
* @param <T> The type of the expression
* @return Whether the expression accepted any of the given modes
*/
public static boolean change(Expression<?> expression, Event event, Object @Nullable [] delta, ChangeMode... modes) {
Changer<?> changer = Classes.getSuperClassInfo(expression.getReturnType()).getChanger();
if (changer == null)
return false;
return change(changer, expression.getArray(event), delta, modes);
}

/**
* Tests whether an expression accepts changes of a certain type. If multiple types are given it test for whether any of the types is accepted.
*
Expand Down Expand Up @@ -94,6 +136,22 @@ public static boolean acceptsChangeTypes(Class<?>[] validTypes, Class<?> @NotNul
return false;
}

/**
* Tests whether an expression accepts changes of a certain type. If multiple types are given it test for whether any of the types is accepted.
*
* @param expression The expression to test
* @param modes The ChangeModes to use in the test
* @param types The types to test for
* @return Whether <tt>expression.{@link Expression#change(Event, Object[], ChangeMode) change}(event, type[], mode)</tt> can be used or not.
*/
public static boolean acceptsChange(Expression<?> expression, ChangeMode[] modes, Class<?>... types) {
for (ChangeMode mode : modes) {
if (acceptsChange(expression, mode, types))
return true;
}
return false;
}

}

}
73 changes: 37 additions & 36 deletions src/main/java/ch/njol/skript/classes/data/DefaultChangers.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.njol.skript.classes.data;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
Expand All @@ -22,17 +23,14 @@
import ch.njol.skript.util.Experience;
import ch.njol.util.coll.CollectionUtils;

/**
* @author Peter Güttinger
*/
public class DefaultChangers {

public DefaultChangers() {}

public final static Changer<Entity> entityChanger = new Changer<Entity>() {

@Override
@Nullable
public Class<? extends Object>[] acceptChange(final ChangeMode mode) {
public Class<? extends Object> @Nullable [] acceptChange(ChangeMode mode) {
switch (mode) {
case ADD:
return CollectionUtils.array(ItemType[].class, Inventory.class, Experience[].class);
Expand All @@ -45,59 +43,62 @@ public Class<? extends Object>[] acceptChange(final ChangeMode mode) {
case SET:
case RESET: // REMIND reset entity? (unshear, remove held item, reset weapon/armour, ...)
return null;
case INTERNAL:
return CollectionUtils.array(Location.class);
default:
return null;
}
assert false;
return null;
}

@Override
public void change(final Entity[] entities, final @Nullable Object[] delta, final ChangeMode mode) {
public void change(Entity[] entities, Object @Nullable [] delta, ChangeMode mode) {
if (delta == null) {
for (final Entity e : entities) {
if (!(e instanceof Player))
e.remove();
for (Entity entity : entities) {
if (!(entity instanceof Player))
entity.remove();
}
return;
}
boolean hasItem = false;
for (final Entity e : entities) {
for (final Object d : delta) {
if (d instanceof PotionEffectType) {
for (Entity entity : entities) {
for (Object object : delta) {
if (object instanceof Location location) {
assert mode == ChangeMode.INTERNAL;
entity.teleport(location);
} else if (object instanceof PotionEffectType) {
assert mode == ChangeMode.REMOVE || mode == ChangeMode.REMOVE_ALL;
if (!(e instanceof LivingEntity))
continue;
((LivingEntity) e).removePotionEffect((PotionEffectType) d);
if (entity instanceof LivingEntity livingEntity)
livingEntity.removePotionEffect((PotionEffectType) object);
} else {
if (e instanceof Player) {
final Player p = (Player) e;
if (d instanceof Experience) {
p.giveExp(((Experience) d).getXP());
} else if (d instanceof Inventory) {
PlayerInventory inventory = p.getInventory();
for (ItemStack itemStack : (Inventory) d) {
if (entity instanceof Player player) {
if (object instanceof Experience experience) {
player.giveExp(experience.getXP());
} else if (object instanceof Inventory inventory) {
PlayerInventory playerInventory = player.getInventory();
for (ItemStack itemStack : inventory) {
if (itemStack == null)
continue;
if (mode == ChangeMode.ADD) {
inventory.addItem(itemStack);
playerInventory.addItem(itemStack);
} else {
inventory.remove(itemStack);
playerInventory.remove(itemStack);
}
}
} else if (d instanceof ItemType) {
} else if (object instanceof ItemType itemType) {
hasItem = true;
final PlayerInventory invi = p.getInventory();
final PlayerInventory invi = player.getInventory();
if (mode == ChangeMode.ADD)
((ItemType) d).addTo(invi);
itemType.addTo(invi);
else if (mode == ChangeMode.REMOVE)
((ItemType) d).removeFrom(invi);
itemType.removeFrom(invi);
else
((ItemType) d).removeAll(invi);
itemType.removeAll(invi);
}
}
}
}
if (e instanceof Player && hasItem)
PlayerUtils.updateInventory((Player) e);
if (entity instanceof Player player && hasItem)
PlayerUtils.updateInventory(player);
}
}
};
Expand Down
109 changes: 50 additions & 59 deletions src/main/java/ch/njol/skript/expressions/ExprCoordinate.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.njol.skript.expressions;

import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

Expand All @@ -14,91 +15,81 @@
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;

/**
* @author Peter Güttinger
*/
@Name("Coordinate")
@Description("Represents a given coordinate of a location. ")
@Examples({"player's y-coordinate is smaller than 40:",
" message \"Watch out for lava!\""})
@Description("Represents a given coordinate of a location or entity.")
@Examples({
"player's y-coordinate is smaller than 40:",
" message \"Watch out for lava!\""
})
@Since("1.4.3")
public class ExprCoordinate extends SimplePropertyExpression<Location, Number> {
public class ExprCoordinate extends SimplePropertyExpression<Location, Double> {

static {
register(ExprCoordinate.class, Number.class, "(0¦x|1¦y|2¦z)(-| )(coord[inate]|pos[ition]|loc[ation])[s]", "locations");
registerDefault(ExprCoordinate.class, Double.class, "(0¦x|1¦y|2¦z)(-| )(coord[inate]|pos[ition]|loc[ation])[s]", "locations");
}

private final static char[] axes = {'x', 'y', 'z'};

private int axis;

@Override
public boolean init(final Expression<?>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) {
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
super.init(exprs, matchedPattern, isDelayed, parseResult);
axis = parseResult.mark;
return true;
}

@Override
public Number convert(final Location l) {
return axis == 0 ? l.getX() : axis == 1 ? l.getY() : l.getZ();
public Double convert(Location location) {
return axis == 0 ? location.getX() : axis == 1 ? location.getY() : location.getZ();
}

@Override
protected String getPropertyName() {
return "the " + axes[axis] + "-coordinate";
return axes[axis] + "-coordinate";
}

@Override
public Class<? extends Number> getReturnType() {
return Number.class;
public Class<? extends Double> getReturnType() {
return Double.class;
}

@Override
@Nullable
public Class<?>[] acceptChange(final ChangeMode mode) {
if ((mode == ChangeMode.SET || mode == ChangeMode.ADD || mode == ChangeMode.REMOVE) && getExpr().isSingle() && ChangerUtils.acceptsChange(getExpr(), ChangeMode.SET, Location.class))
return new Class[] {Number.class};
return null;
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
return switch (mode) {
case SET, ADD, REMOVE -> {
if (getExpr().isSingle() && ChangerUtils.acceptsChange(getExpr(), CollectionUtils.array(ChangeMode.INTERNAL, ChangeMode.SET), Location.class)) {
yield new Class[] {Number.class};
}
yield null;
}
default -> null;
};
}

@Override
public void change(final Event e, final @Nullable Object[] delta, final ChangeMode mode) throws UnsupportedOperationException {
public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
assert delta != null;
final Location l = getExpr().getSingle(e);
if (l == null)
Object object = getExpr().getSingle(event);
Location location = object instanceof Entity entity ? entity.getLocation() : (Location) object;
if (location == null)
return;
double n = ((Number) delta[0]).doubleValue();
switch (mode) {
case REMOVE:
n = -n;
//$FALL-THROUGH$
case ADD:
if (axis == 0) {
l.setX(l.getX() + n);
} else if (axis == 1) {
l.setY(l.getY() + n);
} else {
l.setZ(l.getZ() + n);
}
getExpr().change(e, new Location[] {l}, ChangeMode.SET);
break;
case SET:
if (axis == 0) {
l.setX(n);
} else if (axis == 1) {
l.setY(n);
} else {
l.setZ(n);
}
getExpr().change(e, new Location[] {l}, ChangeMode.SET);
break;
case DELETE:
case REMOVE_ALL:
case RESET:
assert false;
if (mode == ChangeMode.REMOVE) {
n = -n;
mode = ChangeMode.ADD;
}
if (mode == ChangeMode.ADD) {
if (axis == 0) location.setX(location.getX() + n);
else if (axis == 1) location.setY(location.getY() + n);
else location.setZ(location.getZ() + n);
} else if (mode == ChangeMode.SET) {
if (axis == 0) location.setX(n);
else if (axis == 1) location.setY(n);
else location.setZ(n);
}
ChangerUtils.change(getExpr(), event, new Location[] {location}, ChangeMode.INTERNAL, ChangeMode.SET);
}

}