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

Fix entity damage event 1.20.4 constructor changes #6433

Closed
wants to merge 13 commits into from
Closed
66 changes: 55 additions & 11 deletions src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,21 @@
*/
package ch.njol.skript.bukkitutil;

import ch.njol.skript.Skript;
import ch.njol.util.Math2;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.bukkit.attribute.Attributable;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.Damageable;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval;
import org.jetbrains.annotations.Nullable;

public class HealthUtils {

Expand All @@ -38,7 +46,7 @@ public static double getHealth(Damageable e) {
return 0;
return e.getHealth() / 2;
}

/**
* Set the health of an entity
* @param e Entity to set health for
Expand All @@ -47,7 +55,7 @@ public static double getHealth(Damageable e) {
public static void setHealth(Damageable e, double health) {
e.setHealth(Math2.fit(0, health, getMaxHealth(e)) * 2);
}

/**
* Get the max health an entity has
* @param e Entity to get max health from
Expand All @@ -58,7 +66,7 @@ public static double getMaxHealth(Damageable e) {
assert attributeInstance != null;
return attributeInstance.getValue() / 2;
}

/**
* Set the max health an entity can have
* @param e Entity to set max health for
Expand All @@ -69,7 +77,7 @@ public static void setMaxHealth(Damageable e, double health) {
assert attributeInstance != null;
attributeInstance.setBaseValue(health * 2);
}

/**
* Apply damage to an entity
* @param e Entity to apply damage to
Expand All @@ -95,21 +103,57 @@ public static void heal(Damageable e, double h) {
}
setHealth(e, getHealth(e) + h);
}

public static double getDamage(EntityDamageEvent e) {
return e.getDamage() / 2;
}

public static double getFinalDamage(EntityDamageEvent e) {
return e.getFinalDamage() / 2;
}

public static void setDamage(EntityDamageEvent e, double damage) {
e.setDamage(damage * 2);
}

public static void setDamageCause(Damageable e, DamageCause cause) {
e.setLastDamageCause(new EntityDamageEvent(e, cause, 0));

/**
* In a late 1.20.4 version. Spigot added a non null DamageSource parameter in all EntityDamageEvent constructors,
* and removed existing constructors that did not contain a DamageSource parameter.
* @ScheduledForRemoval Existing until proper support is added to ExprLastDamageCause for DamageSource
*/
@Deprecated
@ScheduledForRemoval
public static boolean DAMAGE_SOURCE;
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved

@Nullable
private static Constructor<EntityDamageEvent> DAMAGE_EVENT_CONSTRUCTOR;

static {
if (!DAMAGE_SOURCE) {
try {
DAMAGE_EVENT_CONSTRUCTOR = EntityDamageEvent.class.getConstructor(Damageable.class, DamageCause.class, double.class);
// Throws here. DAMAGE_SOURCE should only be set if DAMAGE_EVENT_CONSTRUCTOR doesn't exist.
DAMAGE_SOURCE = Skript.classExists("org.bukkit.damage.DamageSource");
} catch (NoSuchMethodException | SecurityException e) {}
}
}

/**
* Used to set the damage cause of a damageable entity in an entity damage event.
* Can only be used in versions below 1.20.4.
*
* @param entity The damaged entity.
* @param cause The damage cause in the damage event.
* @deprecated Only used in versions below 1.20.4. See {@link org.bukkit.damage.DamageSource}
*/
@Deprecated
@ScheduledForRemoval
public static void setDamageCause(Damageable entity, DamageCause cause) {
if (DAMAGE_SOURCE)
return;
try {
entity.setLastDamageCause(DAMAGE_EVENT_CONSTRUCTOR.newInstance(entity, cause, 0));
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {}
}

}
47 changes: 47 additions & 0 deletions src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.regex.Matcher;
Expand All @@ -37,7 +38,9 @@
import org.bukkit.GameRule;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.OfflinePlayer;
import org.bukkit.Registry;
import org.bukkit.SoundCategory;
import org.bukkit.World;
import org.bukkit.World.Environment;
Expand All @@ -48,6 +51,8 @@
import org.bukkit.block.DoubleChest;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentOffer;
import org.bukkit.entity.Cat;
Expand Down Expand Up @@ -1548,6 +1553,48 @@ public String toVariableNameString(EnchantmentOffer eo) {
.name("Transform Reason")
.description("Represents a transform reason of an <a href='events.html#entity transform'>entity transform event</a>.")
.since("2.8.0"));

if (Skript.classExists("org.bukkit.damage.DamageType")) {
Classes.registerClass(new ClassInfo<>(DamageSource.class, "damagesource")
.user("damage ?sources?")
.name("Damage Source")
.description("The damage source in an entity damage event.")
.since("INSERT VERSION"));

Classes.registerClass(new ClassInfo<>(DamageType.class, "damagetype")
.user("damage ?types?")
.name("Damage Type")
.description("The damage type of a damage source.")
.since("INSERT VERSION")
.parser(new Parser<DamageType>() {
@Override
@Nullable
public DamageType parse(String input, ParseContext context) {
if (input.contains(":")) {
String[] split = input.split(Pattern.quote(":"));
try {
return Registry.DAMAGE_TYPE.get(new NamespacedKey(split[0], split[1]));
} catch (IllegalArgumentException e) {}
}
try {
return Registry.DAMAGE_TYPE.get(NamespacedKey.minecraft(input));
} catch (IllegalArgumentException e) {}

return null;
}

@Override
public String toString(DamageType type, int flags) {
return type.getKey();
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public String toVariableNameString(DamageType type) {
return "damage type: " + type.getKey();
}
}));
}

}

}
100 changes: 59 additions & 41 deletions src/main/java/ch/njol/skript/expressions/ExprLastDamageCause.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,86 +18,97 @@
*/
package ch.njol.skript.expressions;

import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.bukkitutil.HealthUtils;
import ch.njol.skript.classes.Changer.ChangeMode;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.RequiredPlugins;
import ch.njol.skript.doc.Since;
import ch.njol.skript.expressions.base.PropertyExpression;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.util.Getter;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.eclipse.jdt.annotation.Nullable;

/**
* @author bensku
*
*/
@Name("Last Damage Cause")
@Description("Cause of last damage done to an entity")
@Examples({"set last damage cause of event-entity to fire tick"})
@Name("Last Damage Cause/Type")
@Description({
"Cause of last damage done to an entity.",
"Damage type is more accurate including data pack types and only available in 1.20.4+"
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
})
@Examples({
"set last damage cause of event-entity to fire tick"
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
})
@RequiredPlugins("Spigot 1.20.4+ damage type")
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
@Since("2.2-Fixes-V10")
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
public class ExprLastDamageCause extends PropertyExpression<LivingEntity, DamageCause>{
public class ExprLastDamageCause extends PropertyExpression<LivingEntity, Object> {

static {
register(ExprLastDamageCause.class, DamageCause.class, "last damage (cause|reason|type)", "livingentities");
register(ExprLastDamageCause.class, Object.class, "last damage (cause|reason|:type)", "livingentities");
}

@SuppressWarnings({"unchecked", "null"})
private boolean type;

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
@SuppressWarnings("unchecked")
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
setExpr((Expression<LivingEntity>) exprs[0]);
type = parseResult.hasTag("type");
return true;
}

@Override
protected DamageCause[] get(Event e, LivingEntity[] source) {
return get(source, new Getter<DamageCause, LivingEntity>() {
protected Object[] get(Event event, LivingEntity[] source) {
return get(source, new Getter<Object, LivingEntity>() {
@Override
public DamageCause get(LivingEntity entity) {
EntityDamageEvent dmgEvt = entity.getLastDamageCause();
if (dmgEvt == null) return DamageCause.CUSTOM;
return dmgEvt.getCause();
public Object get(LivingEntity entity) {
EntityDamageEvent damageEvent = entity.getLastDamageCause();
if (damageEvent == null) {
if (type)
return DamageType.GENERIC;
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
return DamageCause.CUSTOM;
}
if (type)
return damageEvent.getDamageSource().getDamageType();
return damageEvent.getCause();
}
});
}

@Override
public String toString(@Nullable Event e, boolean debug) {
return "the damage cause " + getExpr().toString(e, debug);
}


@Override
@Nullable
public Class<?>[] acceptChange(ChangeMode mode) {
if (mode == ChangeMode.REMOVE_ALL)
if (mode == ChangeMode.REMOVE_ALL || type || HealthUtils.DAMAGE_SOURCE)
return null;
return CollectionUtils.array(DamageCause.class);
}

@Override
public void change(Event e, @Nullable Object[] delta, ChangeMode mode) {
DamageCause d = delta == null ? DamageCause.CUSTOM : (DamageCause) delta[0];
assert d != null;
public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
DamageCause cause = delta == null ? DamageCause.CUSTOM : (DamageCause) delta[0];
assert cause != null;
switch (mode) {
case DELETE:
case RESET: // Reset damage cause? Umm, maybe it is custom.
for (LivingEntity entity : getExpr().getArray(e)) {
for (LivingEntity entity : getExpr().getArray(event)) {
assert entity != null : getExpr();
HealthUtils.setDamageCause(entity, DamageCause.CUSTOM);
}
break;
case SET:
for (LivingEntity entity : getExpr().getArray(e)) {
for (LivingEntity entity : getExpr().getArray(event)) {
assert entity != null : getExpr();
HealthUtils.setDamageCause(entity, d);
HealthUtils.setDamageCause(entity, cause);
}
break;
case REMOVE_ALL:
Expand All @@ -107,10 +118,17 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) {
break;
}
}


@Override
public Class<?> getReturnType() {
return type ? DamageType.class : DamageCause.class;
}

@Override
public Class<DamageCause> getReturnType() {
return DamageCause.class;
public String toString(@Nullable Event event, boolean debug) {
if (type)
return "damage type " + getExpr().toString(event, debug);
return "damage cause " + getExpr().toString(event, debug);
}

}
2 changes: 2 additions & 0 deletions src/main/resources/lang/default.lang
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,8 @@ types:
quitreason: quit reason¦s @a
inventoryclosereason: inventory close reason¦s @an
transformreason: transform reason¦s @a
damagesource: damage source¦s @a
damagetype: damage type¦s @a

# Skript
weathertype: weather type¦s @a
Expand Down
Loading