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

Support damage entity with damage-causes in MC 1.20.4+ #7044

Merged
merged 31 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a514e6b
feat: damage entity with damage-causes
0XPYEX0 Sep 6, 2024
1ff2d38
style: import
0XPYEX0 Sep 6, 2024
5f3d85f
fix: ArrayIndexOutOfBoundsException
0XPYEX0 Sep 8, 2024
5b7e469
perf: resolved pr mentioned
0XPYEX0 Sep 9, 2024
0896764
style: Add example
0XPYEX0 Sep 9, 2024
4bbaeef
style: sort codes
0XPYEX0 Sep 9, 2024
0f4b211
perf: resolved PR mentioned
0XPYEX0 Sep 10, 2024
d525ca7
style: depart to DamageUtils
0XPYEX0 Sep 10, 2024
ce426bd
style: remove licence
0XPYEX0 Sep 10, 2024
42b5f7e
perf: depart to HealthUtils
0XPYEX0 Sep 10, 2024
8e1305a
style: description
0XPYEX0 Sep 10, 2024
30ba088
style: to JetBrains annotation
0XPYEX0 Sep 10, 2024
7d9f9ea
perf: resolved PR mentioned
0XPYEX0 Sep 10, 2024
4777452
style: Suppress exactly; Add description
0XPYEX0 Sep 10, 2024
a08c132
perf: Deny using damage cause in old version
0XPYEX0 Sep 10, 2024
6b2e173
perf: resolved PR mentioned
0XPYEX0 Sep 10, 2024
dce2d89
perf: resolved PR mentioned
0XPYEX0 Sep 10, 2024
013d1fb
perf: 更新 EffHealth.java
0XPYEX0 Sep 10, 2024
71d4f98
style: sort code
0XPYEX0 Sep 11, 2024
1715e8b
Merge remote-tracking branch 'origin/dev/feature' into dev/feature
0XPYEX0 Sep 11, 2024
afa0d36
Merge branch 'dev/feature' into dev/feature
0XPYEX0 Sep 11, 2024
951a6bd
feat: test codes
0XPYEX0 Sep 11, 2024
95579f4
perf: test codes
0XPYEX0 Sep 21, 2024
7579963
perf: check version
0XPYEX0 Sep 21, 2024
4a8556e
fix: wrong health
0XPYEX0 Sep 21, 2024
6b0e862
Merge branch 'SkriptLang:dev/feature' into dev/feature
0XPYEX0 Oct 1, 2024
c73eae2
fix: test codes
0XPYEX0 Oct 1, 2024
69741af
Merge branch 'SkriptLang:dev/feature' into dev/feature
0XPYEX0 Oct 2, 2024
571042b
Merge branch 'dev/feature' into dev/feature
sovdeeth Oct 3, 2024
c1832a5
Merge branch 'dev/feature' into dev/feature
Efnilite Nov 30, 2024
05e22e7
Update src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java
Efnilite Nov 30, 2024
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
41 changes: 41 additions & 0 deletions src/main/java/ch/njol/skript/bukkitutil/DamageUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ch.njol.skript.bukkitutil;

import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.jetbrains.annotations.NotNull;

public class DamageUtils {
0XPYEX0 marked this conversation as resolved.
Show resolved Hide resolved

@SuppressWarnings("UnstableApiUsage")
public static @NotNull DamageSource getDamageSourceFromCause(DamageCause cause) {
return DamageSource.builder(switch (cause) {
case KILL, SUICIDE -> DamageType.GENERIC_KILL;
case WORLD_BORDER, VOID -> DamageType.OUT_OF_WORLD;
case CONTACT -> DamageType.CACTUS;
case SUFFOCATION -> DamageType.IN_WALL;
case FALL -> DamageType.FALL;
case FIRE -> DamageType.ON_FIRE;
case FIRE_TICK -> DamageType.IN_FIRE;
case LAVA -> DamageType.LAVA;
case DROWNING -> DamageType.DROWN;
case BLOCK_EXPLOSION, ENTITY_EXPLOSION -> DamageType.EXPLOSION;
case LIGHTNING -> DamageType.LIGHTNING_BOLT;
case STARVATION -> DamageType.STARVE;
case MAGIC, POISON -> DamageType.MAGIC;
case WITHER -> DamageType.WITHER;
case FALLING_BLOCK -> DamageType.FALLING_BLOCK;
case THORNS -> DamageType.THORNS;
case DRAGON_BREATH -> DamageType.DRAGON_BREATH;
case FLY_INTO_WALL -> DamageType.FLY_INTO_WALL;
case HOT_FLOOR -> DamageType.HOT_FLOOR;
case CAMPFIRE -> DamageType.CAMPFIRE;
case CRAMMING -> DamageType.CRAMMING;
case DRYOUT -> DamageType.DRY_OUT;
case FREEZE -> DamageType.FREEZE;
case SONIC_BOOM -> DamageType.SONIC_BOOM;
default -> DamageType.GENERIC;
}).build();
}
0XPYEX0 marked this conversation as resolved.
Show resolved Hide resolved

}
137 changes: 65 additions & 72 deletions src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
/**
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
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 org.bukkit.attribute.Attributable;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
Expand All @@ -31,115 +15,124 @@
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.jetbrains.annotations.Nullable;

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

public class HealthUtils {
private static final @Nullable Constructor<EntityDamageEvent> OLD_DAMAGE_EVENT_CONSTRUCTOR;

static {
Constructor<EntityDamageEvent> constructor = null;
try {
constructor = EntityDamageEvent.class.getConstructor(Damageable.class, DamageCause.class, double.class);
} catch (NoSuchMethodException ignored) {}
OLD_DAMAGE_EVENT_CONSTRUCTOR = constructor;
}

/**
* Get the health of an entity
* @param e Entity to get health from
*
* @param damageable Entity to get health from
* @return The amount of hearts the entity has left
*/
public static double getHealth(Damageable e) {
if (e.isDead())
public static double getHealth(Damageable damageable) {
if (damageable.isDead())
return 0;
return e.getHealth() / 2;
return damageable.getHealth() / 2;
}

/**
* Set the health of an entity
* @param e Entity to set health for
*
* @param damageable Entity to set health for
* @param health The amount of hearts to set
*/
public static void setHealth(Damageable e, double health) {
e.setHealth(Math2.fit(0, health, getMaxHealth(e)) * 2);
public static void setHealth(Damageable damageable, double health) {
damageable.setHealth(Math2.fit(0, health, getMaxHealth(damageable)) * 2);
}

/**
* Get the max health an entity has
* @param e Entity to get max health from
*
* @param damageable Entity to get max health from
* @return How many hearts the entity can have at most
*/
public static double getMaxHealth(Damageable e) {
AttributeInstance attributeInstance = ((Attributable) e).getAttribute(Attribute.GENERIC_MAX_HEALTH);
public static double getMaxHealth(Damageable damageable) {
AttributeInstance attributeInstance = ((Attributable) damageable).getAttribute(Attribute.GENERIC_MAX_HEALTH);
assert attributeInstance != null;
return attributeInstance.getValue() / 2;
}

/**
* Set the max health an entity can have
* @param e Entity to set max health for
*
* @param damageable Entity to set max health for
* @param health How many hearts the entity can have at most
*/
public static void setMaxHealth(Damageable e, double health) {
AttributeInstance attributeInstance = ((Attributable) e).getAttribute(Attribute.GENERIC_MAX_HEALTH);
public static void setMaxHealth(Damageable damageable, double health) {
AttributeInstance attributeInstance = ((Attributable) damageable).getAttribute(Attribute.GENERIC_MAX_HEALTH);
assert attributeInstance != null;
attributeInstance.setBaseValue(health * 2);
}

/**
* Apply damage to an entity
* @param e Entity to apply damage to
* @param d Amount of hearts to damage
*
* @param damageable Entity to apply damage to
* @param damage Amount of hearts to damage
*/
public static void damage(Damageable e, double d) {
if (d < 0) {
heal(e, -d);
public static void damage(Damageable damageable, double damage) {
if (damage < 0) {
heal(damageable, -damage);
return;
}
e.damage(d * 2);
damageable.damage(damage * 2);
}

@SuppressWarnings("UnstableApiUsage")
public static void damage(Damageable damageable, double damage, DamageSource cause) {
if (damage < 0) {
heal(damageable, -damage);
return;
}
damageable.damage(damage * 2, cause);
}

/**
* Heal an entity
* @param e Entity to heal
* @param h Amount of hearts to heal
*
* @param damageable Entity to heal
* @param health Amount of hearts to heal
*/
public static void heal(Damageable e, double h) {
if (h < 0) {
damage(e, -h);
public static void heal(Damageable damageable, double health) {
if (health < 0) {
damage(damageable, -health);
return;
}
setHealth(e, getHealth(e) + h);
setHealth(damageable, getHealth(damageable) + health);
}
public static double getDamage(EntityDamageEvent e) {
return e.getDamage() / 2;

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

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

public static void setDamage(EntityDamageEvent event, double damage) {
event.setDamage(damage * 2);
// Set last damage manually as Bukkit doesn't appear to do that
if (event.getEntity() instanceof LivingEntity)
((LivingEntity) event.getEntity()).setLastDamage(damage * 2);
}

@Nullable
private static final Constructor<EntityDamageEvent> OLD_DAMAGE_EVENT_CONSTRUCTOR;

static {
Constructor<EntityDamageEvent> constructor = null;
try {
constructor = EntityDamageEvent.class.getConstructor(Damageable.class, DamageCause.class, double.class);
} catch (NoSuchMethodException ignored) { }
OLD_DAMAGE_EVENT_CONSTRUCTOR = constructor;
}

public static void setDamageCause(Damageable e, DamageCause cause) {
public static void setDamageCause(Damageable damageable, DamageCause cause) {
if (OLD_DAMAGE_EVENT_CONSTRUCTOR != null) {
try {
e.setLastDamageCause(OLD_DAMAGE_EVENT_CONSTRUCTOR.newInstance(e, cause, 0));
damageable.setLastDamageCause(OLD_DAMAGE_EVENT_CONSTRUCTOR.newInstance(damageable, cause, 0));
} catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
Skript.exception("Failed to set last damage cause");
}
} else {
e.setLastDamageCause(new EntityDamageEvent(e, cause, DamageSource.builder(DamageType.GENERIC).build(), 0));
damageable.setLastDamageCause(new EntityDamageEvent(damageable, cause, DamageSource.builder(DamageType.GENERIC).build(), 0));
}
}

}
Loading