Skip to content

Commit

Permalink
rewrite Hurt command to have NMS backing
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmonkey4eva committed May 2, 2021
1 parent c88e6ec commit cb7fb8b
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 39 deletions.
Expand Up @@ -4,10 +4,13 @@
import com.denizenscript.denizen.nms.util.jnbt.CompoundTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.*;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
Expand Down Expand Up @@ -325,4 +328,34 @@ public void setGhastAttacking(Entity entity, boolean attacking) {
public void setEndermanAngry(Entity entity, boolean angry) {
throw new UnsupportedOperationException();
}

public static EntityDamageEvent fireFakeDamageEvent(Entity target, Entity source, EntityDamageEvent.DamageCause cause, float amount) {
EntityDamageEvent ede = source == null ? new EntityDamageEvent(target, cause, amount) : new EntityDamageByEntityEvent(source, target, cause, amount);
Bukkit.getPluginManager().callEvent(ede);
return ede;
}

public void damage(LivingEntity target, float amount, Entity source, EntityDamageEvent.DamageCause cause) {
if (cause == null) {
if (source == null) {
target.damage(amount);
}
else {
target.damage(amount, source);
}
}
else {
EntityDamageEvent ede = fireFakeDamageEvent(target, source, cause, amount);
if (!ede.isCancelled()) {
target.setLastDamageCause(ede);
if (source == null) {
target.damage(ede.getFinalDamage());
}
else {
target.damage(ede.getFinalDamage(), source);
}
target.setLastDamageCause(ede);
}
}
}
}
@@ -1,5 +1,6 @@
package com.denizenscript.denizen.scripts.commands.entity;

import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizen.utilities.debugging.Debug;
import com.denizenscript.denizen.objects.EntityTag;
Expand All @@ -10,8 +11,6 @@
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.AbstractCommand;
import org.bukkit.Bukkit;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;

import java.util.ArrayList;
Expand All @@ -21,16 +20,16 @@ public class HurtCommand extends AbstractCommand {

public HurtCommand() {
setName("hurt");
setSyntax("hurt (<#.#>) ({player}/<entity>|...) (cause:<cause>) (source:<entity>) (source_once)");
setSyntax("hurt (<#.#>) ({player}/<entity>|...) (cause:<cause>) (source:<entity>)");
setRequiredArguments(0, 5);
isProcedural = false;
}

// <--[command]
// @Name Hurt
// @Syntax hurt (<#.#>) ({player}/<entity>|...) (cause:<cause>) (source:<entity>) (source_once)
// @Syntax hurt (<#.#>) ({player}/<entity>|...) (cause:<cause>) (source:<entity>)
// @Required 0
// @Maximum 5
// @Maximum 4
// @Short Hurts the player or a list of entities.
// @Group entity
//
Expand All @@ -42,13 +41,13 @@ public HurtCommand() {
//
// Does a specified amount of damage usually, but, if no damage is specified, does precisely 1HP worth of damage (half a heart).
//
// Optionally, specify (source:<entity>) to make the system treat that entity as the attacker,
// be warned this does not always work as intended, and is liable to glitch.
// You may also optionally specify a damage cause to fire a proper damage event with the given cause,
// only doing the damage if the event wasn't cancelled. Calculates the 'final damage' rather
// than using the raw damage input number. See <@link language damage cause> for damage causes.
// To make the source only be included in the initial damage event, and not the application of damage, specify 'source_once'.
// Note that 'cause' values are hacked in, similarly to the 'source' value.
// Optionally, specify (source:<entity>) to make the system treat that entity as the attacker.
//
// You may also specify a damage cause to fire a proper damage event with the given cause, only doing the damage if the event wasn't cancelled.
// Calculates the 'final damage' rather than using the raw damage input number. See <@link language damage cause> for damage causes.
//
// Using a valid 'cause' value is best when trying to replicate natural damage, excluding it is best when trying to force the raw damage through.
// Note that using invalid or impossible causes may lead to bugs
//
// @Tags
// <EntityTag.health>
Expand Down Expand Up @@ -139,30 +138,8 @@ public void execute(ScriptEntry scriptEntry) {
Debug.echoDebug(scriptEntry, entity + " is not a living entity!");
continue;
}
if (cause == null) {
if (source == null) {
entity.getLivingEntity().damage(amount);
}
else {
entity.getLivingEntity().damage(amount, source.getBukkitEntity());
}
}
else {
EntityDamageEvent.DamageCause causeEnum = EntityDamageEvent.DamageCause.valueOf(cause.asString().toUpperCase());
EntityDamageEvent ede = source == null ? new EntityDamageEvent(entity.getBukkitEntity(), causeEnum, amount) :
new EntityDamageByEntityEvent(source.getBukkitEntity(), entity.getBukkitEntity(), causeEnum, amount);
Bukkit.getPluginManager().callEvent(ede);
if (!ede.isCancelled()) {
entity.getLivingEntity().setLastDamageCause(ede);
if (source == null || (source_once != null && source_once.asBoolean())) {
entity.getLivingEntity().damage(ede.getFinalDamage());
}
else {
entity.getLivingEntity().damage(ede.getFinalDamage(), source.getBukkitEntity());
}
entity.getLivingEntity().setLastDamageCause(ede);
}
}
EntityDamageEvent.DamageCause causeEnum = cause == null ? null : EntityDamageEvent.DamageCause.valueOf(cause.asString().toUpperCase());
NMSHandler.getEntityHelper().damage(entity.getLivingEntity(), (float) amount, source == null ? null : source.getBukkitEntity(), causeEnum);
}
}
}
Expand Up @@ -130,9 +130,6 @@ public class CommandScriptContainer extends ScriptContainer {
// # <context.command_minecart> returns the EntityTag of the command minecart (if the command was run from one).
// # | All command scripts MUST have this key!
// script:
// - if !<player.is_op||<context.server>>:
// - narrate "<red>You do not have permission for that command."
// - stop
// - narrate Yay!
// - narrate "My command worked!"
// - narrate "And I typed '/<context.alias> <context.raw_args>'!"
Expand Down
Expand Up @@ -19,9 +19,11 @@
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
import org.bukkit.craftbukkit.v1_16_R3.entity.*;
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
import org.bukkit.entity.*;
import org.bukkit.entity.Entity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.inventory.ItemStack;
Expand Down Expand Up @@ -673,4 +675,123 @@ public void setGhastAttacking(Entity entity, boolean attacking) {
public void setEndermanAngry(Entity entity, boolean angry) {
((CraftEnderman) entity).getHandle().getDataWatcher().set(ENTITY_ENDERMAN_DATAWATCHER_SCREAMING, angry);
}

@Override
public void damage(LivingEntity target, float amount, Entity source, EntityDamageEvent.DamageCause cause) {
if (target == null) {
return;
}
EntityLiving nmsTarget = ((CraftLivingEntity) target).getHandle();
net.minecraft.server.v1_16_R3.Entity nmsSource = source == null ? null : ((CraftEntity) source).getHandle();
CraftEventFactory.entityDamage = nmsSource;
try {
DamageSource src = DamageSource.GENERIC;
if (nmsSource != null) {
if (nmsSource instanceof EntityHuman) {
src = DamageSource.playerAttack((EntityHuman) nmsSource);
}
else if (nmsSource instanceof EntityLiving) {
src = DamageSource.mobAttack((EntityLiving) nmsSource);
}
}
if (cause != null) {
switch (cause) {
case CONTACT:
src = DamageSource.CACTUS;
break;
case ENTITY_ATTACK:
src = DamageSource.mobAttack(nmsSource instanceof EntityLiving ? (EntityLiving) nmsSource : null);
break;
case ENTITY_SWEEP_ATTACK:
if (src != DamageSource.GENERIC) {
src.sweep();
}
break;
case PROJECTILE:
src = DamageSource.projectile(nmsSource, source instanceof Projectile && ((Projectile) source).getShooter() instanceof Entity ? ((CraftEntity) ((Projectile) source).getShooter()).getHandle() : null);
break;
case SUFFOCATION:
src = DamageSource.STUCK;
break;
case FALL:
src = DamageSource.FALL;
break;
case FIRE:
src = DamageSource.FIRE;
break;
case FIRE_TICK:
src = DamageSource.BURN;
break;
case MELTING:
src = CraftEventFactory.MELTING;
break;
case LAVA:
src = DamageSource.LAVA;
break;
case DROWNING:
src = DamageSource.DROWN;
break;
case BLOCK_EXPLOSION:
src = DamageSource.d(nmsSource instanceof TNTPrimed && ((TNTPrimed) nmsSource).getSource() instanceof EntityLiving ? (EntityLiving) ((TNTPrimed) nmsSource).getSource() : null);
break;
case ENTITY_EXPLOSION:
src = DamageSource.d(nmsSource instanceof EntityLiving ? (EntityLiving) nmsSource : null);
break;
case VOID:
src = DamageSource.OUT_OF_WORLD;
break;
case LIGHTNING:
src = DamageSource.LIGHTNING;
break;
case STARVATION:
src = DamageSource.STARVE;
break;
case POISON:
src = CraftEventFactory.POISON;
break;
case MAGIC:
src = DamageSource.MAGIC;
break;
case WITHER:
src = DamageSource.WITHER;
break;
case FALLING_BLOCK:
src = DamageSource.FALLING_BLOCK;
break;
case THORNS:
src = DamageSource.a(nmsSource);
break;
case DRAGON_BREATH:
src = DamageSource.DRAGON_BREATH;
break;
case CUSTOM:
src = DamageSource.GENERIC;
break;
case FLY_INTO_WALL:
src = DamageSource.FLY_INTO_WALL;
break;
case HOT_FLOOR:
src = DamageSource.HOT_FLOOR;
break;
case CRAMMING:
src = DamageSource.CRAMMING;
break;
case DRYOUT:
src = DamageSource.DRYOUT;
break;
//case SUICIDE:
default:
EntityDamageEvent ede = fireFakeDamageEvent(target, source, cause, amount);
if (ede.isCancelled()) {
return;
}
break;
}
}
nmsTarget.damageEntity(src, amount);
}
finally {
CraftEventFactory.entityDamage = null;
}
}
}

0 comments on commit cb7fb8b

Please sign in to comment.