From b0fc8d6e32a6fe13b7fc99206180387009eb0e4d Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Mon, 8 Apr 2024 15:35:06 -0400 Subject: [PATCH 01/41] Damage Pipeline Changes --- .../client/player/LocalPlayer.java.patch | 2 +- .../client/player/RemotePlayer.java.patch | 2 +- .../minecraft/world/entity/Entity.java.patch | 266 +++++++--- .../world/entity/LivingEntity.java.patch | 482 +++++++++++------- .../world/entity/player/Inventory.java.patch | 15 + .../world/entity/player/Player.java.patch | 356 +++++++------ .../neoforge/common/CommonHooks.java | 70 ++- .../common/damagesource/DamageContainer.java | 118 +++++ .../extensions/ILivingEntityExtension.java | 13 + .../EntityInvulnerablityCheckEvent.java | 57 +++ .../event/entity/living/ArmorHurtEvent.java | 72 +++ .../event/entity/living/DamageBlockEvent.java | 108 ++++ .../entity/living/DamageSequenceEvent.java | 37 ++ ...DamageEvent.java => DamageTakenEvent.java} | 26 +- ...ckEvent.java => EntityPreDamageEvent.java} | 16 +- ...urtEvent.java => IncomingDamageEvent.java} | 27 +- .../event/entity/living/ShieldBlockEvent.java | 78 --- .../neoforge/debug/data/DataMapTests.java | 6 +- .../debug/entity/EntityEventTests.java | 23 + .../entity/living/LivingEntityEventTests.java | 6 +- .../debug/entity/player/PlayerEventTests.java | 26 + 21 files changed, 1234 insertions(+), 572 deletions(-) create mode 100644 src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java create mode 100644 src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java create mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java create mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java create mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java rename src/main/java/net/neoforged/neoforge/event/entity/living/{LivingDamageEvent.java => DamageTakenEvent.java} (71%) rename src/main/java/net/neoforged/neoforge/event/entity/living/{LivingAttackEvent.java => EntityPreDamageEvent.java} (78%) rename src/main/java/net/neoforged/neoforge/event/entity/living/{LivingHurtEvent.java => IncomingDamageEvent.java} (63%) delete mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/ShieldBlockEvent.java diff --git a/patches/net/minecraft/client/player/LocalPlayer.java.patch b/patches/net/minecraft/client/player/LocalPlayer.java.patch index eeebdce01e..55c270e2c6 100644 --- a/patches/net/minecraft/client/player/LocalPlayer.java.patch +++ b/patches/net/minecraft/client/player/LocalPlayer.java.patch @@ -4,7 +4,7 @@ @Override public boolean hurt(DamageSource p_108662_, float p_108663_) { -+ net.neoforged.neoforge.common.CommonHooks.onPlayerAttack(this, p_108662_, p_108663_); ++ net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer); return false; } diff --git a/patches/net/minecraft/client/player/RemotePlayer.java.patch b/patches/net/minecraft/client/player/RemotePlayer.java.patch index afa4ad0f6c..37a4483449 100644 --- a/patches/net/minecraft/client/player/RemotePlayer.java.patch +++ b/patches/net/minecraft/client/player/RemotePlayer.java.patch @@ -4,7 +4,7 @@ @Override public boolean hurt(DamageSource p_108772_, float p_108773_) { -+ net.neoforged.neoforge.common.CommonHooks.onPlayerAttack(this, p_108772_, p_108773_); ++ net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer); return true; } diff --git a/patches/net/minecraft/world/entity/Entity.java.patch b/patches/net/minecraft/world/entity/Entity.java.patch index 573983871a..5b2dea07e9 100644 --- a/patches/net/minecraft/world/entity/Entity.java.patch +++ b/patches/net/minecraft/world/entity/Entity.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -128,7 +_,7 @@ - import net.minecraft.world.scores.Team; +@@ -124,7 +_,7 @@ + import org.joml.Vector3f; import org.slf4j.Logger; --public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder { -+public abstract class Entity extends net.neoforged.neoforge.attachment.AttachmentHolder implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder, net.neoforged.neoforge.common.extensions.IEntityExtension { +-public abstract class Entity implements Nameable, EntityAccess, CommandSource, ScoreHolder { ++public abstract class Entity extends net.neoforged.neoforge.attachment.AttachmentHolder implements Nameable, EntityAccess, CommandSource, ScoreHolder, net.neoforged.neoforge.common.extensions.IEntityExtension { private static final Logger LOGGER = LogUtils.getLogger(); public static final String ID_TAG = "id"; public static final String PASSENGERS_TAG = "Passengers"; -@@ -149,6 +_,7 @@ +@@ -145,6 +_,7 @@ private static final double LAVA_SLOW_FLOW_SCALE = 0.0023333333333333335; public static final String UUID_TAG = "UUID"; private static double viewScale = 1.0; @@ -17,7 +17,7 @@ private final EntityType type; private int id = ENTITY_COUNTER.incrementAndGet(); public boolean blocksBuilding; -@@ -194,8 +_,10 @@ +@@ -191,8 +_,10 @@ public int tickCount; private int remainingFireTicks = -this.getFireImmuneTicks(); protected boolean wasTouchingWater; @@ -28,19 +28,19 @@ private final Set> fluidOnEyes = new HashSet<>(); public int invulnerableTime; protected boolean firstTick = true; -@@ -263,7 +_,10 @@ - this.defineSynchedData(synchedentitydata$builder); - this.entityData = synchedentitydata$builder.build(); +@@ -260,7 +_,10 @@ + this.entityData.define(DATA_TICKS_FROZEN, 0); + this.defineSynchedData(); this.setPos(0.0, 0.0, 0.0); -- this.eyeHeight = this.dimensions.eyeHeight(); -+ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, Pose.STANDING, this.dimensions, this.dimensions.eyeHeight()); +- this.eyeHeight = this.getEyeHeight(Pose.STANDING, this.dimensions); ++ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, Pose.STANDING, this.dimensions, this.getEyeHeight(Pose.STANDING, this.dimensions)); + this.dimensions = sizeEvent.getNewSize(); + this.eyeHeight = sizeEvent.getNewEyeHeight(); + net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.EntityEvent.EntityConstructing(this)); } public boolean isColliding(BlockPos p_20040_, BlockState p_20041_) { -@@ -467,7 +_,7 @@ +@@ -468,7 +_,7 @@ if (this.isInLava()) { this.lavaHurt(); @@ -49,16 +49,16 @@ } this.checkBelowWorld(); -@@ -673,7 +_,7 @@ +@@ -675,7 +_,7 @@ double d1 = vec3.x; double d2 = vec3.y; double d3 = vec3.z; -- this.flyDist = this.flyDist + (float)(vec3.length() * 0.6); +- this.flyDist += (float)(vec3.length() * 0.6); + this.flyDist = (float)((double)this.flyDist + vec3.length() * 0.6D); BlockPos blockpos1 = this.getOnPos(); BlockState blockstate1 = this.level().getBlockState(blockpos1); boolean flag1 = this.isStateClimbable(blockstate1); -@@ -717,16 +_,16 @@ +@@ -719,16 +_,16 @@ this.setRemainingFireTicks(-this.getFireImmuneTicks()); } @@ -78,7 +78,7 @@ } } } -@@ -812,9 +_,7 @@ +@@ -814,9 +_,7 @@ return blockpos; } else { BlockState blockstate = this.level().getBlockState(blockpos); @@ -89,7 +89,25 @@ ? blockpos.atY(Mth.floor(this.position.y - (double)p_216987_)) : blockpos; } -@@ -1076,19 +_,19 @@ +@@ -889,12 +_,13 @@ + boolean flag1 = p_20273_.y != vec3.y; + boolean flag2 = p_20273_.z != vec3.z; + boolean flag3 = this.onGround() || flag1 && p_20273_.y < 0.0; +- if (this.maxUpStep() > 0.0F && flag3 && (flag || flag2)) { +- Vec3 vec31 = collideBoundingBox(this, new Vec3(p_20273_.x, (double)this.maxUpStep(), p_20273_.z), aabb, this.level(), list); ++ float stepHeight = getStepHeight(); ++ if (stepHeight > 0.0F && flag3 && (flag || flag2)) { ++ Vec3 vec31 = collideBoundingBox(this, new Vec3(p_20273_.x, (double)stepHeight, p_20273_.z), aabb, this.level(), list); + Vec3 vec32 = collideBoundingBox( +- this, new Vec3(0.0, (double)this.maxUpStep(), 0.0), aabb.expandTowards(p_20273_.x, 0.0, p_20273_.z), this.level(), list ++ this, new Vec3(0.0D, (double)stepHeight, 0.0D), aabb.expandTowards(p_20273_.x, 0.0D, p_20273_.z), this.level(), list + ); +- if (vec32.y < (double)this.maxUpStep()) { ++ if (vec32.y < (double)stepHeight) { + Vec3 vec33 = collideBoundingBox(this, new Vec3(p_20273_.x, 0.0, p_20273_.z), aabb.move(vec32), this.level(), list).add(vec32); + if (vec33.horizontalDistanceSqr() > vec31.horizontalDistanceSqr()) { + vec31 = vec33; +@@ -1042,19 +_,19 @@ return !blockstate.is(BlockTags.INSIDE_STEP_SOUND_BLOCKS) && !blockstate.is(BlockTags.COMBINATION_STEP_SOUND_BLOCKS) ? p_278049_ : blockpos; } @@ -115,7 +133,7 @@ this.playSound(soundtype.getStepSound(), soundtype.getVolume() * 0.15F, soundtype.getPitch()); } -@@ -1241,20 +_,23 @@ +@@ -1192,20 +_,23 @@ public void updateSwimming() { if (this.isSwimming()) { @@ -144,15 +162,15 @@ } void updateInWaterStateAndDoWaterCurrentPushing() { -@@ -1279,6 +_,7 @@ +@@ -1231,6 +_,7 @@ private void updateFluidOnEyes() { this.wasEyeInWater = this.isEyeInFluid(FluidTags.WATER); this.fluidOnEyes.clear(); + this.forgeFluidTypeOnEyes = net.neoforged.neoforge.common.NeoForgeMod.EMPTY_TYPE.value(); - double d0 = this.getEyeY(); - if (this.getVehicle() instanceof Boat boat && !boat.isUnderWater() && boat.getBoundingBox().maxY >= d0 && boat.getBoundingBox().minY <= d0) { - return; -@@ -1288,7 +_,7 @@ + double d0 = this.getEyeY() - 0.11111111F; + Entity entity = this.getVehicle(); + if (entity instanceof Boat boat && !boat.isUnderWater() && boat.getBoundingBox().maxY >= d0 && boat.getBoundingBox().minY <= d0) { +@@ -1241,7 +_,7 @@ FluidState fluidstate = this.level().getFluidState(blockpos); double d1 = (double)((float)blockpos.getY() + fluidstate.getHeight(this.level(), blockpos)); if (d1 > d0) { @@ -161,7 +179,7 @@ } } -@@ -1333,12 +_,13 @@ +@@ -1286,12 +_,13 @@ } public boolean canSpawnSprintParticle() { @@ -176,7 +194,7 @@ if (blockstate.getRenderShape() != RenderShape.INVISIBLE) { Vec3 vec3 = this.getDeltaMovement(); BlockPos blockpos1 = this.blockPosition(); -@@ -1352,16 +_,19 @@ +@@ -1305,16 +_,19 @@ d1 = Mth.clamp(d1, (double)blockpos.getZ(), (double)blockpos.getZ() + 1.0); } @@ -198,27 +216,37 @@ } public void moveRelative(float p_19921_, Vec3 p_19922_) { -@@ -1704,6 +_,10 @@ +@@ -1631,6 +_,8 @@ + p_20241_.putBoolean("HasVisualFire", this.hasVisualFire); + } + ++ p_20241_.putBoolean("CanUpdate", canUpdate); ++ + if (!this.tags.isEmpty()) { + ListTag listtag = new ListTag(); + +@@ -1641,6 +_,10 @@ p_20241_.put("Tags", listtag); } -+ CompoundTag attachments = serializeAttachments(registryAccess()); ++ CompoundTag attachments = serializeAttachments(); + if (attachments != null) p_20241_.put(ATTACHMENTS_NBT_KEY, attachments); + if (persistentData != null) p_20241_.put("NeoForgeData", persistentData.copy()); + this.addAdditionalSaveData(p_20241_); if (this.isVehicle()) { ListTag listtag1 = new ListTag(); -@@ -1784,6 +_,8 @@ +@@ -1721,6 +_,9 @@ this.setGlowingTag(p_20259_.getBoolean("Glowing")); this.setTicksFrozen(p_20259_.getInt("TicksFrozen")); this.hasVisualFire = p_20259_.getBoolean("HasVisualFire"); + if (p_20259_.contains("NeoForgeData", 10)) persistentData = p_20259_.getCompound("NeoForgeData"); -+ if (p_20259_.contains(ATTACHMENTS_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) deserializeAttachments(registryAccess(), p_20259_.getCompound(ATTACHMENTS_NBT_KEY)); ++ if (p_20259_.contains("CanUpdate", 99)) this.canUpdate(p_20259_.getBoolean("CanUpdate")); ++ if (p_20259_.contains(ATTACHMENTS_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) deserializeAttachments(p_20259_.getCompound(ATTACHMENTS_NBT_KEY)); if (p_20259_.contains("Tags", 9)) { this.tags.clear(); ListTag listtag3 = p_20259_.getList("Tags", 8); -@@ -1868,6 +_,8 @@ +@@ -1805,6 +_,8 @@ } else { ItemEntity itementity = new ItemEntity(this.level(), this.getX(), this.getY() + (double)p_19986_, this.getZ(), p_19985_); itementity.setDefaultPickUpDelay(); @@ -227,20 +255,15 @@ this.level().addFreshEntity(itementity); return itementity; } -@@ -1935,7 +_,11 @@ +@@ -1851,6 +_,7 @@ public void rideTick() { this.setDeltaMovement(Vec3.ZERO); -- this.tick(); -+ // Neo: Permit cancellation of Entity#tick via EntityTickEvent.Pre -+ if (!net.neoforged.neoforge.event.EventHooks.fireEntityTickPre(this).isCanceled()) { -+ this.tick(); -+ net.neoforged.neoforge.event.EventHooks.fireEntityTickPost(this); -+ } ++ if (canUpdate()) + this.tick(); if (this.isPassenger()) { this.getVehicle().positionRider(this); - } -@@ -1993,6 +_,7 @@ +@@ -1908,6 +_,7 @@ } } @@ -248,7 +271,7 @@ if (p_19967_ || this.canRide(p_19966_) && p_19966_.canAddPassenger(this)) { if (this.isPassenger()) { this.stopRiding(); -@@ -2024,6 +_,7 @@ +@@ -1939,6 +_,7 @@ public void removeVehicle() { if (this.vehicle != null) { Entity entity = this.vehicle; @@ -256,7 +279,7 @@ this.vehicle = null; entity.removePassenger(this); } -@@ -2073,6 +_,8 @@ +@@ -1988,6 +_,8 @@ return this.passengers.isEmpty(); } @@ -265,7 +288,7 @@ protected boolean couldAcceptPassenger() { return true; } -@@ -2257,7 +_,7 @@ +@@ -2193,7 +_,7 @@ } public boolean isVisuallyCrawling() { @@ -274,8 +297,8 @@ } public void setSwimming(boolean p_20283_) { -@@ -2366,7 +_,7 @@ - this.igniteForSeconds(8.0F); +@@ -2302,7 +_,7 @@ + this.setSecondsOnFire(8); } - this.hurt(this.damageSources().lightningBolt(), 5.0F); @@ -283,7 +306,7 @@ } public void onAboveBubbleCol(boolean p_20313_) { -@@ -2461,7 +_,7 @@ +@@ -2397,7 +_,7 @@ } protected Component getTypeName() { @@ -292,15 +315,64 @@ } public boolean is(Entity p_20356_) { -@@ -2544,6 +_,7 @@ +@@ -2452,10 +_,11 @@ + } + + public boolean isInvulnerableTo(DamageSource p_20122_) { +- return this.isRemoved() ++ boolean isVanillaInvulnerable = this.isRemoved() + || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() + || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() + || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); ++ return net.neoforged.neoforge.common.CommonHooks.onEntityInvulnerablityCheck(this, p_20122_, isVanillaInvulnerable); + } + + public boolean isInvulnerable() { +@@ -2480,14 +_,20 @@ @Nullable - public Entity changeDimension(DimensionTransition p_350951_) { -+ if (!net.neoforged.neoforge.common.CommonHooks.onTravelToDimension(this, p_350951_.newLevel().dimension())) return null; - if (this.level() instanceof ServerLevel serverlevel && !this.isRemoved()) { - ServerLevel serverlevel1 = p_350951_.newLevel(); - List list = this.getPassengers(); -@@ -2667,6 +_,7 @@ + public Entity changeDimension(ServerLevel p_20118_) { ++ return this.changeDimension(p_20118_, p_20118_.getPortalForcer()); ++ } ++ @Nullable ++ public Entity changeDimension(ServerLevel p_20118_, net.neoforged.neoforge.common.util.ITeleporter teleporter) { ++ if (!net.neoforged.neoforge.common.CommonHooks.onTravelToDimension(this, p_20118_.dimension())) return null; + if (this.level() instanceof ServerLevel && !this.isRemoved()) { + this.level().getProfiler().push("changeDimension"); + this.unRide(); + this.level().getProfiler().push("reposition"); +- PortalInfo portalinfo = this.findDimensionEntryPoint(p_20118_); ++ PortalInfo portalinfo = teleporter.getPortalInfo(this, p_20118_, this::findDimensionEntryPoint); + if (portalinfo == null) { + return null; + } else { ++ Entity transportedEntity = teleporter.placeEntity(this, (ServerLevel) this.level, p_20118_, this.yRot, spawnPortal -> { //Forge: Start vanilla logic + this.level().getProfiler().popPush("reloading"); + Entity entity = this.getType().create(p_20118_); + if (entity != null) { +@@ -2495,17 +_,19 @@ + entity.moveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z, portalinfo.yRot, entity.getXRot()); + entity.setDeltaMovement(portalinfo.speed); + p_20118_.addDuringTeleport(entity); +- if (p_20118_.dimension() == Level.END) { ++ if (spawnPortal && p_20118_.dimension() == Level.END) { + ServerLevel.makeObsidianPlatform(p_20118_); + } + } ++ return entity; ++ }); //Forge: End vanilla logic + + this.removeAfterChangingDimensions(); + this.level().getProfiler().pop(); + ((ServerLevel)this.level()).resetEmptyTime(); + p_20118_.resetEmptyTime(); + this.level().getProfiler().pop(); +- return entity; ++ return transportedEntity; + } + } else { + return null; +@@ -2641,6 +_,7 @@ return this.stringUUID; } @@ -308,17 +380,32 @@ public boolean isPushedByFluid() { return true; } -@@ -2783,6 +_,8 @@ +@@ -2764,8 +_,10 @@ EntityDimensions entitydimensions = this.dimensions; Pose pose = this.getPose(); EntityDimensions entitydimensions1 = this.getDimensions(pose); -+ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, pose, entitydimensions, entitydimensions1, entitydimensions1.eyeHeight()); // Porting 1.20.5 check if this still works ++ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, pose, entitydimensions, entitydimensions1, this.getEyeHeight(pose, entitydimensions1)); + entitydimensions1 = sizeEvent.getNewSize(); this.dimensions = entitydimensions1; - this.eyeHeight = entitydimensions1.eyeHeight(); +- this.eyeHeight = this.getEyeHeight(pose, entitydimensions1); ++ this.eyeHeight = sizeEvent.getNewEyeHeight(); this.reapplyPosition(); -@@ -3110,9 +_,17 @@ - return Mth.lerp(p_352259_, this.yRotO, this.yRot); + boolean flag = (double)entitydimensions1.width <= 4.0 && (double)entitydimensions1.height <= 4.0; + if (!this.level().isClientSide +@@ -2778,9 +_,10 @@ + double d0 = (double)Math.max(0.0F, entitydimensions1.width - entitydimensions.width) + 1.0E-6; + double d1 = (double)Math.max(0.0F, entitydimensions1.height - entitydimensions.height) + 1.0E-6; + VoxelShape voxelshape = Shapes.create(AABB.ofSize(vec3, d0, d1, d0)); ++ EntityDimensions finalEntitydimensions = entitydimensions1; + this.level() + .findFreePosition(this, voxelshape, vec3, (double)entitydimensions1.width, (double)entitydimensions1.height, (double)entitydimensions1.width) +- .ifPresent(p_185956_ -> this.setPos(p_185956_.add(0.0, (double)(-entitydimensions1.height) / 2.0, 0.0))); ++ .ifPresent(p_185956_ -> this.setPos(p_185956_.add(0.0, (double)(-finalEntitydimensions.height) / 2.0, 0.0))); + } + } + +@@ -3076,9 +_,17 @@ + this.yRotO = this.getYRot(); } + @Deprecated // Forge: Use no parameter version instead, only for vanilla Tags @@ -336,7 +423,7 @@ } else { AABB aabb = this.getBoundingBox().deflate(0.001); int i = Mth.floor(aabb.minX); -@@ -3127,25 +_,36 @@ +@@ -3093,25 +_,36 @@ Vec3 vec3 = Vec3.ZERO; int k1 = 0; BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(); @@ -347,9 +434,9 @@ + } + it.unimi.dsi.fastutil.objects.Object2ObjectMap interimCalcs = null; - for (int l1 = i; l1 < j; l1++) { - for (int i2 = k; i2 < l; i2++) { - for (int j2 = i1; j2 < j1; j2++) { + for(int l1 = i; l1 < j; ++l1) { + for(int i2 = k; i2 < l; ++i2) { + for(int j2 = i1; j2 < j1; ++j2) { blockpos$mutableblockpos.set(l1, i2, j2); FluidState fluidstate = this.level().getFluidState(blockpos$mutableblockpos); - if (fluidstate.is(p_204032_)) { @@ -374,13 +461,13 @@ } - vec3 = vec3.add(vec31); -- k1++; +- ++k1; + interim.flowVector = interim.flowVector.add(vec31); + interim.blockCount++; } } } -@@ -3153,27 +_,30 @@ +@@ -3119,27 +_,30 @@ } } @@ -400,7 +487,7 @@ } Vec3 vec32 = this.getDeltaMovement(); -- vec3 = vec3.scale(p_204033_); +- vec3 = vec3.scale(p_204033_ * 1.0); + interim.flowVector = interim.flowVector.scale(this.getFluidMotionScale(fluidType)); double d2 = 0.003; - if (Math.abs(vec32.x) < 0.003 && Math.abs(vec32.z) < 0.003 && vec3.length() < 0.0045000000000000005) { @@ -421,7 +508,7 @@ } } -@@ -3186,7 +_,10 @@ +@@ -3152,7 +_,10 @@ return !this.level().hasChunksAt(i, k, j, l); } @@ -432,7 +519,7 @@ return this.fluidHeight.getDouble(p_204037_); } -@@ -3323,6 +_,7 @@ +@@ -3289,6 +_,7 @@ this.levelCallback.onMove(); } @@ -440,13 +527,50 @@ } public void checkDespawn() { -@@ -3450,6 +_,117 @@ +@@ -3360,10 +_,27 @@ + return false; + } + ++ /** ++ * Gets the value of the legacy {@link #maxUpStep} field. Only used by players when the modified value causes issues. ++ * @deprecated Use {@link net.neoforged.neoforge.common.extensions.IEntityExtension#getStepHeight()} to get the real step height value. ++ */ ++ @Deprecated + public float maxUpStep() { + return this.maxUpStep; + } + ++ /** ++ * Changes the legacy {@link #maxUpStep} field. Only used by vanilla entities to improve maintainability. ++ *

++ * For your own entities, you should change the default value of {@linkplain net.neoforged.neoforge.common.NeoForgeMod#STEP_HEIGHT NeoForgeMod#STEP_HEIGHT} ++ * during attribute creation. ++ *

++ * For modifying the step height of other entities, you should use {@link net.minecraft.world.entity.ai.attributes.AttributeModifier AttributeModifiers} for ++ * {@link net.neoforged.neoforge.common.NeoForgeMod#STEP_HEIGHT NeoForgeMod#STEP_HEIGHT}. ++ * ++ * @deprecated Use attribute modifiers for the {@link net.neoforged.neoforge.common.NeoForgeMod#STEP_HEIGHT NeoForgeMod#STEP_HEIGHT} attribute. ++ */ ++ @Deprecated + public void setMaxUpStep(float p_275672_) { + this.maxUpStep = p_275672_; + } +@@ -3419,6 +_,126 @@ public boolean mayInteract(Level p_146843_, BlockPos p_146844_) { return true; } + + /* ================================== Forge Start =====================================*/ + ++ private boolean canUpdate = true; ++ @Override ++ public void canUpdate(boolean value) { ++ this.canUpdate = value; ++ } ++ @Override ++ public boolean canUpdate() { ++ return this.canUpdate; ++ } + @Nullable + private java.util.Collection captureDrops = null; + @Override @@ -470,7 +594,7 @@ + public boolean canTrample(BlockState state, BlockPos pos, float fallDistance) { + return level.random.nextFloat() < fallDistance - 0.5F + && this instanceof LivingEntity -+ && (this instanceof Player || net.neoforged.neoforge.event.EventHooks.canEntityGrief(level, this)) ++ && (this instanceof Player || net.neoforged.neoforge.event.EventHooks.getMobGriefingEvent(level, this)) + && this.getBbWidth() * this.getBbWidth() * this.getBbHeight() > 0.512F; + } + @@ -497,10 +621,10 @@ + + // no AT because of overrides + /** -+ * Accessor method for {@link #getEyeHeight(Pose)} ++ * Accessor method for {@link #getEyeHeight(Pose, EntityDimensions)} + */ -+ public float getEyeHeightAccess(Pose pose) { -+ return this.getEyeHeight(pose); ++ public float getEyeHeightAccess(Pose pose, EntityDimensions size) { ++ return this.getEyeHeight(pose, size); + } + + protected Object2DoubleMap forgeFluidTypeHeight = new Object2DoubleArrayMap<>(net.neoforged.neoforge.fluids.FluidType.SIZE.get()); diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index e99e001ebf..983d94db67 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -1,36 +1,55 @@ --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java -@@ -132,7 +_,7 @@ - import net.minecraft.world.scores.Scoreboard; +@@ -119,14 +_,16 @@ + import net.minecraft.world.scores.PlayerTeam; import org.slf4j.Logger; -public abstract class LivingEntity extends Entity implements Attackable { +public abstract class LivingEntity extends Entity implements Attackable, net.neoforged.neoforge.common.extensions.ILivingEntityExtension { private static final Logger LOGGER = LogUtils.getLogger(); private static final String TAG_ACTIVE_EFFECTS = "active_effects"; - private static final ResourceLocation SPEED_MODIFIER_POWDER_SNOW_ID = ResourceLocation.withDefaultNamespace("powder_snow"); -@@ -320,7 +_,9 @@ - .add(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE) - .add(Attributes.WATER_MOVEMENT_EFFICIENCY) - .add(Attributes.MOVEMENT_EFFICIENCY) -- .add(Attributes.ATTACK_KNOCKBACK); -+ .add(Attributes.ATTACK_KNOCKBACK) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.NAMETAG_DISTANCE); + private static final UUID SPEED_MODIFIER_SOUL_SPEED_UUID = UUID.fromString("87f46a96-686f-4796-b035-22e16ee9e038"); + private static final UUID SPEED_MODIFIER_POWDER_SNOW_UUID = UUID.fromString("1eaf83ff-7207-4596-b37a-d7a07b3ec4ce"); ++ private static final UUID SLOW_FALLING_ID = UUID.fromString("A5B6CF2A-2F7C-31EF-9022-7C3E7D5E6ABA"); + private static final AttributeModifier SPEED_MODIFIER_SPRINTING = new AttributeModifier( + UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D"), "Sprinting speed boost", 0.3F, AttributeModifier.Operation.MULTIPLY_TOTAL + ); ++ private static final AttributeModifier SLOW_FALLING = new AttributeModifier(SLOW_FALLING_ID, "Slow falling acceleration reduction", -0.07, AttributeModifier.Operation.ADDITION); // Add -0.07 to 0.08 so we get the vanilla default of 0.01 + public static final int HAND_SLOTS = 2; + public static final int ARMOR_SLOTS = 4; + public static final int EQUIPMENT_SLOT_OFFSET = 98; +@@ -229,6 +_,7 @@ + private float swimAmountO; + protected Brain brain; + private boolean skipDropExperience; ++ protected net.neoforged.neoforge.common.damagesource.DamageContainer damageContainer; + + protected LivingEntity(EntityType p_20966_, Level p_20967_) { + super(p_20966_, p_20967_); +@@ -284,7 +_,11 @@ + .add(Attributes.MOVEMENT_SPEED) + .add(Attributes.ARMOR) + .add(Attributes.ARMOR_TOUGHNESS) +- .add(Attributes.MAX_ABSORPTION); ++ .add(Attributes.MAX_ABSORPTION) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED.value()) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.NAMETAG_DISTANCE.value()) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.ENTITY_GRAVITY.value()) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.STEP_HEIGHT.value()); } @Override -@@ -348,7 +_,8 @@ - float f = (float)Mth.ceil((double)this.fallDistance - d7); - double d4 = Math.min((double)(0.2F + f / 15.0F), 2.5); - int i = (int)(150.0 * d4); -- ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_), d0, d1, d2, i, 0.0, 0.0, 0.0, 0.15F); -+ if (!p_20992_.addLandingEffects((ServerLevel) this.level(), p_20993_, p_20992_, this, i)) -+ ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_).setPos(p_20993_), d0, d1, d2, i, 0.0, 0.0, 0.0, 0.15F); - } +@@ -314,7 +_,8 @@ + float f = (float)Mth.ceil(this.fallDistance - 3.0F); + double d4 = Math.min((double)(0.2F + f / 15.0F), 2.5); + int i = (int)(150.0 * d4); +- ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_), d0, d1, d2, i, 0.0, 0.0, 0.0, 0.15F); ++ if (!p_20992_.addLandingEffects((ServerLevel) this.level(), p_20993_, p_20992_, this, i)) ++ ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_).setPos(p_20993_), d0, d1, d2, i, 0.0D, 0.0D, 0.0D, (double)0.15F); } -@@ -358,6 +_,7 @@ + super.checkFallDamage(p_20990_, p_20991_, p_20992_, p_20993_); +@@ -323,6 +_,7 @@ } } @@ -38,7 +57,7 @@ public final boolean canBreatheUnderwater() { return this.getType().is(EntityTypeTags.CAN_BREATHE_UNDER_WATER); } -@@ -403,6 +_,9 @@ +@@ -364,6 +_,9 @@ } } @@ -48,7 +67,7 @@ if (this.isEyeInFluid(FluidTags.WATER) && !this.level().getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) { boolean flag1 = !this.canBreatheUnderwater() -@@ -441,7 +_,7 @@ +@@ -402,7 +_,7 @@ } } @@ -57,28 +76,29 @@ this.extinguishFire(); } -@@ -772,7 +_,7 @@ - Holder holder = iterator.next(); - MobEffectInstance mobeffectinstance = this.activeEffects.get(holder); +@@ -776,7 +_,7 @@ + MobEffect mobeffect = iterator.next(); + MobEffectInstance mobeffectinstance = this.activeEffects.get(mobeffect); if (!mobeffectinstance.tick(this, () -> this.onEffectUpdated(mobeffectinstance, true, null))) { - if (!this.level().isClientSide) { + if (!this.level().isClientSide && !net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.living.MobEffectEvent.Expired(this, mobeffectinstance)).isCanceled()) { iterator.remove(); this.onEffectRemoved(mobeffectinstance); } -@@ -817,8 +_,9 @@ - List list = this.activeEffects - .values() - .stream() -- .filter(MobEffectInstance::isVisible) -- .map(MobEffectInstance::getParticleOptions) -+ .map(effect -> net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.living.EffectParticleModificationEvent(this, effect))) -+ .filter(net.neoforged.neoforge.event.entity.living.EffectParticleModificationEvent::isVisible) -+ .map(net.neoforged.neoforge.event.entity.living.EffectParticleModificationEvent::getParticleOptions) - .toList(); - this.entityData.set(DATA_EFFECT_PARTICLES, list); - this.entityData.set(DATA_EFFECT_AMBIENCE_ID, areAllEffectsAmbient(this.activeEffects.values())); -@@ -858,6 +_,7 @@ +@@ -834,8 +_,10 @@ + this.setInvisible(false); + } else { + Collection collection = this.activeEffects.values(); +- this.entityData.set(DATA_EFFECT_AMBIENCE_ID, areAllEffectsAmbient(collection)); +- this.entityData.set(DATA_EFFECT_COLOR_ID, PotionUtils.getColor(collection)); ++ net.neoforged.neoforge.event.entity.living.PotionColorCalculationEvent event = new net.neoforged.neoforge.event.entity.living.PotionColorCalculationEvent(this, PotionUtils.getColor(collection), areAllEffectsAmbient(collection), collection); ++ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(event); ++ this.entityData.set(DATA_EFFECT_AMBIENCE_ID, event.areParticlesHidden()); ++ this.entityData.set(DATA_EFFECT_COLOR_ID, event.getColor()); + this.setInvisible(this.hasEffect(MobEffects.INVISIBILITY)); + } + } +@@ -874,6 +_,7 @@ } } @@ -86,10 +106,10 @@ return d0; } -@@ -899,7 +_,9 @@ +@@ -916,7 +_,9 @@ boolean flag; - for (flag = false; iterator.hasNext(); flag = true) { + for(flag = false; iterator.hasNext(); flag = true) { - this.onEffectRemoved(iterator.next()); + MobEffectInstance effect = iterator.next(); + if(net.neoforged.neoforge.event.EventHooks.onEffectRemoved(this, effect, null)) continue; @@ -97,13 +117,7 @@ iterator.remove(); } -@@ -929,11 +_,12 @@ - } - - public boolean addEffect(MobEffectInstance p_147208_, @Nullable Entity p_147209_) { -- if (!this.canBeAffected(p_147208_)) { -+ if (!net.neoforged.neoforge.common.CommonHooks.canMobEffectBeApplied(this, p_147208_)) { - return false; +@@ -951,6 +_,7 @@ } else { MobEffectInstance mobeffectinstance = this.activeEffects.get(p_147208_.getEffect()); boolean flag = false; @@ -111,39 +125,25 @@ if (mobeffectinstance == null) { this.activeEffects.put(p_147208_.getEffect(), p_147208_); this.onEffectAdded(p_147208_, p_147209_); -@@ -949,6 +_,14 @@ - } +@@ -966,6 +_,9 @@ } -+ /** -+ * Neo: Override-Only. Call via {@link net.neoforged.neoforge.common.CommonHooks#canMobEffectBeApplied(LivingEntity, MobEffectInstance)} -+ * -+ * @param p_21197_ A mob effect instance -+ * @return If the mob effect instance can be applied to this entity -+ */ -+ @Deprecated -+ @org.jetbrains.annotations.ApiStatus.OverrideOnly public boolean canBeAffected(MobEffectInstance p_21197_) { - if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) { - return !p_21197_.is(MobEffects.INFESTED); -@@ -962,7 +_,7 @@ - } - - public void forceAddEffect(MobEffectInstance p_147216_, @Nullable Entity p_147217_) { -- if (this.canBeAffected(p_147216_)) { -+ if (net.neoforged.neoforge.common.CommonHooks.canMobEffectBeApplied(this, p_147216_)) { - MobEffectInstance mobeffectinstance = this.activeEffects.put(p_147216_.getEffect(), p_147216_); - if (mobeffectinstance == null) { - this.onEffectAdded(p_147216_, p_147217_); -@@ -983,6 +_,7 @@ - } - - public boolean removeEffect(Holder p_316570_) { -+ if (net.neoforged.neoforge.event.EventHooks.onEffectRemoved(this, p_316570_, null)) return false; - MobEffectInstance mobeffectinstance = this.removeEffectNoUpdate(p_316570_); ++ net.neoforged.neoforge.event.entity.living.MobEffectEvent.Applicable event = new net.neoforged.neoforge.event.entity.living.MobEffectEvent.Applicable(this, p_21197_); ++ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(event); ++ if (event.getResult() != net.neoforged.bus.api.Event.Result.DEFAULT) return event.getResult() == net.neoforged.bus.api.Event.Result.ALLOW; + if (this.getMobType() == MobType.UNDEAD) { + MobEffect mobeffect = p_21197_.getEffect(); + if (mobeffect == MobEffects.REGENERATION || mobeffect == MobEffects.POISON) { +@@ -997,6 +_,7 @@ + } + + public boolean removeEffect(MobEffect p_21196_) { ++ if (net.neoforged.neoforge.event.EventHooks.onEffectRemoved(this, p_21196_, null)) return false; + MobEffectInstance mobeffectinstance = this.removeEffectNoUpdate(p_21196_); if (mobeffectinstance != null) { this.onEffectRemoved(mobeffectinstance); -@@ -1061,6 +_,8 @@ +@@ -1071,6 +_,8 @@ } public void heal(float p_21116_) { @@ -152,28 +152,36 @@ float f = this.getHealth(); if (f > 0.0F) { this.setHealth(f + p_21116_); -@@ -1081,6 +_,7 @@ - - @Override - public boolean hurt(DamageSource p_21016_, float p_21017_) { -+ if (!net.neoforged.neoforge.common.CommonHooks.onLivingAttack(this, p_21016_, p_21017_)) return false; - if (this.isInvulnerableTo(p_21016_)) { +@@ -1100,18 +_,22 @@ + } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; - } else if (this.level().isClientSide) { -@@ -1099,14 +_,17 @@ + } else { ++ this.damageContainer = this.damageContainer == null ? new net.neoforged.neoforge.common.damagesource.DamageContainer(p_21016_, p_21017_) : this.damageContainer; ++ if (!net.neoforged.neoforge.common.CommonHooks.onEntityPreDamage(this, this.damageContainer)) return false; + if (this.isSleeping() && !this.level().isClientSide) { + this.stopSleeping(); + } + + this.noActionTime = 0; +- float f = p_21017_; ++ float f = p_21017_ = this.damageContainer.getNewDamage(); boolean flag = false; float f1 = 0.0F; - if (p_21017_ > 0.0F && this.isDamageSourceBlocked(p_21016_)) { +- if (p_21017_ > 0.0F && this.isDamageSourceBlocked(p_21016_)) { - this.hurtCurrentlyUsedShield(p_21017_); - f1 = p_21017_; - p_21017_ = 0.0F; -+ net.neoforged.neoforge.event.entity.living.ShieldBlockEvent ev = net.neoforged.neoforge.common.CommonHooks.onShieldBlock(this, p_21016_, p_21017_); ++ net.neoforged.neoforge.event.entity.living.DamageBlockEvent ev; ++ if (p_21017_ > 0.0F && (ev = this.damageContainer.setBlockedDamage(net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_)))).getBlocked()) { + if(!ev.isCanceled()) { -+ if(ev.shieldTakesDamage()) this.hurtCurrentlyUsedShield(p_21017_); ++ if(ev.shieldDamage() > 0) this.hurtCurrentlyUsedShield(ev.shieldDamage()); + f1 = ev.getBlockedDamage(); -+ p_21017_ -= ev.getBlockedDamage(); - if (!p_21016_.is(DamageTypeTags.IS_PROJECTILE) && p_21016_.getDirectEntity() instanceof LivingEntity livingentity) { - this.blockUsingShield(livingentity); ++ p_21017_ = ev.getDamageContainer().getNewDamage(); + if (!p_21016_.is(DamageTypeTags.IS_PROJECTILE)) { + Entity entity = p_21016_.getDirectEntity(); + if (entity instanceof LivingEntity livingentity) { +@@ -1119,7 +_,8 @@ + } } - flag = true; @@ -182,19 +190,28 @@ } if (p_21016_.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { -@@ -1147,9 +_,9 @@ - if (entity instanceof Player player1) { +@@ -1138,7 +_,7 @@ + flag1 = false; + } else { + this.lastHurt = p_21017_; +- this.invulnerableTime = 20; ++ this.invulnerableTime = this.damageContainer.getPostAttackInvulnerabilityTicks(); + this.actuallyHurt(p_21016_, p_21017_); + this.hurtDuration = 10; + this.hurtTime = this.hurtDuration; +@@ -1158,9 +_,9 @@ + if (entity1 instanceof Player player1) { this.lastHurtByPlayerTime = 100; this.lastHurtByPlayer = player1; -- } else if (entity instanceof Wolf wolf && wolf.isTame()) { -+ } else if (entity instanceof TamableAnimal tamableAnimal && tamableAnimal.isTame()) { +- } else if (entity1 instanceof Wolf wolf && wolf.isTame()) { ++ } else if (entity1 instanceof TamableAnimal tamableAnimal && tamableAnimal.isTame()) { this.lastHurtByPlayerTime = 100; -- if (wolf.getOwner() instanceof Player player) { -+ if (tamableAnimal.getOwner() instanceof Player player) { +- LivingEntity livingentity2 = wolf.getOwner(); ++ LivingEntity livingentity2 = tamableAnimal.getOwner(); + if (livingentity2 instanceof Player player) { this.lastHurtByPlayer = player; } else { - this.lastHurtByPlayer = null; -@@ -1212,7 +_,7 @@ +@@ -1217,14 +_,14 @@ if (this instanceof ServerPlayer) { CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer)this, p_21016_, f, p_21017_, flag); if (f1 > 0.0F && f1 < 3.4028235E37F) { @@ -203,16 +220,24 @@ } } -@@ -1240,7 +_,7 @@ + if (entity1 instanceof ServerPlayer) { + CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)entity1, this, p_21016_, f, p_21017_, flag); + } +- ++ this.damageContainer = null; + return flag2; + } + } +@@ -1245,7 +_,7 @@ - for (InteractionHand interactionhand : InteractionHand.values()) { + for(InteractionHand interactionhand : InteractionHand.values()) { ItemStack itemstack1 = this.getItemInHand(interactionhand); - if (itemstack1.is(Items.TOTEM_OF_UNDYING)) { + if (itemstack1.is(Items.TOTEM_OF_UNDYING) && net.neoforged.neoforge.common.CommonHooks.onLivingUseTotem(this, p_21263_, itemstack1, interactionhand)) { itemstack = itemstack1.copy(); itemstack1.shrink(1); break; -@@ -1249,13 +_,13 @@ +@@ -1254,13 +_,13 @@ if (itemstack != null) { if (this instanceof ServerPlayer serverplayer) { @@ -228,7 +253,7 @@ this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 900, 1)); this.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, 100, 1)); this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 800, 0)); -@@ -1326,6 +_,7 @@ +@@ -1328,6 +_,7 @@ } public void die(DamageSource p_21014_) { @@ -236,45 +261,53 @@ if (!this.isRemoved() && !this.dead) { Entity entity = p_21014_.getEntity(); LivingEntity livingentity = this.getKillCredit(); -@@ -1361,7 +_,7 @@ +@@ -1364,7 +_,7 @@ if (!this.level().isClientSide) { boolean flag = false; if (p_21269_ instanceof WitherBoss) { - if (this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (net.neoforged.neoforge.event.EventHooks.canEntityGrief(this.level(), p_21269_)) { ++ if (net.neoforged.neoforge.event.EventHooks.getMobGriefingEvent(this.level(), p_21269_)) { BlockPos blockpos = this.blockPosition(); BlockState blockstate = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level().getBlockState(blockpos).isAir() && blockstate.canSurvive(this.level(), blockpos)) { -@@ -1379,6 +_,7 @@ - } - - protected void dropAllDeathLoot(ServerLevel p_348524_, DamageSource p_21192_) { +@@ -1383,12 +_,9 @@ + + protected void dropAllDeathLoot(DamageSource p_21192_) { + Entity entity = p_21192_.getEntity(); +- int i; +- if (entity instanceof Player) { +- i = EnchantmentHelper.getMobLooting((LivingEntity)entity); +- } else { +- i = 0; +- } ++ ++ int i = net.neoforged.neoforge.common.CommonHooks.getLootingLevel(this, entity, p_21192_); + this.captureDrops(new java.util.ArrayList<>()); + boolean flag = this.lastHurtByPlayerTime > 0; - if (this.shouldDropLoot() && p_348524_.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { - this.dropFromLootTable(p_21192_, flag); -@@ -1387,6 +_,10 @@ + if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { +@@ -1398,6 +_,10 @@ this.dropEquipment(); - this.dropExperience(p_21192_.getEntity()); + this.dropExperience(); + + Collection drops = captureDrops(null); -+ if (!net.neoforged.neoforge.common.CommonHooks.onLivingDrops(this, p_21192_, drops, lastHurtByPlayerTime > 0)) ++ if (!net.neoforged.neoforge.common.CommonHooks.onLivingDrops(this, p_21192_, drops, i, lastHurtByPlayerTime > 0)) + drops.forEach(e -> level().addFreshEntity(e)); } protected void dropEquipment() { -@@ -1399,7 +_,8 @@ +@@ -1410,7 +_,8 @@ this.isAlwaysExperienceDropper() || this.lastHurtByPlayerTime > 0 && this.shouldDropExperience() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT) )) { -- ExperienceOrb.award(serverlevel, this.position(), this.getExperienceReward(serverlevel, p_345346_)); -+ int reward = net.neoforged.neoforge.event.EventHooks.getExperienceDrop(this, this.lastHurtByPlayer, this.getExperienceReward(serverlevel, p_345346_)); +- ExperienceOrb.award((ServerLevel)this.level(), this.position(), this.getExperienceReward()); ++ int reward = net.neoforged.neoforge.event.EventHooks.getExperienceDrop(this, this.lastHurtByPlayer, this.getExperienceReward()); + ExperienceOrb.award((ServerLevel) this.level(), this.position(), reward); } } -@@ -1440,6 +_,11 @@ +@@ -1444,6 +_,11 @@ } public void knockback(double p_147241_, double p_147242_, double p_147243_) { @@ -286,10 +319,10 @@ p_147241_ *= 1.0 - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); if (!(p_147241_ <= 0.0)) { this.hasImpulse = true; -@@ -1521,15 +_,9 @@ +@@ -1515,15 +_,9 @@ } else { BlockPos blockpos = this.blockPosition(); - BlockState blockstate = this.getInBlockState(); + BlockState blockstate = this.getFeetBlockState(); - if (blockstate.is(BlockTags.CLIMBABLE)) { - this.lastClimbablePos = Optional.of(blockpos); - return true; @@ -305,7 +338,7 @@ } } -@@ -1558,6 +_,11 @@ +@@ -1545,6 +_,11 @@ @Override public boolean causeFallDamage(float p_147187_, float p_147188_, DamageSource p_147189_) { @@ -317,7 +350,7 @@ boolean flag = super.causeFallDamage(p_147187_, p_147188_, p_147189_); int i = this.calculateFallDamage(p_147187_, p_147188_); if (i > 0) { -@@ -1585,9 +_,10 @@ +@@ -1572,9 +_,10 @@ int i = Mth.floor(this.getX()); int j = Mth.floor(this.getY() - 0.2F); int k = Mth.floor(this.getZ()); @@ -330,9 +363,11 @@ this.playSound(soundtype.getFallSound(), soundtype.getVolume() * 0.5F, soundtype.getPitch() * 0.75F); } } -@@ -1649,9 +_,9 @@ +@@ -1620,10 +_,11 @@ + p_21194_ = Math.max(f / 25.0F, 0.0F); float f2 = f1 - p_21194_; if (f2 > 0.0F && f2 < 3.4028235E37F) { ++ this.damageContainer.setMobEffectReduction(f2); if (this instanceof ServerPlayer) { - ((ServerPlayer)this).awardStat(Stats.DAMAGE_RESISTED, Math.round(f2 * 10.0F)); + ((ServerPlayer)this).awardStat(Stats.CUSTOM.get(Stats.DAMAGE_RESISTED), Math.round(f2 * 10.0F)); @@ -342,24 +377,48 @@ } } } -@@ -1679,6 +_,8 @@ +@@ -1636,20 +_,23 @@ + int k = EnchantmentHelper.getDamageProtection(this.getArmorSlots(), p_21193_); + if (k > 0) { + p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, (float)k); ++ this.damageContainer.setEnchantReduction(this.damageContainer.getNewDamage() - p_21194_); + } +- + return p_21194_; + } + } + } protected void actuallyHurt(DamageSource p_21240_, float p_21241_) { - if (!this.isInvulnerableTo(p_21240_)) { -+ p_21241_ = net.neoforged.neoforge.common.CommonHooks.onLivingHurt(this, p_21240_, p_21241_); -+ if (p_21241_ <= 0) return; - p_21241_ = this.getDamageAfterArmorAbsorb(p_21240_, p_21241_); - p_21241_ = this.getDamageAfterMagicAbsorb(p_21240_, p_21241_); - float f1 = Math.max(p_21241_ - this.getAbsorptionAmount(), 0.0F); -@@ -1688,6 +_,7 @@ - serverplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f * 10.0F)); +- if (!this.isInvulnerableTo(p_21240_)) { +- p_21241_ = this.getDamageAfterArmorAbsorb(p_21240_, p_21241_); +- p_21241_ = this.getDamageAfterMagicAbsorb(p_21240_, p_21241_); +- float f1 = Math.max(p_21241_ - this.getAbsorptionAmount(), 0.0F); +- this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_21241_ - f1)); +- float f = p_21241_ - f1; ++ net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ if (this.damageContainer.getNewDamage() <= 0) return; ++ this.damageContainer.setArmorReduction(this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainer.getNewDamage()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.getAbsorptionAmount(), 0.0F); ++ this.damageContainer.setAbsorption(f1); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); ++ this.setAbsorptionAmount(this.getAbsorptionAmount() - (this.damageContainer.getNewDamage() - f1)); ++ float f = this.damageContainer.getNewDamage() - f1; + if (f > 0.0F && f < 3.4028235E37F) { + Entity entity = p_21240_.getEntity(); + if (entity instanceof ServerPlayer serverplayer) { +@@ -1662,8 +_,8 @@ + this.setHealth(this.getHealth() - f1); + this.setAbsorptionAmount(this.getAbsorptionAmount() - f1); + this.gameEvent(GameEvent.ENTITY_DAMAGE); ++ this.onDamageTaken(this.damageContainer); } +- } + } -+ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamage(this, p_21240_, f1); - if (f1 != 0.0F) { - this.getCombatTracker().recordDamage(p_21240_, f1); - this.setHealth(this.getHealth() - f1); -@@ -1747,6 +_,8 @@ + public CombatTracker getCombatTracker() { +@@ -1716,6 +_,8 @@ } public void swing(InteractionHand p_21012_, boolean p_21013_) { @@ -368,7 +427,7 @@ if (!this.swinging || this.swingTime >= this.getCurrentSwingDuration() / 2 || this.swingTime < 0) { this.swingTime = -1; this.swinging = true; -@@ -1859,8 +_,10 @@ +@@ -1825,8 +_,10 @@ private void swapHandItems() { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.OFFHAND); @@ -381,12 +440,11 @@ } @Override -@@ -2064,15 +_,18 @@ - } - - this.hasImpulse = true; -+ net.neoforged.neoforge.common.CommonHooks.onLivingJump(this); +@@ -2018,14 +_,17 @@ } + + this.hasImpulse = true; ++ net.neoforged.neoforge.common.CommonHooks.onLivingJump(this); } + @Deprecated // FORGE: use sinkInFluid instead @@ -398,12 +456,23 @@ + @Deprecated // FORGE: use jumpInFluid instead protected void jumpInLiquid(TagKey p_204043_) { - this.setDeltaMovement(this.getDeltaMovement().add(0.0, 0.04F, 0.0)); -+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, (double)0.04F * this.getAttributeValue(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED), 0.0D)); ++ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, (double)0.04F * this.getAttribute(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED.value()).getValue(), 0.0D)); } protected float getWaterSlowDown() { -@@ -2097,7 +_,8 @@ +@@ -2039,13 +_,18 @@ + public void travel(Vec3 p_21280_) { + if (this.isControlledByLocalInstance()) { + double d0 = 0.08; ++ AttributeInstance gravity = this.getAttribute(net.neoforged.neoforge.common.NeoForgeMod.ENTITY_GRAVITY.value()); + boolean flag = this.getDeltaMovement().y <= 0.0; + if (flag && this.hasEffect(MobEffects.SLOW_FALLING)) { +- d0 = 0.01; ++ if (!gravity.hasModifier(SLOW_FALLING)) gravity.addTransientModifier(SLOW_FALLING); ++ } else if (gravity.hasModifier(SLOW_FALLING)) { ++ gravity.removeModifier(SLOW_FALLING_ID); } ++ d0 = gravity.getValue(); FluidState fluidstate = this.level().getFluidState(this.blockPosition()); - if (this.isInWater() && this.isAffectedByFluids() && !this.canStandOnFluid(fluidstate)) { @@ -412,15 +481,15 @@ double d9 = this.getY(); float f4 = this.isSprinting() ? 0.9F : this.getWaterSlowDown(); float f5 = 0.02F; -@@ -2115,6 +_,7 @@ +@@ -2067,6 +_,7 @@ f4 = 0.96F; } -+ f5 *= (float)this.getAttributeValue(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED); ++ f5 *= (float)this.getAttribute(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED.value()).getValue(); this.moveRelative(f5, p_21280_); this.move(MoverType.SELF, this.getDeltaMovement()); Vec3 vec36 = this.getDeltaMovement(); -@@ -2128,6 +_,7 @@ +@@ -2080,6 +_,7 @@ if (this.horizontalCollision && this.isFree(vec32.x, vec32.y + 0.6F - this.getY() + d9, vec32.z)) { this.setDeltaMovement(vec32.x, 0.3F, vec32.z); } @@ -428,7 +497,7 @@ } else if (this.isInLava() && this.isAffectedByFluids() && !this.canStandOnFluid(fluidstate)) { double d8 = this.getY(); this.moveRelative(0.02F, p_21280_); -@@ -2190,7 +_,7 @@ +@@ -2142,7 +_,7 @@ } } else { BlockPos blockpos = this.getBlockPosBelowThatAffectsMyMovement(); @@ -437,24 +506,32 @@ float f3 = this.onGround() ? f2 * 0.91F : 0.91F; Vec3 vec35 = this.handleRelativeFrictionAndCalculateMovement(p_21280_, f2); double d2 = vec35.y; -@@ -2284,7 +_,7 @@ +@@ -2238,7 +_,7 @@ double d0 = Mth.clamp(p_21298_.x, -0.15F, 0.15F); double d1 = Mth.clamp(p_21298_.z, -0.15F, 0.15F); double d2 = Math.max(p_21298_.y, -0.15F); -- if (d2 < 0.0 && !this.getInBlockState().is(Blocks.SCAFFOLDING) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { -+ if (d2 < 0.0D && !this.getInBlockState().isScaffolding(this) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { +- if (d2 < 0.0 && !this.getFeetBlockState().is(Blocks.SCAFFOLDING) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { ++ if (d2 < 0.0D && !this.getFeetBlockState().isScaffolding(this) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { d2 = 0.0; } -@@ -2466,6 +_,7 @@ - }; +@@ -2271,6 +_,7 @@ + + @Override + public void tick() { ++ if (net.neoforged.neoforge.common.CommonHooks.onLivingTick(this)) return; + super.tick(); + this.updatingUsingItem(); + this.updateSwimAmount(); +@@ -2422,6 +_,7 @@ + ItemStack itemstack1 = this.getItemBySlot(equipmentslot); if (this.equipmentHasChanged(itemstack, itemstack1)) { + net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.living.LivingEquipmentChangeEvent(this, equipmentslot, itemstack, itemstack1)); if (map == null) { map = Maps.newEnumMap(EquipmentSlot.class); } -@@ -2637,6 +_,9 @@ +@@ -2566,6 +_,9 @@ this.level().getProfiler().push("jump"); if (this.jumping && this.isAffectedByFluids()) { double d3; @@ -464,7 +541,7 @@ if (this.isInLava()) { d3 = this.getFluidHeight(FluidTags.LAVA); } else { -@@ -2647,15 +_,17 @@ +@@ -2576,15 +_,17 @@ double d4 = this.getFluidJumpThreshold(); if (!flag || this.onGround() && !(d3 > d4)) { if (!this.isInLava() || this.onGround() && !(d3 > d4)) { @@ -484,16 +561,16 @@ } } else { this.noJumpDelay = 0; -@@ -2720,6 +_,8 @@ +@@ -2650,6 +_,8 @@ boolean flag = this.getSharedFlag(7); if (flag && !this.onGround() && !this.isPassenger() && !this.hasEffect(MobEffects.LEVITATION)) { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.CHEST); + flag = itemstack.canElytraFly(this) && itemstack.elytraFlightTick(this, this.fallFlyTicks); -+ if (false) //Neo: Moved to ElytraItem ++ if (false) //Forge: Moved to ElytraItem if (itemstack.is(Items.ELYTRA) && ElytraItem.isFlyEnabled(itemstack)) { flag = true; int i = this.fallFlyTicks + 1; -@@ -2979,8 +_,11 @@ +@@ -2910,8 +_,11 @@ private void updatingUsingItem() { if (this.isUsingItem()) { @@ -507,12 +584,12 @@ this.updateUsingItem(this.useItem); } else { this.stopUsingItem(); -@@ -2989,12 +_,15 @@ +@@ -2920,19 +_,22 @@ } protected void updateUsingItem(ItemStack p_147201_) { + if (!p_147201_.isEmpty()) -+ this.useItemRemaining = net.neoforged.neoforge.event.EventHooks.onItemUseTick(this, p_147201_, this.getUseItemRemainingTicks()); ++ this.useItemRemaining = net.neoforged.neoforge.event.EventHooks.onItemUseTick(this, p_147201_, this.getUseItemRemainingTicks()); + if (this.getUseItemRemainingTicks() > 0) p_147201_.onUseTick(this.level(), this, this.getUseItemRemainingTicks()); if (this.shouldTriggerItemUseEffects()) { @@ -524,19 +601,27 @@ this.completeUsingItem(); } } -@@ -3029,8 +_,10 @@ + + private boolean shouldTriggerItemUseEffects() { + int i = this.getUseItemRemainingTicks(); +- FoodProperties foodproperties = this.useItem.getItem().getFoodProperties(); ++ FoodProperties foodproperties = this.useItem.getFoodProperties(this); + boolean flag = foodproperties != null && foodproperties.isFastFood(); + flag |= i <= this.useItem.getUseDuration() - 7; + return flag && i % 4 == 0; +@@ -2961,8 +_,10 @@ public void startUsingItem(InteractionHand p_21159_) { ItemStack itemstack = this.getItemInHand(p_21159_); if (!itemstack.isEmpty() && !this.isUsingItem()) { -+ int duration = net.neoforged.neoforge.event.EventHooks.onItemUseStart(this, itemstack, itemstack.getUseDuration(this)); ++ int duration = net.neoforged.neoforge.event.EventHooks.onItemUseStart(this, itemstack, itemstack.getUseDuration()); + if (duration < 0) return; // Neo: Early return for negative values, as that indicates event cancellation. this.useItem = itemstack; -- this.useItemRemaining = itemstack.getUseDuration(this); +- this.useItemRemaining = itemstack.getUseDuration(); + this.useItemRemaining = duration; if (!this.level().isClientSide) { this.setLivingEntityFlag(1, true); this.setLivingEntityFlag(2, p_21159_ == InteractionHand.OFF_HAND); -@@ -3111,7 +_,8 @@ +@@ -3038,7 +_,8 @@ } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { this.triggerItemUseEffects(this.useItem, 16); @@ -546,7 +631,7 @@ if (itemstack != this.useItem) { this.setItemInHand(interactionhand, itemstack); } -@@ -3136,7 +_,11 @@ +@@ -3063,7 +_,11 @@ public void releaseUsingItem() { if (!this.useItem.isEmpty()) { @@ -558,7 +643,7 @@ if (this.useItem.useOnRelease()) { this.updatingUsingItem(); } -@@ -3146,6 +_,7 @@ +@@ -3073,6 +_,7 @@ } public void stopUsingItem() { @@ -566,16 +651,16 @@ if (!this.level().isClientSide) { boolean flag = this.isUsingItem(); this.setLivingEntityFlag(1, false); -@@ -3161,7 +_,7 @@ +@@ -3088,7 +_,7 @@ public boolean isBlocking() { if (this.isUsingItem() && !this.useItem.isEmpty()) { Item item = this.useItem.getItem(); -- return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem, this) - this.useItemRemaining >= 5; -+ return !this.useItem.canPerformAction(net.neoforged.neoforge.common.ToolActions.SHIELD_BLOCK) ? false : item.getUseDuration(this.useItem, this) - this.useItemRemaining >= 5; - } else { - return false; - } -@@ -3302,8 +_,8 @@ +- if (item.getUseAnimation(this.useItem) != UseAnim.BLOCK) { ++ if (!this.useItem.canPerformAction(net.neoforged.neoforge.common.ToolActions.SHIELD_BLOCK)) { + return false; + } else { + return item.getUseDuration(this.useItem) - this.useItemRemaining >= 5; +@@ -3229,8 +_,8 @@ } BlockState blockstate = this.level().getBlockState(p_21141_); @@ -586,14 +671,14 @@ } this.setPose(Pose.SLEEPING); -@@ -3318,15 +_,17 @@ +@@ -3245,15 +_,17 @@ } private boolean checkBedExists() { -- return this.getSleepingPos().map(p_352707_ -> this.level().getBlockState(p_352707_).getBlock() instanceof BedBlock).orElse(false); -+ // Neo: Overwrite the vanilla instanceof BedBlock check with isBed and fire the CanContinueSleepingEvent. -+ boolean hasBed = this.getSleepingPos().map(pos -> this.level().getBlockState(pos).isBed(this.level(), pos, this)).orElse(false); -+ return net.neoforged.neoforge.event.EventHooks.canEntityContinueSleeping(this, hasBed ? null : Player.BedSleepingProblem.NOT_POSSIBLE_HERE); +- return this.getSleepingPos().map(p_311581_ -> this.level().getBlockState(p_311581_).getBlock() instanceof BedBlock).orElse(false); ++ return this.getSleepingPos().map((p_289310_) -> { ++ return net.neoforged.neoforge.event.EventHooks.fireSleepingLocationCheck(this, p_289310_); ++ }).orElse(false); } public void stopSleeping() { @@ -607,7 +692,7 @@ Vec3 vec31 = BedBlock.findStandUpPosition(this.getType(), this.level(), p_261435_, direction, this.getYRot()).orElseGet(() -> { BlockPos blockpos = p_261435_.above(); return new Vec3((double)blockpos.getX() + 0.5, (double)blockpos.getY() + 0.1, (double)blockpos.getZ() + 0.5); -@@ -3347,7 +_,9 @@ +@@ -3274,7 +_,9 @@ @Nullable public Direction getBedOrientation() { BlockPos blockpos = this.getSleepingPos().orElse(null); @@ -618,7 +703,7 @@ } @Override -@@ -3356,11 +_,11 @@ +@@ -3292,7 +_,7 @@ } public ItemStack getProjectile(ItemStack p_21272_) { @@ -626,14 +711,18 @@ + return net.neoforged.neoforge.common.CommonHooks.getProjectile(this, p_21272_, ItemStack.EMPTY); } - public final ItemStack eat(Level p_21067_, ItemStack p_21068_) { -- FoodProperties foodproperties = p_21068_.get(DataComponents.FOOD); -+ FoodProperties foodproperties = p_21068_.getFoodProperties(this); - return foodproperties != null ? this.eat(p_21067_, p_21068_, foodproperties) : p_21068_; - } - -@@ -3411,6 +_,39 @@ - return p_320526_ == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND; + public ItemStack eat(Level p_21067_, ItemStack p_21068_) { +@@ -3321,7 +_,7 @@ + private void addEatEffect(ItemStack p_21064_, Level p_21065_, LivingEntity p_21066_) { + Item item = p_21064_.getItem(); + if (item.isEdible()) { +- for(Pair pair : item.getFoodProperties().getEffects()) { ++ for(Pair pair : p_21064_.getFoodProperties(this).getEffects()) { + if (!p_21065_.isClientSide && pair.getFirst() != null && p_21065_.random.nextFloat() < pair.getSecond()) { + p_21066_.addEffect(new MobEffectInstance(pair.getFirst())); + } +@@ -3356,6 +_,39 @@ + this.broadcastBreakEvent(p_21191_ == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND); } + /* ==== FORGE START ==== */ @@ -672,21 +761,28 @@ @Override public AABB getBoundingBoxForCulling() { if (this.getItemBySlot(EquipmentSlot.HEAD).is(Items.DRAGON_HEAD)) { -@@ -3422,6 +_,8 @@ +@@ -3367,6 +_,8 @@ } - public EquipmentSlot getEquipmentSlotForItem(ItemStack p_147234_) { + public static EquipmentSlot getEquipmentSlotForItem(ItemStack p_147234_) { + final EquipmentSlot slot = p_147234_.getEquipmentSlot(); + if (slot != null) return slot; // FORGE: Allow modders to set a non-default equipment slot for a stack; e.g. a non-armor chestplate-slot item Equipable equipable = Equipable.get(p_147234_); - if (equipable != null) { - EquipmentSlot equipmentslot = equipable.getEquipmentSlot(); -@@ -3507,7 +_,7 @@ + return equipable != null ? equipable.getEquipmentSlot() : EquipmentSlot.MAINHAND; + } +@@ -3442,9 +_,14 @@ } public boolean canDisableShield() { -- return this.getWeaponItem().getItem() instanceof AxeItem; +- return this.getMainHandItem().getItem() instanceof AxeItem; + return this.getMainHandItem().canDisableShield(this.useItem, this, this); } ++ /** ++ * Gets the value of the legacy {@link #maxUpStep} field. ++ * @deprecated Use {@link #getStepHeight()} to get the real step height value. ++ */ ++ @Deprecated @Override + public float maxUpStep() { + float f = super.maxUpStep(); diff --git a/patches/net/minecraft/world/entity/player/Inventory.java.patch b/patches/net/minecraft/world/entity/player/Inventory.java.patch index 661a168207..918da5ae93 100644 --- a/patches/net/minecraft/world/entity/player/Inventory.java.patch +++ b/patches/net/minecraft/world/entity/player/Inventory.java.patch @@ -35,3 +35,18 @@ crashreportcategory.setDetail("Item ID", Item.getId(p_36042_.getItem())); crashreportcategory.setDetail("Item data", p_36042_.getDamageValue()); crashreportcategory.setDetail("Item name", () -> p_36042_.getHoverName().getString()); +@@ -497,12 +_,12 @@ + if (p_150074_ < 1.0F) { + p_150074_ = 1.0F; + } +- ++ net.neoforged.neoforge.common.CommonHooks.onArmorHurt(p_150073_, this.armor, p_150074_, this.player); p_150075_ = new int[0]; + for(int i : p_150075_) { + ItemStack itemstack = this.armor.get(i); + if ((!p_150073_.is(DamageTypeTags.IS_FIRE) || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { + itemstack.hurtAndBreak( +- (int)p_150074_, this.player, p_35997_ -> p_35997_.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, i)) ++ (int)p_150074_, this.player, p_35997_ -> p_35997_.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, i)) + ); + } + } diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index a50d0b3dbe..a39d3b4d9d 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -113,7 +_,8 @@ +@@ -112,7 +_,8 @@ import net.minecraft.world.scores.Team; import org.slf4j.Logger; @@ -8,54 +8,57 @@ +public abstract class Player extends LivingEntity implements net.neoforged.neoforge.common.extensions.IPlayerExtension { + public static final String PERSISTED_NBT_TAG = "PlayerPersisted"; private static final Logger LOGGER = LogUtils.getLogger(); + public static final int MAX_NAME_LENGTH = 16; public static final HumanoidArm DEFAULT_MAIN_HAND = HumanoidArm.RIGHT; - public static final int DEFAULT_MODEL_CUSTOMIZATION = 0; -@@ -193,6 +_,9 @@ - public Entity currentExplosionCause; - private boolean ignoreFallDamageFromCurrentImpulse; - private int currentImpulseContextResetGraceTime; +@@ -174,6 +_,9 @@ + @Nullable + public FishingHook fishing; + protected float hurtDir; + private final java.util.Collection prefixes = new java.util.LinkedList<>(); + private final java.util.Collection suffixes = new java.util.LinkedList<>(); + @Nullable private Pose forcedPose; public Player(Level p_250508_, BlockPos p_250289_, float p_251702_, GameProfile p_252153_) { super(EntityType.PLAYER, p_250508_); -@@ -229,7 +_,8 @@ - .add(Attributes.SUBMERGED_MINING_SPEED) - .add(Attributes.SNEAKING_SPEED) - .add(Attributes.MINING_EFFICIENCY) -- .add(Attributes.SWEEPING_DAMAGE_RATIO); -+ .add(Attributes.SWEEPING_DAMAGE_RATIO) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.CREATIVE_FLIGHT); +@@ -206,7 +_,11 @@ + .add(Attributes.ATTACK_DAMAGE, 1.0) + .add(Attributes.MOVEMENT_SPEED, 0.1F) + .add(Attributes.ATTACK_SPEED) +- .add(Attributes.LUCK); ++ .add(Attributes.LUCK) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.BLOCK_REACH.value()) ++ .add(Attributes.ATTACK_KNOCKBACK) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.ENTITY_REACH.value()) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.CREATIVE_FLIGHT.value()); } @Override -@@ -245,6 +_,7 @@ +@@ -222,6 +_,7 @@ @Override public void tick() { -+ net.neoforged.neoforge.event.EventHooks.firePlayerTickPre(this); ++ net.neoforged.neoforge.event.EventHooks.onPlayerPreTick(this); this.noPhysics = this.isSpectator(); if (this.isSpectator()) { this.setOnGround(false); -@@ -260,7 +_,7 @@ +@@ -237,7 +_,7 @@ this.sleepCounter = 100; } - if (!this.level().isClientSide && this.level().isDay()) { -+ if (!this.level().isClientSide && !net.neoforged.neoforge.event.EventHooks.canEntityContinueSleeping(this, this.level().isDay() ? BedSleepingProblem.NOT_POSSIBLE_NOW : null)) { ++ if (!this.level().isClientSide && !net.neoforged.neoforge.event.EventHooks.fireSleepingTimeCheck(this, getSleepingPos())) { this.stopSleepInBed(false, true); } } else if (this.sleepCounter > 0) { -@@ -318,6 +_,7 @@ - if (this.currentImpulseContextResetGraceTime > 0) { - this.currentImpulseContextResetGraceTime--; - } -+ net.neoforged.neoforge.event.EventHooks.firePlayerTickPost(this); +@@ -292,6 +_,7 @@ + this.turtleHelmetTick(); + this.cooldowns.tick(); + this.updatePlayerPose(); ++ net.neoforged.neoforge.event.EventHooks.onPlayerPostTick(this); } @Override -@@ -397,6 +_,10 @@ +@@ -371,6 +_,10 @@ } protected void updatePlayerPose() { @@ -66,15 +69,15 @@ if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) { Pose pose; if (this.isFallFlying()) { -@@ -630,6 +_,7 @@ +@@ -613,6 +_,7 @@ @Override public void die(DamageSource p_36152_) { + if (net.neoforged.neoforge.common.CommonHooks.onLivingDeath(this, p_36152_)) return; super.die(p_36152_); this.reapplyPosition(); - if (!this.isSpectator() && this.level() instanceof ServerLevel serverlevel) { -@@ -684,7 +_,7 @@ + if (!this.isSpectator()) { +@@ -667,7 +_,7 @@ @Nullable public ItemEntity drop(ItemStack p_36177_, boolean p_36178_) { @@ -83,7 +86,7 @@ } @Nullable -@@ -726,7 +_,12 @@ +@@ -709,7 +_,12 @@ } } @@ -95,8 +98,8 @@ + public float getDigSpeed(BlockState p_36282_, @Nullable BlockPos pos) { float f = this.inventory.getDestroySpeed(p_36282_); if (f > 1.0F) { - f += (float)this.getAttributeValue(Attributes.MINING_EFFICIENCY); -@@ -754,13 +_,19 @@ + int i = EnchantmentHelper.getBlockEfficiency(this); +@@ -740,11 +_,12 @@ f /= 5.0F; } @@ -104,38 +107,39 @@ return f; } -+ @Deprecated // Neo: use position sensitive version below public boolean hasCorrectToolForDrops(BlockState p_36299_) { - return !p_36299_.requiresCorrectToolForDrops() || this.inventory.getSelected().isCorrectToolForDrops(p_36299_); +- return !p_36299_.requiresCorrectToolForDrops() || this.inventory.getSelected().isCorrectToolForDrops(p_36299_); ++ return net.neoforged.neoforge.event.EventHooks.doPlayerHarvestCheck(this, p_36299_, !p_36299_.requiresCorrectToolForDrops() || this.inventory.getSelected().isCorrectToolForDrops(p_36299_)); } -+ public boolean hasCorrectToolForDrops(BlockState state, Level level, BlockPos pos) { -+ return net.neoforged.neoforge.event.EventHooks.doPlayerHarvestCheck(this, state, level, pos); -+ } -+ @Override - public void readAdditionalSaveData(CompoundTag p_36215_) { - super.readAdditionalSaveData(p_36215_); -@@ -859,6 +_,7 @@ - - @Override - public boolean hurt(DamageSource p_36154_, float p_36155_) { -+ if (!net.neoforged.neoforge.common.CommonHooks.onPlayerAttack(this, p_36154_, p_36155_)) return false; - if (this.isInvulnerableTo(p_36154_)) { - return false; - } else if (this.abilities.invulnerable && !p_36154_.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { -@@ -872,7 +_,9 @@ +@@ -840,11 +_,13 @@ + if (this.isDeadOrDying()) { + return false; + } else { ++ this.damageContainer = new net.neoforged.neoforge.common.damagesource.DamageContainer(p_36154_, p_36155_); ++ if (!net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer)) return false; + if (!this.level().isClientSide) { this.removeEntitiesOnShoulder(); } - +- - if (p_36154_.scalesWithDifficulty()) { -+ p_36155_ = Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, p_36155_, this.level().getDifficulty())); -+ ++ this.damageContainer.setNewDamage(Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, this.damageContainer.getNewDamage(), this.level().getDifficulty()))); + if (false && p_36154_.scalesWithDifficulty()) { if (this.level().getDifficulty() == Difficulty.PEACEFUL) { p_36155_ = 0.0F; } -@@ -926,7 +_,7 @@ +@@ -857,8 +_,7 @@ + p_36155_ = p_36155_ * 3.0F / 2.0F; + } + } +- +- return p_36155_ == 0.0F ? false : super.hurt(p_36154_, p_36155_); ++ if (this.damageContainer.getNewDamage() == 0.0F) {this.damageContainer = null; return false;} else return super.hurt(p_36154_, this.damageContainer.getNewDamage()); + } + } + } +@@ -898,7 +_,7 @@ @Override protected void hurtCurrentlyUsedShield(float p_36383_) { @@ -144,36 +148,69 @@ if (!this.level().isClientSide) { this.awardStat(Stats.ITEM_USED.get(this.useItem.getItem())); } -@@ -934,7 +_,13 @@ +@@ -906,7 +_,11 @@ if (p_36383_ >= 3.0F) { int i = 1 + Mth.floor(p_36383_); InteractionHand interactionhand = this.getUsedItemHand(); -- this.useItem.hurtAndBreak(i, this, getSlotForHand(interactionhand)); -+ if (this.level() instanceof ServerLevel serverlevel && !hasInfiniteMaterials()) { -+ this.useItem.hurtAndBreak(i, serverlevel, this, item -> { -+ this.onEquippedItemBroken(item, getSlotForHand(interactionhand)); -+ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, this.useItem, interactionhand); -+ stopUsingItem(); // Neo: Fix MC-168573 ("After breaking a shield, the player's off-hand can't finish using some items") -+ }); -+ } +- this.useItem.hurtAndBreak(i, this, p_219739_ -> p_219739_.broadcastBreakEvent(interactionhand)); ++ this.useItem.hurtAndBreak(i, this, p_219739_ -> { ++ p_219739_.broadcastBreakEvent(interactionhand); ++ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, this.useItem, interactionhand); ++ stopUsingItem(); // Neo: Fix MC-168573 ("After breaking a shield, the player's off-hand can't finish using some items") ++ }); if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -@@ -952,10 +_,13 @@ +@@ -923,26 +_,28 @@ + @Override protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { - if (!this.isInvulnerableTo(p_36312_)) { -+ p_36313_ = net.neoforged.neoforge.common.CommonHooks.onLivingHurt(this, p_36312_, p_36313_); -+ if (p_36313_ <= 0) return; - p_36313_ = this.getDamageAfterArmorAbsorb(p_36312_, p_36313_); - p_36313_ = this.getDamageAfterMagicAbsorb(p_36312_, p_36313_); - float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamage(this, p_36312_, f1); - float f = p_36313_ - f1; - if (f > 0.0F && f < 3.4028235E37F) { - this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); -@@ -1014,6 +_,8 @@ +- if (!this.isInvulnerableTo(p_36312_)) { +- p_36313_ = this.getDamageAfterArmorAbsorb(p_36312_, p_36313_); +- p_36313_ = this.getDamageAfterMagicAbsorb(p_36312_, p_36313_); +- float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); +- this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); +- float f = p_36313_ - f1; +- if (f > 0.0F && f < 3.4028235E37F) { +- this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); +- } +- +- if (f1 != 0.0F) { +- this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); +- this.getCombatTracker().recordDamage(p_36312_, f1); +- this.setHealth(this.getHealth() - f1); +- if (f1 < 3.4028235E37F) { +- this.awardStat(Stats.DAMAGE_TAKEN, Math.round(f1 * 10.0F)); +- } +- +- this.gameEvent(GameEvent.ENTITY_DAMAGE); +- } ++ net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ if (this.damageContainer.getNewDamage() <= 0) return; ++ this.damageContainer.setArmorReduction(this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.getAbsorptionAmount(), 0.0F); ++ this.damageContainer.setAbsorption(f1); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); ++ this.setAbsorptionAmount(this.getAbsorptionAmount() - (this.damageContainer.getNewDamage() - f1)); ++ float f = this.damageContainer.getNewDamage() - f1; ++ if (f > 0.0F && f < 3.4028235E37F) { ++ this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); ++ } ++ ++ if (f1 != 0.0F) { ++ this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); ++ this.getCombatTracker().recordDamage(p_36312_, f1); ++ this.setHealth(this.getHealth() - f1); ++ if (f1 < 3.4028235E37F) { ++ this.awardStat(Stats.DAMAGE_TAKEN, Math.round(f1 * 10.0F)); ++ } ++ ++ this.gameEvent(GameEvent.ENTITY_DAMAGE); + } + } + +@@ -991,6 +_,8 @@ return InteractionResult.PASS; } else { @@ -182,7 +219,7 @@ ItemStack itemstack = this.getItemInHand(p_36159_); ItemStack itemstack1 = itemstack.copy(); InteractionResult interactionresult = p_36158_.interact(this, p_36159_); -@@ -1022,6 +_,9 @@ +@@ -999,6 +_,9 @@ itemstack.setCount(itemstack1.getCount()); } @@ -192,7 +229,7 @@ return interactionresult; } else { if (!itemstack.isEmpty() && p_36158_ instanceof LivingEntity) { -@@ -1033,6 +_,7 @@ +@@ -1010,6 +_,7 @@ if (interactionresult1.consumesAction()) { this.level().gameEvent(GameEvent.ENTITY_INTERACT, p_36158_.position(), GameEvent.Context.of(this)); if (itemstack.isEmpty() && !this.abilities.instabuild) { @@ -200,80 +237,83 @@ this.setItemInHand(p_36159_, ItemStack.EMPTY); } -@@ -1062,6 +_,7 @@ +@@ -1044,6 +_,7 @@ } @Override + // Forge: Don't update this method to use IForgeEntity#getStepHeight() - https://github.com/MinecraftForge/MinecraftForge/issues/8922 protected Vec3 maybeBackOffFromEdge(Vec3 p_36201_, MoverType p_36202_) { - float f = this.maxUpStep(); if (!this.abilities.flying -@@ -1111,6 +_,7 @@ - } + && p_36201_.y <= 0.0 +@@ -1098,6 +_,7 @@ + return p_36201_; } + // Forge: Don't update this method to use IForgeEntity#getStepHeight() - https://github.com/MinecraftForge/MinecraftForge/issues/9376 - private boolean isAboveGround(float p_341626_) { - return this.onGround() || this.fallDistance < p_341626_ && !this.canFallAtLeast(0.0, 0.0, p_341626_ - this.fallDistance); - } -@@ -1132,6 +_,7 @@ + private boolean isAboveGround() { + return this.onGround() + || this.fallDistance < this.maxUpStep() +@@ -1105,6 +_,7 @@ } public void attack(Entity p_36347_) { + if (!net.neoforged.neoforge.common.CommonHooks.onPlayerAttackTarget(this, p_36347_)) return; if (p_36347_.isAttackable()) { if (!p_36347_.skipAttackInteraction(this)) { - float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE); -@@ -1141,7 +_,6 @@ + float f = (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE); +@@ -1118,11 +_,10 @@ float f2 = this.getAttackStrengthScale(0.5F); f *= 0.2F + f2 * f2 * 0.8F; f1 *= f2; - this.resetAttackStrengthTicker(); - if (p_36347_.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) - && p_36347_ instanceof Projectile projectile - && projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true)) { -@@ -1170,8 +_,12 @@ + if (f > 0.0F || f1 > 0.0F) { + boolean flag = f2 > 0.9F; + boolean flag1 = false; +- int i = 0; ++ float i = (float)this.getAttributeValue(Attributes.ATTACK_KNOCKBACK); // Forge: Initialize this value to the attack knockback attribute of the player, which is by default 0 + i += EnchantmentHelper.getKnockbackBonus(this); + if (this.isSprinting() && flag) { + this.level() +@@ -1140,8 +_,10 @@ && !this.isPassenger() - && p_36347_ instanceof LivingEntity - && !this.isSprinting(); -+ // Neo: Fire the critical hit event and override the critical hit status and damage multiplier based on the event. -+ // The boolean local above (flag2) is the vanilla critical hit result. -+ var critEvent = net.neoforged.neoforge.common.CommonHooks.fireCriticalHit(this, p_36347_, flag1, flag1 ? 1.5F : 1.0F); -+ flag1 = critEvent.isCriticalHit(); - if (flag1) { + && p_36347_ instanceof LivingEntity; + flag2 = flag2 && !this.isSprinting(); ++ net.neoforged.neoforge.event.entity.player.CriticalHitEvent hitResult = net.neoforged.neoforge.common.CommonHooks.getCriticalHit(this, p_36347_, flag2, flag2 ? 1.5F : 1.0F); ++ flag2 = hitResult != null; + if (flag2) { - f *= 1.5F; -+ f *= critEvent.getDamageMultiplier(); ++ f *= hitResult.getDamageModifier(); } - float f3 = f + f1; -@@ -1179,9 +_,7 @@ + f += f1; +@@ -1149,9 +_,7 @@ double d0 = (double)(this.walkDist - this.walkDistO); - if (flag4 && !flag1 && !flag && this.onGround() && d0 < (double)this.getSpeed()) { - ItemStack itemstack1 = this.getItemInHand(InteractionHand.MAIN_HAND); -- if (itemstack1.getItem() instanceof SwordItem) { -- flag2 = true; + if (flag && !flag2 && !flag1 && this.onGround() && d0 < (double)this.getSpeed()) { + ItemStack itemstack = this.getItemInHand(InteractionHand.MAIN_HAND); +- if (itemstack.getItem() instanceof SwordItem) { +- flag3 = true; - } -+ flag2 = itemstack1.canPerformAction(net.neoforged.neoforge.common.ToolActions.SWORD_SWEEP); ++ flag3 = itemstack.canPerformAction(net.neoforged.neoforge.common.ToolActions.SWORD_SWEEP); } - float f6 = 0.0F; -@@ -1217,11 +_,12 @@ + float f4 = 0.0F; +@@ -1193,11 +_,12 @@ - for (LivingEntity livingentity2 : this.level() + for(LivingEntity livingentity : this.level() .getEntitiesOfClass(LivingEntity.class, p_36347_.getBoundingBox().inflate(1.0, 0.25, 1.0))) { -+ double entityReachSq = Mth.square(this.entityInteractionRange()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. - if (livingentity2 != this - && livingentity2 != p_36347_ - && !this.isAlliedTo(livingentity2) - && (!(livingentity2 instanceof ArmorStand) || !((ArmorStand)livingentity2).isMarker()) -- && this.distanceToSqr(livingentity2) < 9.0) { -+ && this.distanceToSqr(livingentity2) < entityReachSq) { - float f5 = this.getEnchantedDamage(livingentity2, f7, damagesource) * f2; - livingentity2.knockback( ++ double entityReachSq = Mth.square(this.getEntityReach()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. + if (livingentity != this + && livingentity != p_36347_ + && !this.isAlliedTo(livingentity) + && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).isMarker()) +- && this.distanceToSqr(livingentity) < 9.0) { ++ && this.distanceToSqr(livingentity) < entityReachSq) { + livingentity.knockback( 0.4F, -@@ -1268,11 +_,12 @@ - - this.setLastHurtMob(p_36347_); + (double)Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), +@@ -1246,13 +_,15 @@ + EnchantmentHelper.doPostDamageEffects(this, p_36347_); + ItemStack itemstack1 = this.getMainHandItem(); Entity entity = p_36347_; - if (p_36347_ instanceof EnderDragonPart) { - entity = ((EnderDragonPart)p_36347_).parentMob; @@ -281,37 +321,32 @@ + entity = ((net.neoforged.neoforge.entity.PartEntity) p_36347_).getParent(); } - boolean flag5 = false; -+ ItemStack copy = itemstack.copy(); - if (this.level() instanceof ServerLevel serverlevel1) { - if (entity instanceof LivingEntity livingentity3) { - flag5 = itemstack.hurtEnemy(livingentity3, this); -@@ -1287,6 +_,7 @@ + if (!this.level().isClientSide && !itemstack1.isEmpty() && entity instanceof LivingEntity) { ++ ItemStack copy = itemstack1.copy(); + itemstack1.hurtEnemy((LivingEntity)entity, this); + if (itemstack1.isEmpty()) { ++ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, copy, InteractionHand.MAIN_HAND); + this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); } - - if (itemstack.isEmpty()) { -+ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, copy, itemstack == this.getMainHandItem() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); - if (itemstack == this.getMainHandItem()) { - this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); - } else { -@@ -1311,6 +_,7 @@ - .playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F); + } +@@ -1280,6 +_,7 @@ + } } } + this.resetAttackStrengthTicker(); // FORGE: Moved from beginning of attack() so that getAttackStrengthScale() returns an accurate value during all attack events } } } -@@ -1325,7 +_,7 @@ - } +@@ -1296,7 +_,7 @@ + } - public void disableShield() { -- this.getCooldowns().addCooldown(Items.SHIELD, 100); -+ this.getCooldowns().addCooldown(this.getUseItem().getItem(), 100); - this.stopUsingItem(); - this.level().broadcastEntityEvent(this, (byte)30); - } -@@ -1391,6 +_,7 @@ + if (this.random.nextFloat() < f) { +- this.getCooldowns().addCooldown(Items.SHIELD, 100); ++ this.getCooldowns().addCooldown(this.getUseItem().getItem(), 100); + this.stopUsingItem(); + this.level().broadcastEntityEvent(this, (byte)30); + } +@@ -1358,6 +_,7 @@ } public void stopSleepInBed(boolean p_36226_, boolean p_36227_) { @@ -319,7 +354,16 @@ super.stopSleeping(); if (this.level() instanceof ServerLevel && p_36227_) { ((ServerLevel)this.level()).updateSleepingPlayerList(); -@@ -1503,7 +_,8 @@ +@@ -1390,7 +_,7 @@ + } else if (block instanceof BedBlock && BedBlock.canSetSpawn(p_36131_)) { + return BedBlock.findStandUpPosition(EntityType.PLAYER, p_36131_, p_36132_, blockstate.getValue(BedBlock.FACING), p_36133_); + } else if (!p_36134_) { +- return Optional.empty(); ++ return blockstate.getRespawnPosition(EntityType.PLAYER, p_36131_, p_36132_, p_36133_, null); + } else { + boolean flag = block.isPossibleToRespawnInThis(blockstate); + BlockState blockstate1 = p_36131_.getBlockState(p_36132_.above()); +@@ -1500,7 +_,8 @@ @Override public boolean causeFallDamage(float p_150093_, float p_150094_, DamageSource p_150095_) { @@ -329,7 +373,7 @@ return false; } else { if (p_150093_ >= 2.0F) { -@@ -1535,7 +_,7 @@ +@@ -1514,7 +_,7 @@ public boolean tryToStartFallFlying() { if (!this.onGround() && !this.isFallFlying() && !this.isInWater() && !this.hasEffect(MobEffects.LEVITATION)) { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.CHEST); @@ -338,7 +382,7 @@ this.startFallFlying(); return true; } -@@ -1564,13 +_,13 @@ +@@ -1543,13 +_,13 @@ protected void playStepSound(BlockPos p_282121_, BlockState p_282194_) { if (this.isInWater()) { this.waterSwimSound(); @@ -354,7 +398,7 @@ } else { super.playStepSound(blockpos, blockstate); } -@@ -1601,6 +_,10 @@ +@@ -1578,6 +_,10 @@ } public void giveExperiencePoints(int p_36291_) { @@ -363,9 +407,9 @@ + p_36291_ = event.getAmount(); + this.increaseScore(p_36291_); - this.experienceProgress = this.experienceProgress + (float)p_36291_ / (float)this.getXpNeededForNextLevel(); + this.experienceProgress += (float)p_36291_ / (float)this.getXpNeededForNextLevel(); this.totalExperience = Mth.clamp(this.totalExperience + p_36291_, 0, Integer.MAX_VALUE); -@@ -1628,7 +_,7 @@ +@@ -1605,7 +_,7 @@ } public void onEnchantmentPerformed(ItemStack p_36172_, int p_36173_) { @@ -374,7 +418,7 @@ if (this.experienceLevel < 0) { this.experienceLevel = 0; this.experienceProgress = 0.0F; -@@ -1639,6 +_,10 @@ +@@ -1616,6 +_,10 @@ } public void giveExperienceLevels(int p_36276_) { @@ -385,7 +429,7 @@ this.experienceLevel += p_36276_; if (this.experienceLevel < 0) { this.experienceLevel = 0; -@@ -1847,7 +_,11 @@ +@@ -1819,7 +_,11 @@ @Override public Component getDisplayName() { @@ -398,7 +442,7 @@ return this.decorateDisplayNameComponent(mutablecomponent); } -@@ -2012,18 +_,18 @@ +@@ -1966,25 +_,25 @@ Predicate predicate = ((ProjectileWeaponItem)p_36349_.getItem()).getSupportedHeldProjectiles(); ItemStack itemstack = ProjectileWeaponItem.getHeldProjectile(this, predicate); if (!itemstack.isEmpty()) { @@ -407,7 +451,7 @@ } else { predicate = ((ProjectileWeaponItem)p_36349_.getItem()).getAllSupportedProjectiles(); - for (int i = 0; i < this.inventory.getContainerSize(); i++) { + for(int i = 0; i < this.inventory.getContainerSize(); ++i) { ItemStack itemstack1 = this.inventory.getItem(i); if (predicate.test(itemstack1)) { - return itemstack1; @@ -420,7 +464,15 @@ } } } -@@ -2201,5 +_,39 @@ + + @Override + public ItemStack eat(Level p_36185_, ItemStack p_36186_) { +- this.getFoodData().eat(p_36186_.getItem(), p_36186_); ++ this.getFoodData().eat(p_36186_.getItem(), p_36186_, this); + this.awardStat(Stats.ITEM_USED.get(p_36186_.getItem())); + p_36185_.playSound( + null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, p_36185_.random.nextFloat() * 0.1F + 0.9F +@@ -2108,5 +_,39 @@ public Component getMessage() { return this.message; } diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index d59c272a0e..97e4d4e433 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -48,6 +49,7 @@ import net.minecraft.core.SectionPos; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.NonNullList; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; @@ -70,6 +72,8 @@ import net.minecraft.server.packs.PackType; import net.minecraft.stats.Stats; import net.minecraft.tags.BlockTags; +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.tags.TagEntry; import net.minecraft.tags.TagKey; import net.minecraft.util.CrudeIncrementalIntIdentityHashBiMap; import net.minecraft.util.Mth; @@ -95,12 +99,14 @@ import net.minecraft.world.entity.ai.village.poi.PoiManager; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.monster.EnderMan; +import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AnvilMenu; import net.minecraft.world.inventory.ClickAction; import net.minecraft.world.inventory.ContainerLevelAccess; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.AdventureModePredicate; +import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.EnchantedBookItem; @@ -148,6 +154,7 @@ import net.neoforged.fml.loading.FMLEnvironment; import net.neoforged.neoforge.client.ClientHooks; import net.neoforged.neoforge.common.conditions.ConditionalOps; +import net.neoforged.neoforge.common.damagesource.DamageContainer; import net.neoforged.neoforge.common.extensions.IEntityExtension; import net.neoforged.neoforge.common.loot.IGlobalLootModifier; import net.neoforged.neoforge.common.loot.LootModifierManager; @@ -167,25 +174,27 @@ import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent; import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; import net.neoforged.neoforge.event.entity.EntityEvent; +import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; import net.neoforged.neoforge.event.entity.EntityTravelToDimensionEvent; import net.neoforged.neoforge.event.entity.item.ItemTossEvent; +import net.neoforged.neoforge.event.entity.living.ArmorHurtEvent; +import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; +import net.neoforged.neoforge.event.entity.living.DamageTakenEvent; import net.neoforged.neoforge.event.entity.living.EnderManAngerEvent; -import net.neoforged.neoforge.event.entity.living.LivingAttackEvent; +import net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent; +import net.neoforged.neoforge.event.entity.living.IncomingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingBreatheEvent; import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent; -import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingDeathEvent; import net.neoforged.neoforge.event.entity.living.LivingDropsEvent; import net.neoforged.neoforge.event.entity.living.LivingDrownEvent; import net.neoforged.neoforge.event.entity.living.LivingEvent; import net.neoforged.neoforge.event.entity.living.LivingFallEvent; import net.neoforged.neoforge.event.entity.living.LivingGetProjectileEvent; -import net.neoforged.neoforge.event.entity.living.LivingHurtEvent; import net.neoforged.neoforge.event.entity.living.LivingKnockBackEvent; import net.neoforged.neoforge.event.entity.living.LivingSwapItemsEvent; import net.neoforged.neoforge.event.entity.living.LivingUseTotemEvent; -import net.neoforged.neoforge.event.entity.living.MobEffectEvent; -import net.neoforged.neoforge.event.entity.living.ShieldBlockEvent; +import net.neoforged.neoforge.event.entity.living.LootingLevelEvent; import net.neoforged.neoforge.event.entity.player.AnvilRepairEvent; import net.neoforged.neoforge.event.entity.player.AttackEntityEvent; import net.neoforged.neoforge.event.entity.player.CriticalHitEvent; @@ -238,12 +247,20 @@ public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, return event; } - public static boolean onLivingAttack(LivingEntity entity, DamageSource src, float amount) { - return entity instanceof Player || !NeoForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount)).isCanceled(); + public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource source, boolean isInvul) { + return NeoForge.EVENT_BUS.post(new EntityInvulnerablityCheckEvent(entity, source, isInvul)).isInvulnerable(); } - public static boolean onPlayerAttack(LivingEntity entity, DamageSource src, float amount) { - return !NeoForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount)).isCanceled(); + public static boolean onLivingTick(LivingEntity entity) { + return NeoForge.EVENT_BUS.post(new LivingEvent.LivingTickEvent(entity)).isCanceled(); + } + + public static boolean onEntityPreDamage(LivingEntity entity, DamageContainer container) { + return entity instanceof Player || !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); + } + + public static boolean onPlayerEntityPreDamage(LivingEntity entity, DamageContainer container) { + return !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); } public static LivingKnockBackEvent onLivingKnockBack(LivingEntity target, float strength, double ratioX, double ratioZ) { @@ -256,14 +273,33 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS return !NeoForge.EVENT_BUS.post(new LivingUseTotemEvent(entity, damageSource, totem, hand)).isCanceled(); } - public static float onLivingHurt(LivingEntity entity, DamageSource src, float amount) { - LivingHurtEvent event = new LivingHurtEvent(entity, src, amount); - return (NeoForge.EVENT_BUS.post(event).isCanceled() ? 0 : event.getAmount()); + public static void onIncomingDamage(LivingEntity entity, DamageContainer container) { + NeoForge.EVENT_BUS.post(new IncomingDamageEvent(entity, container)); + } + + public static void onLivingDamageTaken(LivingEntity entity, DamageContainer container) { + NeoForge.EVENT_BUS.post(new DamageTakenEvent(entity, container)); } - public static float onLivingDamage(LivingEntity entity, DamageSource src, float amount) { - LivingDamageEvent event = new LivingDamageEvent(entity, src, amount); - return (NeoForge.EVENT_BUS.post(event).isCanceled() ? 0 : event.getAmount()); + public static void onArmorHurt(DamageSource source, NonNullList armor, float damage, Player player) { + EnumMap armorMap = new EnumMap<>(EquipmentSlot.class); + EnumMap damageMap = new EnumMap<>(EquipmentSlot.class); + for (int index : Inventory.ALL_ARMOR_SLOTS) { + ItemStack armorPiece = armor.get(index); + if (armorPiece.isEmpty()) continue; + EquipmentSlot slot = EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index); + armorMap.put(slot, armor.get(index)); + damageMap.put(slot, damage); + } + + ArmorHurtEvent event = NeoForge.EVENT_BUS.post(new ArmorHurtEvent(armorMap, damageMap, player)); + if (event.isCanceled()) return; + event.getArmorMap().forEach((slot, armorPiece) -> { + if ((!source.is(DamageTypeTags.IS_FIRE) || !armorPiece.getItem().isFireResistant()) && armorPiece.getItem() instanceof ArmorItem) { + Float finalDamage = event.isCanceled() ? event.getOriginalDamage(slot) : event.getNewDamage(slot); + armorPiece.hurtAndBreak(finalDamage.intValue(), player, p_35997_ -> p_35997_.broadcastBreakEvent(slot)); + } + }); } public static boolean onLivingDeath(LivingEntity entity, DamageSource src) { @@ -1001,8 +1037,8 @@ public static void onEntityEnterSection(Entity entity, long packedOldPos, long p NeoForge.EVENT_BUS.post(new EntityEvent.EnteringSection(entity, packedOldPos, packedNewPos)); } - public static ShieldBlockEvent onShieldBlock(LivingEntity blocker, DamageSource source, float blocked) { - ShieldBlockEvent e = new ShieldBlockEvent(blocker, source, blocked); + public static DamageBlockEvent onDamageBlock(LivingEntity blocker, DamageContainer container, boolean originalBlocked) { + DamageBlockEvent e = new DamageBlockEvent(blocker, container, originalBlocked); NeoForge.EVENT_BUS.post(e); return e; } diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java new file mode 100644 index 0000000000..23c730bf10 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.common.damagesource; + +import net.minecraft.world.damagesource.DamageSource; +import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; + +/** + * DamageContainer encapsulates aspects of the entity damage sequence so that + * all context related to damage dealt is accessible throughout the entire + * sequence. + *

Note: certain values will be defaults until the stage in the sequence when they are set.

+ *
    + *
  • {@link #originalDamage} stores a reference to the raw damage value passed to the defender from the attacker.
  • + *
  • {@link #newDamage} represents the event-modified damage to be applied throughout the sequence.
  • + *
  • {@link #source} an immutable reference to the damage source
  • + *
  • {@link #armorReduction} the amount reduced by armor.
  • + *
  • {@link #absorption} the amount of absorption consumed by the damage sequence.
  • + *
  • {@link #enchantReduction} the amount of damage reduced by enchantments
  • + *
  • {@link #mobEffectReduction} the amount of damage reduced by mob effects
  • + *
  • {@link #invulnerabilityTicksAfterAttack} defaults to 20. Changes how long an entity is invulnerable after this damage sequence. + * This can be modified at any point.
  • + *
  • {@link #blockedDamage} The amount of damage blocked by the shield. This value is set by {@link DamageBlockEvent} and cannot + * be directly modified. {@link #getBlockedDamage()} can be used to obtain the value after the event is fired.
  • + *
  • {@link #shieldDamage} How much damage the shield item will take.
  • + *

+ */ +public class DamageContainer { + private final float originalDamage; + private final DamageSource source; + private float newDamage; + private float armorReduction = 0f; + private float absorption = 0f; + private float enchantReduction = 0f; + private float mobEffectReduction = 0f; + private float blockedDamage = 0; + private float shieldDamage = 0; + private int invulnerabilityTicksAfterAttack = 20; + + public DamageContainer(DamageSource source, float originalDamage) { + this.source = source; + this.originalDamage = originalDamage; + this.newDamage = originalDamage; + } + + public float getOriginalDamage() { + return originalDamage; + } + + public DamageSource getSource() { + return source; + } + + public DamageBlockEvent setBlockedDamage(DamageBlockEvent event) { + this.blockedDamage = event.getBlockedDamage(); + this.shieldDamage = event.shieldDamage(); + return event; + } + + public float getBlockedDamage() { + return blockedDamage; + } + + public float getShieldDamage() { + return shieldDamage; + } + + public void setPostAttackInvulnerabilityTicks(int ticks) { + this.invulnerabilityTicksAfterAttack = ticks; + } + + public int getPostAttackInvulnerabilityTicks() { + return invulnerabilityTicksAfterAttack; + } + + public void setArmorReduction(float reduction) { + this.armorReduction = reduction; + } + + public float getArmorReduction() { + return armorReduction; + } + + public void setEnchantReduction(float reduction) { + this.enchantReduction = reduction; + } + + public float getEnchantReduction() { + return enchantReduction; + } + + public void setMobEffectReduction(float reduction) { + this.mobEffectReduction = reduction; + } + + public float getMobEffectReduction() { + return mobEffectReduction; + } + + public void setAbsorption(float absorption) { + this.absorption = absorption; + } + + public float getAbsorption() { + return absorption; + } + + public void setNewDamage(float damage) { + this.newDamage = damage; + } + + public float getNewDamage() { + return newDamage; + } +} diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/ILivingEntityExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/ILivingEntityExtension.java index 3c071ad62c..2d03a767b5 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/ILivingEntityExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/ILivingEntityExtension.java @@ -5,10 +5,12 @@ package net.neoforged.neoforge.common.extensions; +import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.common.NeoForgeMod; +import net.neoforged.neoforge.common.damagesource.DamageContainer; import net.neoforged.neoforge.fluids.FluidType; public interface ILivingEntityExtension extends IEntityExtension { @@ -64,4 +66,15 @@ default boolean canDrownInFluidType(FluidType type) { default boolean moveInFluid(FluidState state, Vec3 movementVector, double gravity) { return state.move(self(), movementVector, gravity); } + + /** + * Executes in {@link LivingEntity#hurt(DamageSource, float)} after all damage and + * effects have applied. Overriding this method is preferred over overriding the + * hurt method in custom entities where special behavior is desired after vanilla + * logic. + * + * @param damageContainer The aggregated damage details preceding this hook, which + * includes changes made to the damage sequence by events. + */ + default void onDamageTaken(DamageContainer damageContainer) {} } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java new file mode 100644 index 0000000000..f38c38bf05 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.event.entity; + +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.ApiStatus; + +/** + * Fired when {@link Entity#hurt(DamageSource, float)} is invoked and determines if + * downstream hurt logic should apply. This event is fired in {@link Entity#isInvulnerableTo(DamageSource)} + *

+ * This event cannot be cancelled. + *

+ * This event does not have a result. + *

+ * This event is fired on the {@link NeoForge#EVENT_BUS}. + */ +public class EntityInvulnerablityCheckEvent extends EntityEvent { + private final boolean originallyInvulnerable; + private boolean isInvulnerable; + private final DamageSource source; + + @ApiStatus.Internal + public EntityInvulnerablityCheckEvent(Entity entity, DamageSource source, boolean isVanillaInvulnerable) { + super(entity); + this.originallyInvulnerable = isVanillaInvulnerable; + this.isInvulnerable = isVanillaInvulnerable; + this.source = source; + } + + /** + * Sets the invulnerable status of the entity. By default, the invulnerability will be + * set by value passed into the event invocation. + */ + public void setInvulnerable(boolean isInvulnerable) { + this.isInvulnerable = isInvulnerable; + } + + /** @return the current invulnerability state */ + public boolean isInvulnerable() { + return isInvulnerable; + } + + /** @return an immutable reference to the damage source being applied to this entity */ + public DamageSource getSource() { + return source; + } + + /** @return the invulnerability status passed into the event by vanilla */ + public boolean getOriginalInvulnerability() { + return originallyInvulnerable; + } +} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java new file mode 100644 index 0000000000..609a513614 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.event.entity.living; + +import java.util.Map; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; + +/** + * Fired when a {@link Player}'s armor is dealt damage in {@link Player#actuallyHurt(DamageSource, float) actuallyHurt}. + *

+ * This event is {@link ICancellableEvent cancelable}. Cancelling this event will ignore all damage modifications + * and result in the original damage being applied to the armor item. + *

+ * This event does not have a result. + *

+ * This event is fired on the {@link NeoForge#EVENT_BUS} + */ +public class ArmorHurtEvent extends PlayerEvent implements ICancellableEvent { + private final Map armorItemStack; + private final Map originalDamage; + private final Map damage; + + @ApiStatus.Internal + public ArmorHurtEvent(Map armorItemStack, Map damage, Player player) { + super(player); + this.armorItemStack = armorItemStack; + this.originalDamage = damage; + this.damage = damage; + } + + /** + * Provides the Itemstack for the given slot. Hand slots will always return {@link ItemStack#EMPTY} + * + * @return the {@link ItemStack} to be hurt for the given slot + */ + public ItemStack getArmorItemStack(EquipmentSlot slot) { + return armorItemStack.getOrDefault(slot, ItemStack.EMPTY); + } + + /** {@return the original damage before any event modifications} */ + public Float getOriginalDamage(EquipmentSlot slot) { + return originalDamage.getOrDefault(slot, 0f); + } + + /** {@return the amount to hurt the armor if the event is not cancelled} */ + public Float getNewDamage(EquipmentSlot slot) { + return damage.getOrDefault(slot, 0f); + } + + /** + * Sets new damage for the armor. Setting damage for empty slots will have no effect. + * + * @param damage the new amount to hurt the armor. Values below zero will be set to zero. + */ + public void setNewDamage(EquipmentSlot slot, float damage) { + if (this.damage.containsKey(slot)) this.damage.put(slot, Math.max(damage, 0)); + } + + /** Used internally to get the full map of {@link ItemStack}s to be hurt */ + public Map getArmorMap() { + return armorItemStack; + } +} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java new file mode 100644 index 0000000000..de11e66c4d --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.event.entity.living; + +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.neoforge.common.damagesource.DamageContainer; + +/** + * The ShieldBlockEvent is fired when an entity successfully blocks with a shield.
+ * Cancelling this event will have the same impact as if the shield was not eligible to block.
+ * The damage blocked cannot be set lower than zero or greater than the original value.
+ * Note: The shield item stack "should" be available from {@link LivingEntity#getUseItem()} + * at least for players. + */ +public class DamageBlockEvent extends DamageSequenceEvent implements ICancellableEvent { + private float dmgBlocked; + private float shieldDamage = 0; + private final boolean originalBlocked; + private boolean newBlocked; + + public DamageBlockEvent(LivingEntity blocker, DamageContainer container, boolean originalBlockedState) { + super(blocker, container); + this.dmgBlocked = container.getOriginalDamage(); + this.originalBlocked = originalBlockedState; + this.newBlocked = originalBlockedState; + } + + /** + * @return The damage source. + */ + public DamageSource getDamageSource() { + return this.getDamageContainer().getSource(); + } + + /** + * @return The original amount of damage blocked, which is the same as the original + * incoming damage value. + */ + public float getOriginalBlockedDamage() { + return this.getDamageContainer().getOriginalDamage(); + } + + /** + * @return The current amount of damage blocked, as a result of this event. + */ + public float getBlockedDamage() { + return this.dmgBlocked; + } + + /** + * Controls if {@link LivingEntity#hurtCurrentlyUsedShield} is called. + * + * @return If the shield item will take durability damage or not. + */ + public float shieldDamage() { + return this.shieldDamage; + } + + /** + * Set how much damage is blocked by this action.
+ * Note that initially the blocked amount is the entire attack.
+ */ + public void setBlockedDamage(float blocked) { + this.dmgBlocked = Mth.clamp(blocked, 0, this.getOriginalBlockedDamage()); + } + + /** + * Set if the shield will take durability damage or not. + */ + public void setShieldTakesDamage(float damage) { + this.shieldDamage = damage; + } + + /** + * @return whether the damage would have been blocked by vanilla logic + */ + public boolean getOriginalBlock() { + return originalBlocked; + } + + /** + * Used in {@link LivingEntity#hurt(DamageSource, float)} to signify that a blocking + * action has occurred. If returning false, damage to the shield will not occur. + * + * @return true if the entity should be considered "blocking" + */ + public boolean getBlocked() { + return newBlocked; + } + + /** + * Sets the blocking state of the entity. By default, entities raising a shield, + * facing the damage source, and not being hit by a source that bypasses shields + * will be considered blocking. An entity can be considered blocking regardless + * by supplying true to this. + * + * @param isBlocked should the entity be treated as if it is blocking + */ + public void setBlocked(boolean isBlocked) { + this.newBlocked = isBlocked; + } +} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java new file mode 100644 index 0000000000..ffd46956ce --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.event.entity.living; + +import net.minecraft.world.entity.LivingEntity; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.neoforge.common.damagesource.DamageContainer; + +/** + * DamageSequenceEvent is not, and should not be, directly invoked. Instead, + * implementations of this class should be used to allow simple discrimination + * of where in the damage sequence the {@link DamageContainer} is. + *
+ * {@link #container} can be accessed to modify or obtain values from the damage + * sequence. Note that depending on where in the damage sequence a child event + * is invoked, modification of a value may have no effect. Read the documentation + * on the child event of your listener for more detail. + *
+ * This event is not {@link ICancellableEvent} by default. Implementation classes + * can implement this interface if their corresponding hooks effectively terminate + * the damage sequence. + */ +public abstract class DamageSequenceEvent extends LivingEvent { + final DamageContainer container; + + public DamageSequenceEvent(LivingEntity entity, DamageContainer container) { + super(entity); + this.container = container; + } + + public DamageContainer getDamageContainer() { + return container; + } +} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java similarity index 71% rename from src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java rename to src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java index 91b3a98486..f18889c21b 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java @@ -9,6 +9,7 @@ import net.minecraft.world.entity.LivingEntity; import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.CommonHooks; +import net.neoforged.neoforge.common.damagesource.DamageContainer; /** * LivingDamageEvent is fired just before damage is applied to entity.
@@ -28,27 +29,10 @@ *
* This event does not have a result. {@link HasResult}
* - * @see LivingHurtEvent + * @see IncomingDamageEvent **/ -public class LivingDamageEvent extends LivingEvent implements ICancellableEvent { - private final DamageSource source; - private float amount; - - public LivingDamageEvent(LivingEntity entity, DamageSource source, float amount) { - super(entity); - this.source = source; - this.amount = amount; - } - - public DamageSource getSource() { - return source; - } - - public float getAmount() { - return amount; - } - - public void setAmount(float amount) { - this.amount = amount; +public class DamageTakenEvent extends DamageSequenceEvent { + public DamageTakenEvent(LivingEntity entity, DamageContainer container) { + super(entity, container); } } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingAttackEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java similarity index 78% rename from src/main/java/net/neoforged/neoforge/event/entity/living/LivingAttackEvent.java rename to src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java index 7ab20fe52b..ab430365bc 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingAttackEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java @@ -11,6 +11,7 @@ import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.CommonHooks; import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.common.damagesource.DamageContainer; /** * LivingAttackEvent is fired when a living Entity is attacked.
@@ -30,21 +31,16 @@ *
* This event is fired on the {@link NeoForge#EVENT_BUS}. **/ -public class LivingAttackEvent extends LivingEvent implements ICancellableEvent { - private final DamageSource source; - private final float amount; - - public LivingAttackEvent(LivingEntity entity, DamageSource source, float amount) { - super(entity); - this.source = source; - this.amount = amount; +public class EntityPreDamageEvent extends DamageSequenceEvent implements ICancellableEvent { + public EntityPreDamageEvent(LivingEntity entity, DamageContainer container) { + super(entity, container); } public DamageSource getSource() { - return source; + return this.container.getSource(); } public float getAmount() { - return amount; + return this.container.getNewDamage(); } } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java similarity index 63% rename from src/main/java/net/neoforged/neoforge/event/entity/living/LivingHurtEvent.java rename to src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java index b337a260e5..730377575d 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java @@ -10,6 +10,7 @@ import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.CommonHooks; import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.common.damagesource.DamageContainer; /** * LivingHurtEvent is fired when an Entity is set to be hurt.
@@ -20,7 +21,6 @@ * This event is fired via the {@link CommonHooks#onLivingHurt(LivingEntity, DamageSource, float)}.
*
* {@link #source} contains the DamageSource that caused this Entity to be hurt.
- * {@link #amount} contains the amount of damage dealt to the Entity that was hurt.
*
* This event is {@link ICancellableEvent}.
* If this event is canceled, the Entity is not hurt.
@@ -29,27 +29,10 @@ *
* This event is fired on the {@link NeoForge#EVENT_BUS}. * - * @see LivingDamageEvent + * @see DamageTakenEvent **/ -public class LivingHurtEvent extends LivingEvent implements ICancellableEvent { - private final DamageSource source; - private float amount; - - public LivingHurtEvent(LivingEntity entity, DamageSource source, float amount) { - super(entity); - this.source = source; - this.amount = amount; - } - - public DamageSource getSource() { - return source; - } - - public float getAmount() { - return amount; - } - - public void setAmount(float amount) { - this.amount = amount; +public class IncomingDamageEvent extends DamageSequenceEvent { + public IncomingDamageEvent(LivingEntity entity, DamageContainer source) { + super(entity, source); } } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ShieldBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ShieldBlockEvent.java deleted file mode 100644 index 3f5f9275e6..0000000000 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ShieldBlockEvent.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.event.entity.living; - -import net.minecraft.util.Mth; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.LivingEntity; -import net.neoforged.bus.api.ICancellableEvent; - -/** - * The ShieldBlockEvent is fired when an entity successfully blocks with a shield.
- * Cancelling this event will have the same impact as if the shield was not eligible to block.
- * The damage blocked cannot be set lower than zero or greater than the original value.
- * Note: The shield item stack "should" be available from {@link LivingEntity#getUseItem()} - * at least for players. - */ -public class ShieldBlockEvent extends LivingEvent implements ICancellableEvent { - private final DamageSource source; - private final float originalBlocked; - private float dmgBlocked; - private boolean shieldTakesDamage = true; - - public ShieldBlockEvent(LivingEntity blocker, DamageSource source, float blocked) { - super(blocker); - this.source = source; - this.originalBlocked = blocked; - this.dmgBlocked = blocked; - } - - /** - * @return The damage source. - */ - public DamageSource getDamageSource() { - return this.source; - } - - /** - * @return The original amount of damage blocked, which is the same as the original - * incoming damage value. - */ - public float getOriginalBlockedDamage() { - return this.originalBlocked; - } - - /** - * @return The current amount of damage blocked, as a result of this event. - */ - public float getBlockedDamage() { - return this.dmgBlocked; - } - - /** - * Controls if {@link LivingEntity#hurtCurrentlyUsedShield} is called. - * - * @return If the shield item will take durability damage or not. - */ - public boolean shieldTakesDamage() { - return this.shieldTakesDamage; - } - - /** - * Set how much damage is blocked by this action.
- * Note that initially the blocked amount is the entire attack.
- */ - public void setBlockedDamage(float blocked) { - this.dmgBlocked = Mth.clamp(blocked, 0, this.originalBlocked); - } - - /** - * Set if the shield will take durability damage or not. - */ - public void setShieldTakesDamage(boolean damage) { - this.shieldTakesDamage = damage; - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java index 565c32db90..2810cf86cc 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java @@ -38,7 +38,7 @@ import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.data.DataMapProvider; import net.neoforged.neoforge.debug.EventTests; -import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; +import net.neoforged.neoforge.event.entity.living.DamageTakenEvent; import net.neoforged.neoforge.event.entity.player.UseItemOnBlockEvent; import net.neoforged.neoforge.registries.datamaps.AdvancedDataMapType; import net.neoforged.neoforge.registries.datamaps.DataMapType; @@ -276,8 +276,8 @@ protected void gather() { } }); - test.eventListeners().forge().addListener((final LivingDamageEvent event) -> { - final ExperienceGrant grant = event.getSource().typeHolder().getData(xpGrant); + test.eventListeners().forge().addListener((final DamageTakenEvent event) -> { + final ExperienceGrant grant = event.getDamageContainer().getSource().typeHolder().getData(xpGrant); if (grant != null && event.getEntity() instanceof Player player) { player.giveExperiencePoints(grant.amount()); } diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java index b775d16416..c70875cc7c 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java @@ -8,6 +8,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.GameTest; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.attributes.RangedAttribute; import net.minecraft.world.entity.animal.Cow; @@ -17,13 +19,16 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.phys.Vec3; +import net.minecraft.world.level.GameType; import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; +import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; import net.neoforged.neoforge.event.entity.EntityTeleportEvent; import net.neoforged.neoforge.event.level.ExplosionKnockbackEvent; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; import net.neoforged.testframework.annotation.TestHolder; import net.neoforged.testframework.gametest.EmptyTemplate; +import net.neoforged.testframework.gametest.GameTestPlayer; import net.neoforged.testframework.registration.RegistrationHelper; @ForEachTest(groups = { EntityTests.GROUP + ".event", "event" }) @@ -93,4 +98,22 @@ static void entityVerticalExplosionKnockbackEvent(final DynamicTest test) { .thenExecute(helper::killAllEntities) .thenSucceed()); } + + @GameTest + @EmptyTemplate + @TestHolder(description = "Tests if EntityInvulnerabilityCheckEvent prevents damage when modified.") + static void entityInvulnerabilityCheckEvent(final DynamicTest test, final RegistrationHelper reg) { + test.eventListeners().forge().addListener((final EntityInvulnerablityCheckEvent event) -> { + if (event.getEntity() instanceof GameTestPlayer entity) + event.setInvulnerable(false); + }); + + test.onGameTest(helper -> { + DamageSource source = new DamageSource(helper.getLevel().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.MOB_ATTACK)); + helper.startSequence(() -> helper.makeTickingMockServerPlayerInLevel(GameType.SURVIVAL)) + .thenExecute(player -> player.setInvulnerable(true)) + .thenWaitUntil(player -> helper.assertTrue(!player.isInvulnerableTo(source), "Player Invulnerability not bypassed.")) + .thenSucceed(); + }); + } } diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java index 27c6f9158b..3e7350b248 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java @@ -39,13 +39,13 @@ import net.minecraft.world.level.GameType; import net.neoforged.fml.util.ObfuscationReflectionHelper; import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent; +import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent; import net.neoforged.neoforge.event.entity.living.LivingConversionEvent; import net.neoforged.neoforge.event.entity.living.LivingEntityUseItemEvent; import net.neoforged.neoforge.event.entity.living.LivingGetProjectileEvent; import net.neoforged.neoforge.event.entity.living.LivingSwapItemsEvent; import net.neoforged.neoforge.event.entity.living.MobSplitEvent; -import net.neoforged.neoforge.event.entity.living.ShieldBlockEvent; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; import net.neoforged.testframework.annotation.TestHolder; @@ -188,8 +188,8 @@ static void setAttackTargetEvent(final DynamicTest test, final RegistrationHelpe @EmptyTemplate(floor = true) @TestHolder(description = "Tests if the ShieldBlockEvent is fired") static void shieldBlockEvent(final DynamicTest test) { - test.eventListeners().forge().addListener((final ShieldBlockEvent event) -> { - if (event.getDamageSource().getDirectEntity() instanceof AbstractArrow arrow && event.getEntity() instanceof Zombie zombie && Objects.equals(zombie.getName(), Component.literal("shieldblock"))) { + test.eventListeners().forge().addListener((final DamageBlockEvent event) -> { + if (event.getBlocked() && event.getDamageSource().getDirectEntity() instanceof AbstractArrow arrow && event.getEntity() instanceof Zombie zombie && Objects.equals(zombie.getName(), Component.literal("shieldblock"))) { zombie.setItemSlot(EquipmentSlot.OFFHAND, new ItemStack(Items.STONE)); event.setBlockedDamage(event.getOriginalBlockedDamage() / 2); arrow.discard(); diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java index e2a055d4c9..9547962096 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java @@ -9,6 +9,7 @@ import net.minecraft.commands.Commands; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.GameTest; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ServerboundInteractPacket; @@ -18,8 +19,13 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.entity.Entity; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -32,6 +38,7 @@ import net.neoforged.bus.api.EventPriority; import net.neoforged.neoforge.event.StatAwardEvent; import net.neoforged.neoforge.event.entity.player.ItemEntityPickupEvent; +import net.neoforged.neoforge.event.entity.living.ArmorHurtEvent; import net.neoforged.neoforge.event.entity.player.PermissionsChangedEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; @@ -275,4 +282,23 @@ static void playerRespawnEvent(final DynamicTest test, final RegistrationHelper .thenExecute(() -> helper.assertEntityIsHolding(new BlockPos(0, 1, 1), EntityType.PLAYER, Items.APPLE)) .thenSucceed()); } + @GameTest + @EmptyTemplate + @TestHolder(description = "Tests if ArmorHurtEvent fires and prevents armor damage.") + static void armorHurtEvent(final DynamicTest test) { + test.eventListeners().forge().addListener((final ArmorHurtEvent event) -> { + if (event.getEntity() instanceof GameTestPlayer player && player.getItemBySlot(EquipmentSlot.HEAD).getItem().equals(Items.DIAMOND_HELMET)) + event.setNewDamage(EquipmentSlot.HEAD, 5); + }); + + test.onGameTest(helper -> { + DamageSource source = new DamageSource(helper.getLevel().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.MOB_ATTACK)); + helper.startSequence(() -> helper.makeTickingMockServerPlayerInLevel(GameType.SURVIVAL)) + .thenExecute(player -> player.setItemSlot(EquipmentSlot.HEAD, new ItemStack(Items.DIAMOND_HELMET))) + .thenExecute(player -> player.getInventory().hurtArmor(source, 100, Inventory.ALL_ARMOR_SLOTS)) + .thenWaitUntil(player -> helper.assertTrue(player.getItemBySlot(EquipmentSlot.HEAD).getDamageValue() == 5, + "Armor hurt not applied. %s actual but expected 5f".formatted(player.getItemBySlot(EquipmentSlot.HEAD).getDamageValue()))) + .thenSucceed(); + }); + } } From acf194a418b25c3631e620881c2bdc8abcb7a909 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:47:40 -0400 Subject: [PATCH 02/41] tweaks to implementation - function-based modifiers - interface for damage container - javadocs --- .../world/entity/LivingEntity.java.patch | 27 +- .../world/entity/player/Player.java.patch | 19 +- .../neoforge/common/CommonHooks.java | 6 +- .../common/damagesource/DamageContainer.java | 349 ++++++++++++++---- 4 files changed, 295 insertions(+), 106 deletions(-) diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index 983d94db67..cd775137cc 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -22,7 +22,7 @@ private float swimAmountO; protected Brain brain; private boolean skipDropExperience; -+ protected net.neoforged.neoforge.common.damagesource.DamageContainer damageContainer; ++ protected net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer damageContainer; protected LivingEntity(EntityType p_20966_, Level p_20967_) { super(p_20966_, p_20967_); @@ -156,7 +156,7 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { -+ this.damageContainer = this.damageContainer == null ? new net.neoforged.neoforge.common.damagesource.DamageContainer(p_21016_, p_21017_) : this.damageContainer; ++ this.damageContainer = this.damageContainer == null ? new net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer(p_21016_, p_21017_) : this.damageContainer; + if (!net.neoforged.neoforge.common.CommonHooks.onEntityPreDamage(this, this.damageContainer)) return false; if (this.isSleeping() && !this.level().isClientSide) { this.stopSleeping(); @@ -377,7 +377,7 @@ } } } -@@ -1636,20 +_,23 @@ +@@ -1636,20 +_,22 @@ int k = EnchantmentHelper.getDamageProtection(this.getArmorSlots(), p_21193_); if (k > 0) { p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, (float)k); @@ -396,19 +396,24 @@ - float f1 = Math.max(p_21241_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_21241_ - f1)); - float f = p_21241_ - f1; -+ net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); -+ if (this.damageContainer.getNewDamage() <= 0) return; -+ this.damageContainer.setArmorReduction(this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getNewDamage())); ++ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getNewDamage())); + this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainer.getNewDamage()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.getAbsorptionAmount(), 0.0F); -+ this.damageContainer.setAbsorption(f1); -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); -+ this.setAbsorptionAmount(this.getAbsorptionAmount() - (this.damageContainer.getNewDamage() - f1)); ++ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ if (f1 <= 0) return; + float f = this.damageContainer.getNewDamage() - f1; if (f > 0.0F && f < 3.4028235E37F) { Entity entity = p_21240_.getEntity(); if (entity instanceof ServerPlayer serverplayer) { -@@ -1662,8 +_,8 @@ +@@ -1657,13 +_,14 @@ + } + } + ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); + if (f1 != 0.0F) { + this.getCombatTracker().recordDamage(p_21240_, f1); this.setHealth(this.getHealth() - f1); this.setAbsorptionAmount(this.getAbsorptionAmount() - f1); this.gameEvent(GameEvent.ENTITY_DAMAGE); diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index a39d3b4d9d..620c20b69b 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -117,7 +117,7 @@ if (this.isDeadOrDying()) { return false; } else { -+ this.damageContainer = new net.neoforged.neoforge.common.damagesource.DamageContainer(p_36154_, p_36155_); ++ this.damageContainer = new net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer(p_36154_, p_36155_); + if (!net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer)) return false; if (!this.level().isClientSide) { this.removeEntitiesOnShoulder(); @@ -161,7 +161,7 @@ if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -@@ -923,26 +_,28 @@ +@@ -923,26 +_,27 @@ @Override protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { @@ -185,19 +185,18 @@ - - this.gameEvent(GameEvent.ENTITY_DAMAGE); - } -+ net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); -+ if (this.damageContainer.getNewDamage() <= 0) return; -+ this.damageContainer.setArmorReduction(this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); ++ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); + this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.getAbsorptionAmount(), 0.0F); -+ this.damageContainer.setAbsorption(f1); -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); -+ this.setAbsorptionAmount(this.getAbsorptionAmount() - (this.damageContainer.getNewDamage() - f1)); ++ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ if (f1 <= 0) return; + float f = this.damageContainer.getNewDamage() - f1; + if (f > 0.0F && f < 3.4028235E37F) { + this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); + } -+ ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); + if (f1 != 0.0F) { + this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); + this.getCombatTracker().recordDamage(p_36312_, f1); diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 97e4d4e433..86277300ae 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -273,12 +273,12 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS return !NeoForge.EVENT_BUS.post(new LivingUseTotemEvent(entity, damageSource, totem, hand)).isCanceled(); } - public static void onIncomingDamage(LivingEntity entity, DamageContainer container) { - NeoForge.EVENT_BUS.post(new IncomingDamageEvent(entity, container)); + public static float onIncomingDamage(LivingEntity entity, DamageContainer container) { + return NeoForge.EVENT_BUS.post(new IncomingDamageEvent(entity, container)).getDamageContainer().getNewDamage(); } public static void onLivingDamageTaken(LivingEntity entity, DamageContainer container) { - NeoForge.EVENT_BUS.post(new DamageTakenEvent(entity, container)); + NeoForge.EVENT_BUS.post(new DamageTakenEvent(entity, new DamageContainer.ResultDamageContainer(container))); } public static void onArmorHurt(DamageSource source, NonNullList armor, float damage, Player player) { diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 23c730bf10..f4428d79da 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -5,114 +5,299 @@ package net.neoforged.neoforge.common.damagesource; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.function.BiFunction; import net.minecraft.world.damagesource.DamageSource; import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; +import org.jetbrains.annotations.ApiStatus; /** * DamageContainer encapsulates aspects of the entity damage sequence so that - * all context related to damage dealt is accessible throughout the entire + * relevant context related to damage dealt is accessible throughout the entire * sequence. *

Note: certain values will be defaults until the stage in the sequence when they are set.

- *
    - *
  • {@link #originalDamage} stores a reference to the raw damage value passed to the defender from the attacker.
  • - *
  • {@link #newDamage} represents the event-modified damage to be applied throughout the sequence.
  • - *
  • {@link #source} an immutable reference to the damage source
  • - *
  • {@link #armorReduction} the amount reduced by armor.
  • - *
  • {@link #absorption} the amount of absorption consumed by the damage sequence.
  • - *
  • {@link #enchantReduction} the amount of damage reduced by enchantments
  • - *
  • {@link #mobEffectReduction} the amount of damage reduced by mob effects
  • - *
  • {@link #invulnerabilityTicksAfterAttack} defaults to 20. Changes how long an entity is invulnerable after this damage sequence. - * This can be modified at any point.
  • - *
  • {@link #blockedDamage} The amount of damage blocked by the shield. This value is set by {@link DamageBlockEvent} and cannot - * be directly modified. {@link #getBlockedDamage()} can be used to obtain the value after the event is fired.
  • - *
  • {@link #shieldDamage} How much damage the shield item will take.
  • - *

+ *

Damage Sequence and uses

    + *
  1. Entity is hurt by a damage source
  2. + *
  3. {@link net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent EntityInvulnerablityCheckEvent} + * fires and determines if the sequence can commence
  4. + *
  5. {@link net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent EntityPreDamageEvent} fires + * and gives access to this. Modifiers should be added here.
  6. + *
  7. {@link DamageBlockEvent} fires
  8. + *
  9. armor, enchantments, mob effect, and absorption modifiers are applied to the damage
  10. + *
  11. {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent IncomingDamageEvent} fires and + * provides final values for the preceding modifiers and the last chance to negate the damage but will not + * undo the preceding effects
  12. + *
  13. {@link net.neoforged.neoforge.event.entity.living.DamageTakenEvent DamageTakenEvent} fires and provides + * an immutable perspective of what the entire sequence ended with.
  14. + *
+ * + * */ -public class DamageContainer { - private final float originalDamage; - private final DamageSource source; - private float newDamage; - private float armorReduction = 0f; - private float absorption = 0f; - private float enchantReduction = 0f; - private float mobEffectReduction = 0f; - private float blockedDamage = 0; - private float shieldDamage = 0; - private int invulnerabilityTicksAfterAttack = 20; - - public DamageContainer(DamageSource source, float originalDamage) { - this.source = source; - this.originalDamage = originalDamage; - this.newDamage = originalDamage; +public interface DamageContainer { + public enum Reduction { + /** Damage reduced from the effects of armor */ + ARMOR, + /** Damage reduced from enchantments on armor */ + ENCHANT, + /** Damage reduced from active mob effects */ + MOBEFFECT, + /** Damage absorbed by absorption. */ + ABSORPTION } - public float getOriginalDamage() { - return originalDamage; - } + /** + * @return the value passed into {@link net.minecraft.world.entity.LivingEntity#hurt(DamageSource, float)} before + * any modifications are made. + */ + float getOriginalDamage(); - public DamageSource getSource() { - return source; - } + /** + * @return the current amount expected to be applied to the entity or used in subsequent damage calculations. + */ + float getNewDamage(); - public DamageBlockEvent setBlockedDamage(DamageBlockEvent event) { - this.blockedDamage = event.getBlockedDamage(); - this.shieldDamage = event.shieldDamage(); - return event; - } + /** + * @return The damage source for this damage sequence + */ + DamageSource getSource(); - public float getBlockedDamage() { - return blockedDamage; - } + /** + * Adds a callback modifier to the vanilla damage reductions. Each function will be performed in sequence + * on the vanilla value at the time the {@link Reduction} type is set by vanilla. + *

Note: only the {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent IncomingDamageEvent} + * happens early enough in the sequence for this method to have any effect.

+ * + * @param type The reduction type your function will apply to + * @param operation takes the current reduction from vanilla and any preceding functions and returns a new + * value for the reduction. These are always executed in insertion order. if sequence + * matters, use {@link net.neoforged.bus.api.EventPriority} to order your function. + */ + void addModifier(Reduction type, BiFunction operation); - public float getShieldDamage() { - return shieldDamage; - } + /** + * This sets the current damage value for the entity at the stage of the damage sequence in which it is set. + * Subsequent steps in the damage sequence will use and modify this value accordingly. If this is called in + * the final step of the sequence, this value will be applied against the entity's health. + * + * @param damage the amount to harm this entity at the end of the damage sequence + */ + void setNewDamage(float damage); - public void setPostAttackInvulnerabilityTicks(int ticks) { - this.invulnerabilityTicksAfterAttack = ticks; - } + /** + * @return The damage blocked during the {@link net.neoforged.neoforge.event.entity.living.DamageBlockEvent} + */ + float getBlockedDamage(); - public int getPostAttackInvulnerabilityTicks() { - return invulnerabilityTicksAfterAttack; - } + /** + * @return The durability applied to the applicable shield after {@link net.neoforged.neoforge.event.entity.living.DamageBlockEvent} + * returned a successful block + */ + float getShieldDamage(); - public void setArmorReduction(float reduction) { - this.armorReduction = reduction; - } + /** + * Explicitly sets the invulnerability ticks after the damage has been applied. + * + * @param ticks Ticks of invulnerability after this damage sequence + */ + void setPostAttackInvulnerabilityTicks(int ticks); - public float getArmorReduction() { - return armorReduction; - } + /** + * @return The number of ticks this entity will be invulnerable after damage is applied. + */ + int getPostAttackInvulnerabilityTicks(); - public void setEnchantReduction(float reduction) { - this.enchantReduction = reduction; - } + /** + * This provides a post-reduction value for armor reduction and modifiers. This will always return zero + * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all + * modifiers prior to the event. + * + * @return The amount of damage reduced by armor after vanilla armor reductions and added modifiers + */ + float getArmorReduction(); - public float getEnchantReduction() { - return enchantReduction; - } + /** + * This provides a post-reduction value for enchantment reduction and modifiers. This will always return zero + * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all + * modifiers prior to the event. + * + * @return the amount of damage reduced by enchantments after vanilla enchantment reductions and added modifiers + */ + float getEnchantReduction(); - public void setMobEffectReduction(float reduction) { - this.mobEffectReduction = reduction; - } + /** + * This provides a post-reduction value for mob effect reduction and modifiers. This will always return zero + * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all + * modifiers prior to the event. + * + * @return The amount of damage reduced by mob effects after vanilla mob effect reductions and added modifiers + */ + float getMobEffectReduction(); - public float getMobEffectReduction() { - return mobEffectReduction; - } + /** + * This provides a post-reduction value for absorption consumption and modifiers. This will always return zero + * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all + * modifiers prior to the event. + * + * @return The amount of absorption consumed after vanilla absorption consumption and added modifiers + */ + float getAbsorption(); - public void setAbsorption(float absorption) { - this.absorption = absorption; - } + public class InternalDamageContainer implements DamageContainer { + private final EnumMap>> reductionMap = new EnumMap<>(Reduction.class); + private final float originalDamage; + private final DamageSource source; + private float newDamage; + private float armorReduction = 0f; + private float absorption = 0f; + private float enchantReduction = 0f; + private float mobEffectReduction = 0f; + private float blockedDamage = 0f; + private float shieldDamage = 0; + private int invulnerabilityTicksAfterAttack = 20; - public float getAbsorption() { - return absorption; - } + public InternalDamageContainer(DamageSource source, float originalDamage) { + this.source = source; + this.originalDamage = originalDamage; + this.newDamage = originalDamage; + } + + @Override + public float getOriginalDamage() { + return originalDamage; + } + + @Override + public DamageSource getSource() { + return source; + } + + @Override + public void setNewDamage(float damage) { + this.newDamage = damage; + } + + @Override + public float getNewDamage() { + return newDamage; + } - public void setNewDamage(float damage) { - this.newDamage = damage; + public void addModifier(Reduction type, BiFunction operation) { + this.reductionMap.computeIfAbsent(type, a -> new ArrayList<>()).add(operation); + } + + @Override + public float getBlockedDamage() { + return blockedDamage; + } + + @Override + public float getShieldDamage() { + return shieldDamage; + } + + @Override + public void setPostAttackInvulnerabilityTicks(int ticks) { + this.invulnerabilityTicksAfterAttack = ticks; + } + + @Override + public int getPostAttackInvulnerabilityTicks() { + return invulnerabilityTicksAfterAttack; + } + + @Override + public float getArmorReduction() { + return armorReduction; + } + + @Override + public float getEnchantReduction() { + return enchantReduction; + } + + @Override + public float getMobEffectReduction() { + return mobEffectReduction; + } + + @Override + public float getAbsorption() { + return absorption; + } + + //=============INTERNAL METHODS - DO NOT USE=================== + + @ApiStatus.Internal + public DamageBlockEvent setBlockedDamage(DamageBlockEvent event) { + if (event.getBlocked()) { + this.blockedDamage = event.getBlockedDamage(); + this.shieldDamage = event.shieldDamage(); + this.newDamage -= this.blockedDamage; + } + return event; + } + + @ApiStatus.Internal + public void setAbsorption(float absorption) { + this.absorption = modifyReduction(Reduction.ABSORPTION, absorption); + this.newDamage -= Math.max(0, absorption); + } + + @ApiStatus.Internal + public void setMobEffectReduction(float reduction) { + this.mobEffectReduction = modifyReduction(Reduction.MOBEFFECT, reduction); + this.newDamage -= Math.max(0, reduction); + } + + @ApiStatus.Internal + public void setEnchantReduction(float reduction) { + this.enchantReduction = modifyReduction(Reduction.ENCHANT, reduction); + this.newDamage -= Math.max(0, reduction); + } + + @ApiStatus.Internal + public void setArmorReduction(float reduction) { + this.armorReduction = modifyReduction(Reduction.ARMOR, reduction); + this.newDamage -= Math.max(0, this.armorReduction); + } + + private float modifyReduction(Reduction type, float reduction) { + for (var func : reductionMap.getOrDefault(type, new ArrayList<>())) { + reduction = func.apply(this, reduction); + } + return reduction; + } } - public float getNewDamage() { - return newDamage; + public record ResultDamageContainer( + float getOriginalDamage, + DamageSource getSource, + float getNewDamage, + float getBlockedDamage, + float getShieldDamage, + int getPostAttackInvulnerabilityTicks, + float getArmorReduction, + float getEnchantReduction, + float getMobEffectReduction, + float getAbsorption + + ) implements DamageContainer { + public ResultDamageContainer(DamageContainer container) { + this(container.getOriginalDamage(), container.getSource(), container.getNewDamage(), + container.getBlockedDamage(), container.getShieldDamage(), container.getPostAttackInvulnerabilityTicks(), + container.getArmorReduction(), container.getEnchantReduction(), container.getMobEffectReduction(), + container.getAbsorption()); + } + + @Override + public void addModifier(Reduction type, BiFunction function) {} + + @Override + public void setNewDamage(float damage) {} + + @Override + public void setPostAttackInvulnerabilityTicks(int ticks) {} } } From be0fc4d07c3e7d62bc968959163c1261b445033f Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:58:06 -0400 Subject: [PATCH 03/41] add internal annotation to internal class --- .../neoforged/neoforge/common/damagesource/DamageContainer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index f4428d79da..0b803f5e0d 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -144,6 +144,7 @@ public enum Reduction { */ float getAbsorption(); + @ApiStatus.Internal public class InternalDamageContainer implements DamageContainer { private final EnumMap>> reductionMap = new EnumMap<>(Reduction.class); private final float originalDamage; From 0a92ec01680fb8aa73367fb30d197e0132d1403b Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 11 Apr 2024 05:46:52 -0400 Subject: [PATCH 04/41] javadoc and type clarity changes --- .../neoforge/common/damagesource/DamageContainer.java | 2 +- .../neoforge/event/entity/living/ArmorHurtEvent.java | 9 +++++---- .../neoforge/event/entity/living/DamageBlockEvent.java | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 0b803f5e0d..70284f8399 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -66,7 +66,7 @@ public enum Reduction { /** * Adds a callback modifier to the vanilla damage reductions. Each function will be performed in sequence * on the vanilla value at the time the {@link Reduction} type is set by vanilla. - *

Note: only the {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent IncomingDamageEvent} + *

Note: only the {@link net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent EntityPreDamageEvent} * happens early enough in the sequence for this method to have any effect.

* * @param type The reduction type your function will apply to diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index 609a513614..9a82c5e810 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -5,6 +5,7 @@ package net.neoforged.neoforge.event.entity.living; +import java.util.EnumMap; import java.util.Map; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EquipmentSlot; @@ -25,12 +26,12 @@ * This event is fired on the {@link NeoForge#EVENT_BUS} */ public class ArmorHurtEvent extends PlayerEvent implements ICancellableEvent { - private final Map armorItemStack; - private final Map originalDamage; - private final Map damage; + private final EnumMap armorItemStack; + private final EnumMap originalDamage; + private final EnumMap damage; @ApiStatus.Internal - public ArmorHurtEvent(Map armorItemStack, Map damage, Player player) { + public ArmorHurtEvent(EnumMap armorItemStack, EnumMap damage, Player player) { super(player); this.armorItemStack = armorItemStack; this.originalDamage = damage; diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java index de11e66c4d..1c698f4f92 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java @@ -54,9 +54,10 @@ public float getBlockedDamage() { } /** - * Controls if {@link LivingEntity#hurtCurrentlyUsedShield} is called. + * If the event is {@link #getBlocked()} and the user is holding a shield, the returned amount + * will be taken from the item's durability. * - * @return If the shield item will take durability damage or not. + * @return The amount of sheild durability damage to take. */ public float shieldDamage() { return this.shieldDamage; From 2b6bf36211717654baa2cfb210a7e7d5eb0ebc02 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 11 Apr 2024 18:05:15 -0400 Subject: [PATCH 05/41] update armor event --- .../neoforge/common/CommonHooks.java | 16 ++++----- .../event/entity/living/ArmorHurtEvent.java | 35 ++++++++++++------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 86277300ae..4fc001a7d8 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -282,22 +282,20 @@ public static void onLivingDamageTaken(LivingEntity entity, DamageContainer cont } public static void onArmorHurt(DamageSource source, NonNullList armor, float damage, Player player) { - EnumMap armorMap = new EnumMap<>(EquipmentSlot.class); - EnumMap damageMap = new EnumMap<>(EquipmentSlot.class); + EnumMap armorMap = new EnumMap<>(EquipmentSlot.class); for (int index : Inventory.ALL_ARMOR_SLOTS) { ItemStack armorPiece = armor.get(index); if (armorPiece.isEmpty()) continue; EquipmentSlot slot = EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index); - armorMap.put(slot, armor.get(index)); - damageMap.put(slot, damage); + armorMap.put(slot, new ArmorHurtEvent.ArmorEntry(armorPiece, damage)); } - ArmorHurtEvent event = NeoForge.EVENT_BUS.post(new ArmorHurtEvent(armorMap, damageMap, player)); + ArmorHurtEvent event = NeoForge.EVENT_BUS.post(new ArmorHurtEvent(armorMap, player)); if (event.isCanceled()) return; - event.getArmorMap().forEach((slot, armorPiece) -> { - if ((!source.is(DamageTypeTags.IS_FIRE) || !armorPiece.getItem().isFireResistant()) && armorPiece.getItem() instanceof ArmorItem) { - Float finalDamage = event.isCanceled() ? event.getOriginalDamage(slot) : event.getNewDamage(slot); - armorPiece.hurtAndBreak(finalDamage.intValue(), player, p_35997_ -> p_35997_.broadcastBreakEvent(slot)); + event.getArmorMap().forEach((slot, entry) -> { + if ((!source.is(DamageTypeTags.IS_FIRE) || !entry.armorItemStack.getItem().isFireResistant()) && entry.armorItemStack.getItem() instanceof ArmorItem) { + Float finalDamage = event.isCanceled() ? entry.originalDamage : entry.newDamage; + entry.armorItemStack.hurtAndBreak(finalDamage.intValue(), player, p_35997_ -> p_35997_.broadcastBreakEvent(slot)); } }); } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index 9a82c5e810..e10790dd7e 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -7,6 +7,7 @@ import java.util.EnumMap; import java.util.Map; +import java.util.stream.Collectors; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; @@ -26,16 +27,24 @@ * This event is fired on the {@link NeoForge#EVENT_BUS} */ public class ArmorHurtEvent extends PlayerEvent implements ICancellableEvent { - private final EnumMap armorItemStack; - private final EnumMap originalDamage; - private final EnumMap damage; + public static class ArmorEntry { + public ItemStack armorItemStack; + public final float originalDamage; + public float newDamage; + + public ArmorEntry(ItemStack armorStack, float damageIn) { + this.armorItemStack = armorStack; + this.originalDamage = damageIn; + this.newDamage = damageIn; + } + } + + private final EnumMap armorEntries; @ApiStatus.Internal - public ArmorHurtEvent(EnumMap armorItemStack, EnumMap damage, Player player) { + public ArmorHurtEvent(EnumMap armorMap, Player player) { super(player); - this.armorItemStack = armorItemStack; - this.originalDamage = damage; - this.damage = damage; + this.armorEntries = armorMap; } /** @@ -44,17 +53,17 @@ public ArmorHurtEvent(EnumMap armorItemStack, EnumMap< * @return the {@link ItemStack} to be hurt for the given slot */ public ItemStack getArmorItemStack(EquipmentSlot slot) { - return armorItemStack.getOrDefault(slot, ItemStack.EMPTY); + return armorEntries.containsKey(slot) ? armorEntries.get(slot).armorItemStack : ItemStack.EMPTY; } /** {@return the original damage before any event modifications} */ public Float getOriginalDamage(EquipmentSlot slot) { - return originalDamage.getOrDefault(slot, 0f); + return armorEntries.containsKey(slot) ? armorEntries.get(slot).originalDamage : 0f; } /** {@return the amount to hurt the armor if the event is not cancelled} */ public Float getNewDamage(EquipmentSlot slot) { - return damage.getOrDefault(slot, 0f); + return armorEntries.containsKey(slot) ? armorEntries.get(slot).newDamage : 0f; } /** @@ -63,11 +72,11 @@ public Float getNewDamage(EquipmentSlot slot) { * @param damage the new amount to hurt the armor. Values below zero will be set to zero. */ public void setNewDamage(EquipmentSlot slot, float damage) { - if (this.damage.containsKey(slot)) this.damage.put(slot, Math.max(damage, 0)); + if (this.armorEntries.containsKey(slot)) this.armorEntries.get(slot).newDamage = damage; } /** Used internally to get the full map of {@link ItemStack}s to be hurt */ - public Map getArmorMap() { - return armorItemStack; + public Map getArmorMap() { + return armorEntries; } } From 642b5ea5ef20fee7ef1514ac65c35fd524cb02b6 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 11 Apr 2024 18:18:58 -0400 Subject: [PATCH 06/41] resolve missed formatting error --- .../neoforged/neoforge/event/entity/living/ArmorHurtEvent.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index e10790dd7e..ae10dd2946 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -7,7 +7,6 @@ import java.util.EnumMap; import java.util.Map; -import java.util.stream.Collectors; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; From 4bff4ea470c813b0c111bd7d0e921fc91d581a19 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 11 Apr 2024 19:48:25 -0400 Subject: [PATCH 07/41] armor hook reorg --- .../net/neoforged/neoforge/common/CommonHooks.java | 10 +++------- .../neoforge/event/entity/living/ArmorHurtEvent.java | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 4fc001a7d8..92cb8e6d70 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -286,18 +286,14 @@ public static void onArmorHurt(DamageSource source, NonNullList armor for (int index : Inventory.ALL_ARMOR_SLOTS) { ItemStack armorPiece = armor.get(index); if (armorPiece.isEmpty()) continue; + float damageAfterFireResist = ((!source.is(DamageTypeTags.IS_FIRE) || !armorPiece.getItem().isFireResistant()) && armorPiece.getItem() instanceof ArmorItem) ? damage : 0; EquipmentSlot slot = EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index); - armorMap.put(slot, new ArmorHurtEvent.ArmorEntry(armorPiece, damage)); + armorMap.put(slot, new ArmorHurtEvent.ArmorEntry(armorPiece, damageAfterFireResist)); } ArmorHurtEvent event = NeoForge.EVENT_BUS.post(new ArmorHurtEvent(armorMap, player)); if (event.isCanceled()) return; - event.getArmorMap().forEach((slot, entry) -> { - if ((!source.is(DamageTypeTags.IS_FIRE) || !entry.armorItemStack.getItem().isFireResistant()) && entry.armorItemStack.getItem() instanceof ArmorItem) { - Float finalDamage = event.isCanceled() ? entry.originalDamage : entry.newDamage; - entry.armorItemStack.hurtAndBreak(finalDamage.intValue(), player, p_35997_ -> p_35997_.broadcastBreakEvent(slot)); - } - }); + event.getArmorMap().forEach((slot, entry) -> entry.armorItemStack.hurtAndBreak(entry.newDamage.intValue(), player, p_35997_ -> p_35997_.broadcastBreakEvent(slot))); } public static boolean onLivingDeath(LivingEntity entity, DamageSource src) { diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index ae10dd2946..becd935cab 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -29,7 +29,7 @@ public class ArmorHurtEvent extends PlayerEvent implements ICancellableEvent { public static class ArmorEntry { public ItemStack armorItemStack; public final float originalDamage; - public float newDamage; + public Float newDamage; public ArmorEntry(ItemStack armorStack, float damageIn) { this.armorItemStack = armorStack; From 55be2d47540e73636873117b1db682082f494d0f Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Fri, 12 Apr 2024 06:29:33 -0400 Subject: [PATCH 08/41] minor tweaks - int cast, shield damage --- src/main/java/net/neoforged/neoforge/common/CommonHooks.java | 2 +- .../neoforged/neoforge/event/entity/living/ArmorHurtEvent.java | 2 +- .../neoforge/event/entity/living/DamageBlockEvent.java | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 92cb8e6d70..46fdd7299d 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -293,7 +293,7 @@ public static void onArmorHurt(DamageSource source, NonNullList armor ArmorHurtEvent event = NeoForge.EVENT_BUS.post(new ArmorHurtEvent(armorMap, player)); if (event.isCanceled()) return; - event.getArmorMap().forEach((slot, entry) -> entry.armorItemStack.hurtAndBreak(entry.newDamage.intValue(), player, p_35997_ -> p_35997_.broadcastBreakEvent(slot))); + event.getArmorMap().forEach((slot, entry) -> entry.armorItemStack.hurtAndBreak((int) entry.newDamage, player, p_35997_ -> p_35997_.broadcastBreakEvent(slot))); } public static boolean onLivingDeath(LivingEntity entity, DamageSource src) { diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index becd935cab..ae10dd2946 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -29,7 +29,7 @@ public class ArmorHurtEvent extends PlayerEvent implements ICancellableEvent { public static class ArmorEntry { public ItemStack armorItemStack; public final float originalDamage; - public Float newDamage; + public float newDamage; public ArmorEntry(ItemStack armorStack, float damageIn) { this.armorItemStack = armorStack; diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java index 1c698f4f92..d6610e550a 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java @@ -29,6 +29,7 @@ public DamageBlockEvent(LivingEntity blocker, DamageContainer container, boolean this.dmgBlocked = container.getOriginalDamage(); this.originalBlocked = originalBlockedState; this.newBlocked = originalBlockedState; + this.shieldDamage = container.getOriginalDamage(); } /** From 8f26b03b6b238759befc1892bbb77c6374816066 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Fri, 12 Apr 2024 06:31:57 -0400 Subject: [PATCH 09/41] shield damage value verification --- .../neoforge/event/entity/living/DamageBlockEvent.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java index d6610e550a..a0b7325a1a 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java @@ -20,7 +20,7 @@ */ public class DamageBlockEvent extends DamageSequenceEvent implements ICancellableEvent { private float dmgBlocked; - private float shieldDamage = 0; + private float shieldDamage = -1; private final boolean originalBlocked; private boolean newBlocked; @@ -61,7 +61,9 @@ public float getBlockedDamage() { * @return The amount of sheild durability damage to take. */ public float shieldDamage() { - return this.shieldDamage; + if (newBlocked) + return shieldDamage >= 0 ? shieldDamage : dmgBlocked; + return 0; } /** From 49b2d0f82d73a0e817c559b5f5179b45477922fa Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Fri, 12 Apr 2024 06:53:32 -0400 Subject: [PATCH 10/41] update javadoc, max block amount, og dmg amount --- .../event/entity/living/DamageBlockEvent.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java index a0b7325a1a..0575be5c9a 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java @@ -12,11 +12,14 @@ import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * The ShieldBlockEvent is fired when an entity successfully blocks with a shield.
+ * The ShieldBlockEvent is fired when an entity is hurt and vanilla checks if the entity is attempting + * to block with a shield.
* Cancelling this event will have the same impact as if the shield was not eligible to block.
* The damage blocked cannot be set lower than zero or greater than the original value.
- * Note: The shield item stack "should" be available from {@link LivingEntity#getUseItem()} - * at least for players. + *

Note: This event fires whether the player is actively using a shield or not. Vanilla shield + * blocking logic is captured and passed into the event via {@link #getOriginalBlock()}. If this is + * true, The shield item stack "should" be available from {@link LivingEntity#getUseItem()} at least + * for players.

*/ public class DamageBlockEvent extends DamageSequenceEvent implements ICancellableEvent { private float dmgBlocked; @@ -26,10 +29,10 @@ public class DamageBlockEvent extends DamageSequenceEvent implements ICancellabl public DamageBlockEvent(LivingEntity blocker, DamageContainer container, boolean originalBlockedState) { super(blocker, container); - this.dmgBlocked = container.getOriginalDamage(); + this.dmgBlocked = container.getNewDamage(); this.originalBlocked = originalBlockedState; this.newBlocked = originalBlockedState; - this.shieldDamage = container.getOriginalDamage(); + this.shieldDamage = container.getNewDamage(); } /** @@ -44,25 +47,25 @@ public DamageSource getDamageSource() { * incoming damage value. */ public float getOriginalBlockedDamage() { - return this.getDamageContainer().getOriginalDamage(); + return this.getDamageContainer().getNewDamage(); } /** * @return The current amount of damage blocked, as a result of this event. */ public float getBlockedDamage() { - return this.dmgBlocked; + return Math.min(this.dmgBlocked, container.getNewDamage()); } /** * If the event is {@link #getBlocked()} and the user is holding a shield, the returned amount * will be taken from the item's durability. * - * @return The amount of sheild durability damage to take. + * @return The amount of shield durability damage to take. */ public float shieldDamage() { if (newBlocked) - return shieldDamage >= 0 ? shieldDamage : dmgBlocked; + return shieldDamage >= 0 ? shieldDamage : getBlockedDamage(); return 0; } @@ -75,9 +78,11 @@ public void setBlockedDamage(float blocked) { } /** - * Set if the shield will take durability damage or not. + * Set how much durability the shield will lose if {@link #getBlocked()} is true. + * + * @param damage the new durability value taken from the shield on successful block */ - public void setShieldTakesDamage(float damage) { + public void setShieldDamage(float damage) { this.shieldDamage = damage; } From db41d0ebb3f5f5fd302704c01eb911592745a039 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Fri, 12 Apr 2024 07:20:22 -0400 Subject: [PATCH 11/41] javadoc update to refresh upstream tasks --- .../neoforge/event/entity/living/DamageSequenceEvent.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java index ffd46956ce..f6ec6735cb 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java @@ -14,10 +14,10 @@ * implementations of this class should be used to allow simple discrimination * of where in the damage sequence the {@link DamageContainer} is. *
- * {@link #container} can be accessed to modify or obtain values from the damage - * sequence. Note that depending on where in the damage sequence a child event - * is invoked, modification of a value may have no effect. Read the documentation - * on the child event of your listener for more detail. + * The {@link DamageContainer container} can be accessed to modify or obtain values + * from the damage sequence. Note that depending on where in the damage sequence + * a child event is invoked, modification of a value may have no effect. Read the + * documentation on the child event of your listener for more detail. *
* This event is not {@link ICancellableEvent} by default. Implementation classes * can implement this interface if their corresponding hooks effectively terminate From 1f5ab24b6b7f3a3a1fdf269353e516515148087d Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:26:54 -0400 Subject: [PATCH 12/41] fix 1.20.5 merge errors. --- .../minecraft/world/entity/Entity.java.patch | 181 ++++------ .../world/entity/LivingEntity.java.patch | 325 ++++++++--------- .../world/entity/player/Inventory.java.patch | 15 - .../world/entity/player/Player.java.patch | 326 +++++++++-------- .../neoforge/common/CommonHooks.java | 327 +++++++----------- .../event/entity/living/ArmorHurtEvent.java | 12 +- .../debug/entity/player/PlayerEventTests.java | 72 +--- 7 files changed, 517 insertions(+), 741 deletions(-) diff --git a/patches/net/minecraft/world/entity/Entity.java.patch b/patches/net/minecraft/world/entity/Entity.java.patch index 5b2dea07e9..8010d7aba8 100644 --- a/patches/net/minecraft/world/entity/Entity.java.patch +++ b/patches/net/minecraft/world/entity/Entity.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -124,7 +_,7 @@ - import org.joml.Vector3f; +@@ -126,7 +_,7 @@ + import net.minecraft.world.scores.Team; import org.slf4j.Logger; --public abstract class Entity implements Nameable, EntityAccess, CommandSource, ScoreHolder { -+public abstract class Entity extends net.neoforged.neoforge.attachment.AttachmentHolder implements Nameable, EntityAccess, CommandSource, ScoreHolder, net.neoforged.neoforge.common.extensions.IEntityExtension { +-public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder { ++public abstract class Entity extends net.neoforged.neoforge.attachment.AttachmentHolder implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder, net.neoforged.neoforge.common.extensions.IEntityExtension { private static final Logger LOGGER = LogUtils.getLogger(); public static final String ID_TAG = "id"; public static final String PASSENGERS_TAG = "Passengers"; -@@ -145,6 +_,7 @@ +@@ -147,6 +_,7 @@ private static final double LAVA_SLOW_FLOW_SCALE = 0.0023333333333333335; public static final String UUID_TAG = "UUID"; private static double viewScale = 1.0; @@ -17,7 +17,7 @@ private final EntityType type; private int id = ENTITY_COUNTER.incrementAndGet(); public boolean blocksBuilding; -@@ -191,8 +_,10 @@ +@@ -192,8 +_,10 @@ public int tickCount; private int remainingFireTicks = -this.getFireImmuneTicks(); protected boolean wasTouchingWater; @@ -28,19 +28,19 @@ private final Set> fluidOnEyes = new HashSet<>(); public int invulnerableTime; protected boolean firstTick = true; -@@ -260,7 +_,10 @@ - this.entityData.define(DATA_TICKS_FROZEN, 0); - this.defineSynchedData(); +@@ -262,7 +_,10 @@ + this.defineSynchedData(synchedentitydata$builder); + this.entityData = synchedentitydata$builder.build(); this.setPos(0.0, 0.0, 0.0); -- this.eyeHeight = this.getEyeHeight(Pose.STANDING, this.dimensions); -+ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, Pose.STANDING, this.dimensions, this.getEyeHeight(Pose.STANDING, this.dimensions)); +- this.eyeHeight = this.dimensions.eyeHeight(); ++ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, Pose.STANDING, this.dimensions, this.getEyeHeight(Pose.STANDING)); + this.dimensions = sizeEvent.getNewSize(); + this.eyeHeight = sizeEvent.getNewEyeHeight(); + net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.EntityEvent.EntityConstructing(this)); } public boolean isColliding(BlockPos p_20040_, BlockState p_20041_) { -@@ -468,7 +_,7 @@ +@@ -466,7 +_,7 @@ if (this.isInLava()) { this.lavaHurt(); @@ -49,16 +49,16 @@ } this.checkBelowWorld(); -@@ -675,7 +_,7 @@ +@@ -672,7 +_,7 @@ double d1 = vec3.x; double d2 = vec3.y; double d3 = vec3.z; -- this.flyDist += (float)(vec3.length() * 0.6); +- this.flyDist = this.flyDist + (float)(vec3.length() * 0.6); + this.flyDist = (float)((double)this.flyDist + vec3.length() * 0.6D); BlockPos blockpos1 = this.getOnPos(); BlockState blockstate1 = this.level().getBlockState(blockpos1); boolean flag1 = this.isStateClimbable(blockstate1); -@@ -719,16 +_,16 @@ +@@ -716,16 +_,16 @@ this.setRemainingFireTicks(-this.getFireImmuneTicks()); } @@ -78,7 +78,7 @@ } } } -@@ -814,9 +_,7 @@ +@@ -811,9 +_,7 @@ return blockpos; } else { BlockState blockstate = this.level().getBlockState(blockpos); @@ -89,25 +89,7 @@ ? blockpos.atY(Mth.floor(this.position.y - (double)p_216987_)) : blockpos; } -@@ -889,12 +_,13 @@ - boolean flag1 = p_20273_.y != vec3.y; - boolean flag2 = p_20273_.z != vec3.z; - boolean flag3 = this.onGround() || flag1 && p_20273_.y < 0.0; -- if (this.maxUpStep() > 0.0F && flag3 && (flag || flag2)) { -- Vec3 vec31 = collideBoundingBox(this, new Vec3(p_20273_.x, (double)this.maxUpStep(), p_20273_.z), aabb, this.level(), list); -+ float stepHeight = getStepHeight(); -+ if (stepHeight > 0.0F && flag3 && (flag || flag2)) { -+ Vec3 vec31 = collideBoundingBox(this, new Vec3(p_20273_.x, (double)stepHeight, p_20273_.z), aabb, this.level(), list); - Vec3 vec32 = collideBoundingBox( -- this, new Vec3(0.0, (double)this.maxUpStep(), 0.0), aabb.expandTowards(p_20273_.x, 0.0, p_20273_.z), this.level(), list -+ this, new Vec3(0.0D, (double)stepHeight, 0.0D), aabb.expandTowards(p_20273_.x, 0.0D, p_20273_.z), this.level(), list - ); -- if (vec32.y < (double)this.maxUpStep()) { -+ if (vec32.y < (double)stepHeight) { - Vec3 vec33 = collideBoundingBox(this, new Vec3(p_20273_.x, 0.0, p_20273_.z), aabb.move(vec32), this.level(), list).add(vec32); - if (vec33.horizontalDistanceSqr() > vec31.horizontalDistanceSqr()) { - vec31 = vec33; -@@ -1042,19 +_,19 @@ +@@ -1039,19 +_,19 @@ return !blockstate.is(BlockTags.INSIDE_STEP_SOUND_BLOCKS) && !blockstate.is(BlockTags.COMBINATION_STEP_SOUND_BLOCKS) ? p_278049_ : blockpos; } @@ -133,7 +115,7 @@ this.playSound(soundtype.getStepSound(), soundtype.getVolume() * 0.15F, soundtype.getPitch()); } -@@ -1192,20 +_,23 @@ +@@ -1204,20 +_,23 @@ public void updateSwimming() { if (this.isSwimming()) { @@ -162,15 +144,15 @@ } void updateInWaterStateAndDoWaterCurrentPushing() { -@@ -1231,6 +_,7 @@ +@@ -1242,6 +_,7 @@ private void updateFluidOnEyes() { this.wasEyeInWater = this.isEyeInFluid(FluidTags.WATER); this.fluidOnEyes.clear(); + this.forgeFluidTypeOnEyes = net.neoforged.neoforge.common.NeoForgeMod.EMPTY_TYPE.value(); - double d0 = this.getEyeY() - 0.11111111F; - Entity entity = this.getVehicle(); - if (entity instanceof Boat boat && !boat.isUnderWater() && boat.getBoundingBox().maxY >= d0 && boat.getBoundingBox().minY <= d0) { -@@ -1241,7 +_,7 @@ + double d0 = this.getEyeY(); + if (this.getVehicle() instanceof Boat boat && !boat.isUnderWater() && boat.getBoundingBox().maxY >= d0 && boat.getBoundingBox().minY <= d0) { + return; +@@ -1251,7 +_,7 @@ FluidState fluidstate = this.level().getFluidState(blockpos); double d1 = (double)((float)blockpos.getY() + fluidstate.getHeight(this.level(), blockpos)); if (d1 > d0) { @@ -179,7 +161,7 @@ } } -@@ -1286,12 +_,13 @@ +@@ -1296,12 +_,13 @@ } public boolean canSpawnSprintParticle() { @@ -194,7 +176,7 @@ if (blockstate.getRenderShape() != RenderShape.INVISIBLE) { Vec3 vec3 = this.getDeltaMovement(); BlockPos blockpos1 = this.blockPosition(); -@@ -1305,16 +_,19 @@ +@@ -1315,16 +_,19 @@ d1 = Mth.clamp(d1, (double)blockpos.getZ(), (double)blockpos.getZ() + 1.0); } @@ -216,7 +198,7 @@ } public void moveRelative(float p_19921_, Vec3 p_19922_) { -@@ -1631,6 +_,8 @@ +@@ -1645,6 +_,8 @@ p_20241_.putBoolean("HasVisualFire", this.hasVisualFire); } @@ -225,28 +207,28 @@ if (!this.tags.isEmpty()) { ListTag listtag = new ListTag(); -@@ -1641,6 +_,10 @@ +@@ -1655,6 +_,10 @@ p_20241_.put("Tags", listtag); } -+ CompoundTag attachments = serializeAttachments(); ++ CompoundTag attachments = serializeAttachments(registryAccess()); + if (attachments != null) p_20241_.put(ATTACHMENTS_NBT_KEY, attachments); + if (persistentData != null) p_20241_.put("NeoForgeData", persistentData.copy()); + this.addAdditionalSaveData(p_20241_); if (this.isVehicle()) { ListTag listtag1 = new ListTag(); -@@ -1721,6 +_,9 @@ +@@ -1735,6 +_,9 @@ this.setGlowingTag(p_20259_.getBoolean("Glowing")); this.setTicksFrozen(p_20259_.getInt("TicksFrozen")); this.hasVisualFire = p_20259_.getBoolean("HasVisualFire"); + if (p_20259_.contains("NeoForgeData", 10)) persistentData = p_20259_.getCompound("NeoForgeData"); + if (p_20259_.contains("CanUpdate", 99)) this.canUpdate(p_20259_.getBoolean("CanUpdate")); -+ if (p_20259_.contains(ATTACHMENTS_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) deserializeAttachments(p_20259_.getCompound(ATTACHMENTS_NBT_KEY)); ++ if (p_20259_.contains(ATTACHMENTS_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) deserializeAttachments(registryAccess(), p_20259_.getCompound(ATTACHMENTS_NBT_KEY)); if (p_20259_.contains("Tags", 9)) { this.tags.clear(); ListTag listtag3 = p_20259_.getList("Tags", 8); -@@ -1805,6 +_,8 @@ +@@ -1819,6 +_,8 @@ } else { ItemEntity itementity = new ItemEntity(this.level(), this.getX(), this.getY() + (double)p_19986_, this.getZ(), p_19985_); itementity.setDefaultPickUpDelay(); @@ -255,7 +237,7 @@ this.level().addFreshEntity(itementity); return itementity; } -@@ -1851,6 +_,7 @@ +@@ -1865,6 +_,7 @@ public void rideTick() { this.setDeltaMovement(Vec3.ZERO); @@ -263,7 +245,7 @@ this.tick(); if (this.isPassenger()) { this.getVehicle().positionRider(this); -@@ -1908,6 +_,7 @@ +@@ -1923,6 +_,7 @@ } } @@ -271,7 +253,7 @@ if (p_19967_ || this.canRide(p_19966_) && p_19966_.canAddPassenger(this)) { if (this.isPassenger()) { this.stopRiding(); -@@ -1939,6 +_,7 @@ +@@ -1954,6 +_,7 @@ public void removeVehicle() { if (this.vehicle != null) { Entity entity = this.vehicle; @@ -279,7 +261,7 @@ this.vehicle = null; entity.removePassenger(this); } -@@ -1988,6 +_,8 @@ +@@ -2003,6 +_,8 @@ return this.passengers.isEmpty(); } @@ -288,7 +270,7 @@ protected boolean couldAcceptPassenger() { return true; } -@@ -2193,7 +_,7 @@ +@@ -2192,7 +_,7 @@ } public boolean isVisuallyCrawling() { @@ -297,8 +279,8 @@ } public void setSwimming(boolean p_20283_) { -@@ -2302,7 +_,7 @@ - this.setSecondsOnFire(8); +@@ -2301,7 +_,7 @@ + this.igniteForSeconds(8); } - this.hurt(this.damageSources().lightningBolt(), 5.0F); @@ -306,7 +288,7 @@ } public void onAboveBubbleCol(boolean p_20313_) { -@@ -2397,7 +_,7 @@ +@@ -2396,7 +_,7 @@ } protected Component getTypeName() { @@ -315,7 +297,7 @@ } public boolean is(Entity p_20356_) { -@@ -2452,10 +_,11 @@ +@@ -2451,10 +_,11 @@ } public boolean isInvulnerableTo(DamageSource p_20122_) { @@ -328,7 +310,7 @@ } public boolean isInvulnerable() { -@@ -2480,14 +_,20 @@ +@@ -2479,14 +_,20 @@ @Nullable public Entity changeDimension(ServerLevel p_20118_) { @@ -350,7 +332,7 @@ this.level().getProfiler().popPush("reloading"); Entity entity = this.getType().create(p_20118_); if (entity != null) { -@@ -2495,17 +_,19 @@ +@@ -2494,17 +_,19 @@ entity.moveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z, portalinfo.yRot, entity.getXRot()); entity.setDeltaMovement(portalinfo.speed); p_20118_.addDuringTeleport(entity); @@ -372,7 +354,7 @@ } } else { return null; -@@ -2641,6 +_,7 @@ +@@ -2639,6 +_,7 @@ return this.stringUUID; } @@ -380,31 +362,30 @@ public boolean isPushedByFluid() { return true; } -@@ -2764,8 +_,10 @@ +@@ -2764,6 +_,8 @@ EntityDimensions entitydimensions = this.dimensions; Pose pose = this.getPose(); EntityDimensions entitydimensions1 = this.getDimensions(pose); -+ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, pose, entitydimensions, entitydimensions1, this.getEyeHeight(pose, entitydimensions1)); ++ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, pose, entitydimensions, entitydimensions1, entitydimensions1.eyeHeight()); // Porting 1.20.5 check if this still works + entitydimensions1 = sizeEvent.getNewSize(); this.dimensions = entitydimensions1; -- this.eyeHeight = this.getEyeHeight(pose, entitydimensions1); -+ this.eyeHeight = sizeEvent.getNewEyeHeight(); + this.eyeHeight = entitydimensions1.eyeHeight(); this.reapplyPosition(); - boolean flag = (double)entitydimensions1.width <= 4.0 && (double)entitydimensions1.height <= 4.0; - if (!this.level().isClientSide -@@ -2778,9 +_,10 @@ - double d0 = (double)Math.max(0.0F, entitydimensions1.width - entitydimensions.width) + 1.0E-6; - double d1 = (double)Math.max(0.0F, entitydimensions1.height - entitydimensions.height) + 1.0E-6; +@@ -2778,11 +_,12 @@ + double d0 = (double)Math.max(0.0F, entitydimensions1.width() - entitydimensions.width()) + 1.0E-6; + double d1 = (double)Math.max(0.0F, entitydimensions1.height() - entitydimensions.height()) + 1.0E-6; VoxelShape voxelshape = Shapes.create(AABB.ofSize(vec3, d0, d1, d0)); + EntityDimensions finalEntitydimensions = entitydimensions1; this.level() - .findFreePosition(this, voxelshape, vec3, (double)entitydimensions1.width, (double)entitydimensions1.height, (double)entitydimensions1.width) -- .ifPresent(p_185956_ -> this.setPos(p_185956_.add(0.0, (double)(-entitydimensions1.height) / 2.0, 0.0))); -+ .ifPresent(p_185956_ -> this.setPos(p_185956_.add(0.0, (double)(-finalEntitydimensions.height) / 2.0, 0.0))); + .findFreePosition( + this, voxelshape, vec3, (double)entitydimensions1.width(), (double)entitydimensions1.height(), (double)entitydimensions1.width() + ) +- .ifPresent(p_315932_ -> this.setPos(p_315932_.add(0.0, (double)(-entitydimensions1.height()) / 2.0, 0.0))); ++ .ifPresent(p_315932_ -> this.setPos(p_315932_.add(0.0, (double)(-finalEntitydimensions.height()) / 2.0, 0.0))); } } -@@ -3076,9 +_,17 @@ +@@ -3084,9 +_,17 @@ this.yRotO = this.getYRot(); } @@ -423,7 +404,7 @@ } else { AABB aabb = this.getBoundingBox().deflate(0.001); int i = Mth.floor(aabb.minX); -@@ -3093,25 +_,36 @@ +@@ -3101,25 +_,36 @@ Vec3 vec3 = Vec3.ZERO; int k1 = 0; BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(); @@ -434,9 +415,9 @@ + } + it.unimi.dsi.fastutil.objects.Object2ObjectMap interimCalcs = null; - for(int l1 = i; l1 < j; ++l1) { - for(int i2 = k; i2 < l; ++i2) { - for(int j2 = i1; j2 < j1; ++j2) { + for (int l1 = i; l1 < j; l1++) { + for (int i2 = k; i2 < l; i2++) { + for (int j2 = i1; j2 < j1; j2++) { blockpos$mutableblockpos.set(l1, i2, j2); FluidState fluidstate = this.level().getFluidState(blockpos$mutableblockpos); - if (fluidstate.is(p_204032_)) { @@ -461,13 +442,13 @@ } - vec3 = vec3.add(vec31); -- ++k1; +- k1++; + interim.flowVector = interim.flowVector.add(vec31); + interim.blockCount++; } } } -@@ -3119,27 +_,30 @@ +@@ -3127,27 +_,30 @@ } } @@ -508,7 +489,7 @@ } } -@@ -3152,7 +_,10 @@ +@@ -3160,7 +_,10 @@ return !this.level().hasChunksAt(i, k, j, l); } @@ -519,7 +500,7 @@ return this.fluidHeight.getDouble(p_204037_); } -@@ -3289,6 +_,7 @@ +@@ -3297,6 +_,7 @@ this.levelCallback.onMove(); } @@ -527,35 +508,7 @@ } public void checkDespawn() { -@@ -3360,10 +_,27 @@ - return false; - } - -+ /** -+ * Gets the value of the legacy {@link #maxUpStep} field. Only used by players when the modified value causes issues. -+ * @deprecated Use {@link net.neoforged.neoforge.common.extensions.IEntityExtension#getStepHeight()} to get the real step height value. -+ */ -+ @Deprecated - public float maxUpStep() { - return this.maxUpStep; - } - -+ /** -+ * Changes the legacy {@link #maxUpStep} field. Only used by vanilla entities to improve maintainability. -+ *

-+ * For your own entities, you should change the default value of {@linkplain net.neoforged.neoforge.common.NeoForgeMod#STEP_HEIGHT NeoForgeMod#STEP_HEIGHT} -+ * during attribute creation. -+ *

-+ * For modifying the step height of other entities, you should use {@link net.minecraft.world.entity.ai.attributes.AttributeModifier AttributeModifiers} for -+ * {@link net.neoforged.neoforge.common.NeoForgeMod#STEP_HEIGHT NeoForgeMod#STEP_HEIGHT}. -+ * -+ * @deprecated Use attribute modifiers for the {@link net.neoforged.neoforge.common.NeoForgeMod#STEP_HEIGHT NeoForgeMod#STEP_HEIGHT} attribute. -+ */ -+ @Deprecated - public void setMaxUpStep(float p_275672_) { - this.maxUpStep = p_275672_; - } -@@ -3419,6 +_,126 @@ +@@ -3424,6 +_,126 @@ public boolean mayInteract(Level p_146843_, BlockPos p_146844_) { return true; } @@ -621,10 +574,10 @@ + + // no AT because of overrides + /** -+ * Accessor method for {@link #getEyeHeight(Pose, EntityDimensions)} ++ * Accessor method for {@link #getEyeHeight(Pose)} + */ -+ public float getEyeHeightAccess(Pose pose, EntityDimensions size) { -+ return this.getEyeHeight(pose, size); ++ public float getEyeHeightAccess(Pose pose) { ++ return this.getEyeHeight(pose); + } + + protected Object2DoubleMap forgeFluidTypeHeight = new Object2DoubleArrayMap<>(net.neoforged.neoforge.fluids.FluidType.SIZE.get()); diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index cd775137cc..dc1d222166 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java -@@ -119,14 +_,16 @@ - import net.minecraft.world.scores.PlayerTeam; +@@ -126,7 +_,7 @@ + import net.minecraft.world.scores.Scoreboard; import org.slf4j.Logger; -public abstract class LivingEntity extends Entity implements Attackable { @@ -9,47 +9,36 @@ private static final Logger LOGGER = LogUtils.getLogger(); private static final String TAG_ACTIVE_EFFECTS = "active_effects"; private static final UUID SPEED_MODIFIER_SOUL_SPEED_UUID = UUID.fromString("87f46a96-686f-4796-b035-22e16ee9e038"); - private static final UUID SPEED_MODIFIER_POWDER_SNOW_UUID = UUID.fromString("1eaf83ff-7207-4596-b37a-d7a07b3ec4ce"); -+ private static final UUID SLOW_FALLING_ID = UUID.fromString("A5B6CF2A-2F7C-31EF-9022-7C3E7D5E6ABA"); - private static final AttributeModifier SPEED_MODIFIER_SPRINTING = new AttributeModifier( - UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D"), "Sprinting speed boost", 0.3F, AttributeModifier.Operation.MULTIPLY_TOTAL - ); -+ private static final AttributeModifier SLOW_FALLING = new AttributeModifier(SLOW_FALLING_ID, "Slow falling acceleration reduction", -0.07, AttributeModifier.Operation.ADDITION); // Add -0.07 to 0.08 so we get the vanilla default of 0.01 - public static final int HAND_SLOTS = 2; - public static final int ARMOR_SLOTS = 4; - public static final int EQUIPMENT_SLOT_OFFSET = 98; -@@ -229,6 +_,7 @@ - private float swimAmountO; +@@ -242,6 +_,7 @@ protected Brain brain; private boolean skipDropExperience; + protected float appliedScale = 1.0F; + protected net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer damageContainer; protected LivingEntity(EntityType p_20966_, Level p_20967_) { super(p_20966_, p_20967_); -@@ -284,7 +_,11 @@ - .add(Attributes.MOVEMENT_SPEED) - .add(Attributes.ARMOR) - .add(Attributes.ARMOR_TOUGHNESS) -- .add(Attributes.MAX_ABSORPTION); -+ .add(Attributes.MAX_ABSORPTION) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED.value()) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.NAMETAG_DISTANCE.value()) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.ENTITY_GRAVITY.value()) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.STEP_HEIGHT.value()); +@@ -302,7 +_,9 @@ + .add(Attributes.GRAVITY) + .add(Attributes.SAFE_FALL_DISTANCE) + .add(Attributes.FALL_DAMAGE_MULTIPLIER) +- .add(Attributes.JUMP_STRENGTH); ++ .add(Attributes.JUMP_STRENGTH) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED) ++ .add(net.neoforged.neoforge.common.NeoForgeMod.NAMETAG_DISTANCE); } @Override -@@ -314,7 +_,8 @@ - float f = (float)Mth.ceil(this.fallDistance - 3.0F); - double d4 = Math.min((double)(0.2F + f / 15.0F), 2.5); - int i = (int)(150.0 * d4); -- ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_), d0, d1, d2, i, 0.0, 0.0, 0.0, 0.15F); -+ if (!p_20992_.addLandingEffects((ServerLevel) this.level(), p_20993_, p_20992_, this, i)) -+ ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_).setPos(p_20993_), d0, d1, d2, i, 0.0D, 0.0D, 0.0D, (double)0.15F); +@@ -331,7 +_,8 @@ + float f = (float)Mth.ceil((double)this.fallDistance - d0); + double d5 = Math.min((double)(0.2F + f / 15.0F), 2.5); + int i = (int)(150.0 * d5); +- ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_), d1, d2, d3, i, 0.0, 0.0, 0.0, 0.15F); ++ if (!p_20992_.addLandingEffects((ServerLevel) this.level(), p_20993_, p_20992_, this, i)) ++ ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_).setPos(p_20993_), d1, d2, d3, i, 0.0D, 0.0D, 0.0D, 0.15F); + } } - super.checkFallDamage(p_20990_, p_20991_, p_20992_, p_20993_); -@@ -323,6 +_,7 @@ +@@ -341,6 +_,7 @@ } } @@ -57,7 +46,7 @@ public final boolean canBreatheUnderwater() { return this.getType().is(EntityTypeTags.CAN_BREATHE_UNDER_WATER); } -@@ -364,6 +_,9 @@ +@@ -382,6 +_,9 @@ } } @@ -67,7 +56,7 @@ if (this.isEyeInFluid(FluidTags.WATER) && !this.level().getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) { boolean flag1 = !this.canBreatheUnderwater() -@@ -402,7 +_,7 @@ +@@ -420,7 +_,7 @@ } } @@ -76,29 +65,24 @@ this.extinguishFire(); } -@@ -776,7 +_,7 @@ - MobEffect mobeffect = iterator.next(); - MobEffectInstance mobeffectinstance = this.activeEffects.get(mobeffect); +@@ -813,7 +_,7 @@ + Holder holder = iterator.next(); + MobEffectInstance mobeffectinstance = this.activeEffects.get(holder); if (!mobeffectinstance.tick(this, () -> this.onEffectUpdated(mobeffectinstance, true, null))) { - if (!this.level().isClientSide) { + if (!this.level().isClientSide && !net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.living.MobEffectEvent.Expired(this, mobeffectinstance)).isCanceled()) { iterator.remove(); this.onEffectRemoved(mobeffectinstance); } -@@ -834,8 +_,10 @@ - this.setInvisible(false); - } else { - Collection collection = this.activeEffects.values(); -- this.entityData.set(DATA_EFFECT_AMBIENCE_ID, areAllEffectsAmbient(collection)); -- this.entityData.set(DATA_EFFECT_COLOR_ID, PotionUtils.getColor(collection)); -+ net.neoforged.neoforge.event.entity.living.PotionColorCalculationEvent event = new net.neoforged.neoforge.event.entity.living.PotionColorCalculationEvent(this, PotionUtils.getColor(collection), areAllEffectsAmbient(collection), collection); -+ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(event); -+ this.entityData.set(DATA_EFFECT_AMBIENCE_ID, event.areParticlesHidden()); -+ this.entityData.set(DATA_EFFECT_COLOR_ID, event.getColor()); - this.setInvisible(this.hasEffect(MobEffects.INVISIBILITY)); - } - } -@@ -874,6 +_,7 @@ +@@ -861,6 +_,7 @@ + .filter(MobEffectInstance::isVisible) + .map(MobEffectInstance::getParticleOptions) + .toList(); ++ // Porting 1.20.5 re-add or remove PotionColorCalculationEvent + this.entityData.set(DATA_EFFECT_PARTICLES, list); + this.entityData.set(DATA_EFFECT_AMBIENCE_ID, areAllEffectsAmbient(this.activeEffects.values())); + } +@@ -899,6 +_,7 @@ } } @@ -106,10 +90,10 @@ return d0; } -@@ -916,7 +_,9 @@ +@@ -940,7 +_,9 @@ boolean flag; - for(flag = false; iterator.hasNext(); flag = true) { + for (flag = false; iterator.hasNext(); flag = true) { - this.onEffectRemoved(iterator.next()); + MobEffectInstance effect = iterator.next(); + if(net.neoforged.neoforge.event.EventHooks.onEffectRemoved(this, effect, null)) continue; @@ -117,7 +101,7 @@ iterator.remove(); } -@@ -951,6 +_,7 @@ +@@ -975,6 +_,7 @@ } else { MobEffectInstance mobeffectinstance = this.activeEffects.get(p_147208_.getEffect()); boolean flag = false; @@ -125,25 +109,25 @@ if (mobeffectinstance == null) { this.activeEffects.put(p_147208_.getEffect(), p_147208_); this.onEffectAdded(p_147208_, p_147209_); -@@ -966,6 +_,9 @@ +@@ -991,6 +_,9 @@ } public boolean canBeAffected(MobEffectInstance p_21197_) { + net.neoforged.neoforge.event.entity.living.MobEffectEvent.Applicable event = new net.neoforged.neoforge.event.entity.living.MobEffectEvent.Applicable(this, p_21197_); + net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(event); + if (event.getResult() != net.neoforged.bus.api.Event.Result.DEFAULT) return event.getResult() == net.neoforged.bus.api.Event.Result.ALLOW; - if (this.getMobType() == MobType.UNDEAD) { - MobEffect mobeffect = p_21197_.getEffect(); - if (mobeffect == MobEffects.REGENERATION || mobeffect == MobEffects.POISON) { -@@ -997,6 +_,7 @@ + if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) { + return !p_21197_.is(MobEffects.INFESTED); + } else if (this.getType().is(EntityTypeTags.IMMUNE_TO_OOZING)) { +@@ -1024,6 +_,7 @@ } - public boolean removeEffect(MobEffect p_21196_) { -+ if (net.neoforged.neoforge.event.EventHooks.onEffectRemoved(this, p_21196_, null)) return false; - MobEffectInstance mobeffectinstance = this.removeEffectNoUpdate(p_21196_); + public boolean removeEffect(Holder p_316570_) { ++ if (net.neoforged.neoforge.event.EventHooks.onEffectRemoved(this, p_316570_, null)) return false; + MobEffectInstance mobeffectinstance = this.removeEffectNoUpdate(p_316570_); if (mobeffectinstance != null) { this.onEffectRemoved(mobeffectinstance); -@@ -1071,6 +_,8 @@ +@@ -1098,6 +_,8 @@ } public void heal(float p_21116_) { @@ -152,7 +136,7 @@ float f = this.getHealth(); if (f > 0.0F) { this.setHealth(f + p_21116_); -@@ -1100,18 +_,22 @@ +@@ -1127,23 +_,26 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { @@ -173,24 +157,19 @@ - p_21017_ = 0.0F; + net.neoforged.neoforge.event.entity.living.DamageBlockEvent ev; + if (p_21017_ > 0.0F && (ev = this.damageContainer.setBlockedDamage(net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_)))).getBlocked()) { -+ if(!ev.isCanceled()) { + if(ev.shieldDamage() > 0) this.hurtCurrentlyUsedShield(ev.shieldDamage()); + f1 = ev.getBlockedDamage(); + p_21017_ = ev.getDamageContainer().getNewDamage(); - if (!p_21016_.is(DamageTypeTags.IS_PROJECTILE)) { - Entity entity = p_21016_.getDirectEntity(); - if (entity instanceof LivingEntity livingentity) { -@@ -1119,7 +_,8 @@ - } + if (!p_21016_.is(DamageTypeTags.IS_PROJECTILE) && p_21016_.getDirectEntity() instanceof LivingEntity livingentity) { + this.blockUsingShield(livingentity); } - flag = true; + flag = p_21017_ <= 0; -+ } } if (p_21016_.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { -@@ -1138,7 +_,7 @@ +@@ -1167,7 +_,7 @@ flag1 = false; } else { this.lastHurt = p_21017_; @@ -199,19 +178,19 @@ this.actuallyHurt(p_21016_, p_21017_); this.hurtDuration = 10; this.hurtTime = this.hurtDuration; -@@ -1158,9 +_,9 @@ - if (entity1 instanceof Player player1) { +@@ -1184,9 +_,9 @@ + if (entity instanceof Player player1) { this.lastHurtByPlayerTime = 100; this.lastHurtByPlayer = player1; -- } else if (entity1 instanceof Wolf wolf && wolf.isTame()) { -+ } else if (entity1 instanceof TamableAnimal tamableAnimal && tamableAnimal.isTame()) { +- } else if (entity instanceof Wolf wolf && wolf.isTame()) { ++ } else if (entity instanceof TamableAnimal tamableAnimal && tamableAnimal.isTame()) { this.lastHurtByPlayerTime = 100; -- LivingEntity livingentity2 = wolf.getOwner(); -+ LivingEntity livingentity2 = tamableAnimal.getOwner(); - if (livingentity2 instanceof Player player) { +- if (wolf.getOwner() instanceof Player player) { ++ if (tamableAnimal.getOwner() instanceof Player player) { this.lastHurtByPlayer = player; } else { -@@ -1217,14 +_,14 @@ + this.lastHurtByPlayer = null; +@@ -1245,14 +_,14 @@ if (this instanceof ServerPlayer) { CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer)this, p_21016_, f, p_21017_, flag); if (f1 > 0.0F && f1 < 3.4028235E37F) { @@ -220,24 +199,24 @@ } } - if (entity1 instanceof ServerPlayer) { - CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)entity1, this, p_21016_, f, p_21017_, flag); + if (entity instanceof ServerPlayer) { + CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)entity, this, p_21016_, f, p_21017_, flag); } - + this.damageContainer = null; return flag2; } } -@@ -1245,7 +_,7 @@ +@@ -1273,7 +_,7 @@ - for(InteractionHand interactionhand : InteractionHand.values()) { + for (InteractionHand interactionhand : InteractionHand.values()) { ItemStack itemstack1 = this.getItemInHand(interactionhand); - if (itemstack1.is(Items.TOTEM_OF_UNDYING)) { + if (itemstack1.is(Items.TOTEM_OF_UNDYING) && net.neoforged.neoforge.common.CommonHooks.onLivingUseTotem(this, p_21263_, itemstack1, interactionhand)) { itemstack = itemstack1.copy(); itemstack1.shrink(1); break; -@@ -1254,13 +_,13 @@ +@@ -1282,13 +_,13 @@ if (itemstack != null) { if (this instanceof ServerPlayer serverplayer) { @@ -253,7 +232,7 @@ this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 900, 1)); this.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, 100, 1)); this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 800, 0)); -@@ -1328,6 +_,7 @@ +@@ -1359,6 +_,7 @@ } public void die(DamageSource p_21014_) { @@ -261,7 +240,7 @@ if (!this.isRemoved() && !this.dead) { Entity entity = p_21014_.getEntity(); LivingEntity livingentity = this.getKillCredit(); -@@ -1364,7 +_,7 @@ +@@ -1394,7 +_,7 @@ if (!this.level().isClientSide) { boolean flag = false; if (p_21269_ instanceof WitherBoss) { @@ -270,7 +249,7 @@ BlockPos blockpos = this.blockPosition(); BlockState blockstate = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level().getBlockState(blockpos).isAir() && blockstate.canSurvive(this.level(), blockpos)) { -@@ -1383,12 +_,9 @@ +@@ -1413,12 +_,9 @@ protected void dropAllDeathLoot(DamageSource p_21192_) { Entity entity = p_21192_.getEntity(); @@ -286,7 +265,7 @@ boolean flag = this.lastHurtByPlayerTime > 0; if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { -@@ -1398,6 +_,10 @@ +@@ -1428,6 +_,10 @@ this.dropEquipment(); this.dropExperience(); @@ -297,7 +276,7 @@ } protected void dropEquipment() { -@@ -1410,7 +_,8 @@ +@@ -1440,7 +_,8 @@ this.isAlwaysExperienceDropper() || this.lastHurtByPlayerTime > 0 && this.shouldDropExperience() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT) )) { @@ -307,7 +286,7 @@ } } -@@ -1444,6 +_,11 @@ +@@ -1474,6 +_,11 @@ } public void knockback(double p_147241_, double p_147242_, double p_147243_) { @@ -319,10 +298,10 @@ p_147241_ *= 1.0 - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); if (!(p_147241_ <= 0.0)) { this.hasImpulse = true; -@@ -1515,15 +_,9 @@ +@@ -1545,15 +_,9 @@ } else { BlockPos blockpos = this.blockPosition(); - BlockState blockstate = this.getFeetBlockState(); + BlockState blockstate = this.getInBlockState(); - if (blockstate.is(BlockTags.CLIMBABLE)) { - this.lastClimbablePos = Optional.of(blockpos); - return true; @@ -338,7 +317,7 @@ } } -@@ -1545,6 +_,11 @@ +@@ -1584,6 +_,11 @@ @Override public boolean causeFallDamage(float p_147187_, float p_147188_, DamageSource p_147189_) { @@ -350,7 +329,7 @@ boolean flag = super.causeFallDamage(p_147187_, p_147188_, p_147189_); int i = this.calculateFallDamage(p_147187_, p_147188_); if (i > 0) { -@@ -1572,9 +_,10 @@ +@@ -1611,9 +_,10 @@ int i = Mth.floor(this.getX()); int j = Mth.floor(this.getY() - 0.2F); int k = Mth.floor(this.getZ()); @@ -363,7 +342,16 @@ this.playSound(soundtype.getFallSound(), soundtype.getVolume() * 0.5F, soundtype.getPitch() * 0.75F); } } -@@ -1620,10 +_,11 @@ +@@ -1641,7 +_,7 @@ + protected void doHurtEquipment(DamageSource p_330843_, float p_330394_, EquipmentSlot... p_331314_) { + if (!(p_330394_ <= 0.0F)) { + int i = (int)Math.max(1.0F, p_330394_ / 4.0F); +- ++ net.neoforged.neoforge.common.CommonHooks.onArmorHurt(p_330843_, p_331314_, p_330394_, this); p_331314_ = new EquipmentSlot[0]; + for (EquipmentSlot equipmentslot : p_331314_) { + ItemStack itemstack = this.getItemBySlot(equipmentslot); + if (itemstack.getItem() instanceof ArmorItem && itemstack.canBeHurtBy(p_330843_)) { +@@ -1674,10 +_,11 @@ p_21194_ = Math.max(f / 25.0F, 0.0F); float f2 = f1 - p_21194_; if (f2 > 0.0F && f2 < 3.4028235E37F) { @@ -377,16 +365,15 @@ } } } -@@ -1636,20 +_,22 @@ - int k = EnchantmentHelper.getDamageProtection(this.getArmorSlots(), p_21193_); +@@ -1690,6 +_,7 @@ + int k = EnchantmentHelper.getDamageProtection(this.getArmorAndBodyArmorSlots(), p_21193_); if (k > 0) { p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, (float)k); + this.damageContainer.setEnchantReduction(this.damageContainer.getNewDamage() - p_21194_); } -- + return p_21194_; - } - } +@@ -1698,23 +_,26 @@ } protected void actuallyHurt(DamageSource p_21240_, float p_21241_) { @@ -404,11 +391,8 @@ + f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); + if (f1 <= 0) return; + float f = this.damageContainer.getNewDamage() - f1; - if (f > 0.0F && f < 3.4028235E37F) { - Entity entity = p_21240_.getEntity(); - if (entity instanceof ServerPlayer serverplayer) { -@@ -1657,13 +_,14 @@ - } + if (f > 0.0F && f < 3.4028235E37F && p_21240_.getEntity() instanceof ServerPlayer serverplayer) { + serverplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f * 10.0F)); } + net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); @@ -423,7 +407,7 @@ } public CombatTracker getCombatTracker() { -@@ -1716,6 +_,8 @@ +@@ -1767,6 +_,8 @@ } public void swing(InteractionHand p_21012_, boolean p_21013_) { @@ -432,7 +416,7 @@ if (!this.swinging || this.swingTime >= this.getCurrentSwingDuration() / 2 || this.swingTime < 0) { this.swingTime = -1; this.swinging = true; -@@ -1825,8 +_,10 @@ +@@ -1879,8 +_,10 @@ private void swapHandItems() { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.OFFHAND); @@ -445,11 +429,12 @@ } @Override -@@ -2018,14 +_,17 @@ - } +@@ -2077,15 +_,18 @@ + } - this.hasImpulse = true; -+ net.neoforged.neoforge.common.CommonHooks.onLivingJump(this); + this.hasImpulse = true; ++ net.neoforged.neoforge.common.CommonHooks.onLivingJump(this); + } } + @Deprecated // FORGE: use sinkInFluid instead @@ -461,23 +446,12 @@ + @Deprecated // FORGE: use jumpInFluid instead protected void jumpInLiquid(TagKey p_204043_) { - this.setDeltaMovement(this.getDeltaMovement().add(0.0, 0.04F, 0.0)); -+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, (double)0.04F * this.getAttribute(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED.value()).getValue(), 0.0D)); ++ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, (double)0.04F * this.getAttributeValue(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED), 0.0D)); } protected float getWaterSlowDown() { -@@ -2039,13 +_,18 @@ - public void travel(Vec3 p_21280_) { - if (this.isControlledByLocalInstance()) { - double d0 = 0.08; -+ AttributeInstance gravity = this.getAttribute(net.neoforged.neoforge.common.NeoForgeMod.ENTITY_GRAVITY.value()); - boolean flag = this.getDeltaMovement().y <= 0.0; - if (flag && this.hasEffect(MobEffects.SLOW_FALLING)) { -- d0 = 0.01; -+ if (!gravity.hasModifier(SLOW_FALLING)) gravity.addTransientModifier(SLOW_FALLING); -+ } else if (gravity.hasModifier(SLOW_FALLING)) { -+ gravity.removeModifier(SLOW_FALLING_ID); +@@ -2110,7 +_,8 @@ } -+ d0 = gravity.getValue(); FluidState fluidstate = this.level().getFluidState(this.blockPosition()); - if (this.isInWater() && this.isAffectedByFluids() && !this.canStandOnFluid(fluidstate)) { @@ -486,15 +460,15 @@ double d9 = this.getY(); float f4 = this.isSprinting() ? 0.9F : this.getWaterSlowDown(); float f5 = 0.02F; -@@ -2067,6 +_,7 @@ +@@ -2132,6 +_,7 @@ f4 = 0.96F; } -+ f5 *= (float)this.getAttribute(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED.value()).getValue(); ++ f5 *= (float)this.getAttributeValue(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED); this.moveRelative(f5, p_21280_); this.move(MoverType.SELF, this.getDeltaMovement()); Vec3 vec36 = this.getDeltaMovement(); -@@ -2080,6 +_,7 @@ +@@ -2145,6 +_,7 @@ if (this.horizontalCollision && this.isFree(vec32.x, vec32.y + 0.6F - this.getY() + d9, vec32.z)) { this.setDeltaMovement(vec32.x, 0.3F, vec32.z); } @@ -502,7 +476,7 @@ } else if (this.isInLava() && this.isAffectedByFluids() && !this.canStandOnFluid(fluidstate)) { double d8 = this.getY(); this.moveRelative(0.02F, p_21280_); -@@ -2142,7 +_,7 @@ +@@ -2207,7 +_,7 @@ } } else { BlockPos blockpos = this.getBlockPosBelowThatAffectsMyMovement(); @@ -511,16 +485,16 @@ float f3 = this.onGround() ? f2 * 0.91F : 0.91F; Vec3 vec35 = this.handleRelativeFrictionAndCalculateMovement(p_21280_, f2); double d2 = vec35.y; -@@ -2238,7 +_,7 @@ +@@ -2301,7 +_,7 @@ double d0 = Mth.clamp(p_21298_.x, -0.15F, 0.15F); double d1 = Mth.clamp(p_21298_.z, -0.15F, 0.15F); double d2 = Math.max(p_21298_.y, -0.15F); -- if (d2 < 0.0 && !this.getFeetBlockState().is(Blocks.SCAFFOLDING) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { -+ if (d2 < 0.0D && !this.getFeetBlockState().isScaffolding(this) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { +- if (d2 < 0.0 && !this.getInBlockState().is(Blocks.SCAFFOLDING) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { ++ if (d2 < 0.0D && !this.getInBlockState().isScaffolding(this) && this.isSuppressingSlidingDownLadder() && this instanceof Player) { d2 = 0.0; } -@@ -2271,6 +_,7 @@ +@@ -2334,6 +_,7 @@ @Override public void tick() { @@ -528,15 +502,15 @@ super.tick(); this.updatingUsingItem(); this.updateSwimAmount(); -@@ -2422,6 +_,7 @@ - +@@ -2483,6 +_,7 @@ + }; ItemStack itemstack1 = this.getItemBySlot(equipmentslot); if (this.equipmentHasChanged(itemstack, itemstack1)) { + net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.living.LivingEquipmentChangeEvent(this, equipmentslot, itemstack, itemstack1)); if (map == null) { map = Maps.newEnumMap(EquipmentSlot.class); } -@@ -2566,6 +_,9 @@ +@@ -2642,6 +_,9 @@ this.level().getProfiler().push("jump"); if (this.jumping && this.isAffectedByFluids()) { double d3; @@ -546,7 +520,7 @@ if (this.isInLava()) { d3 = this.getFluidHeight(FluidTags.LAVA); } else { -@@ -2576,15 +_,17 @@ +@@ -2652,15 +_,17 @@ double d4 = this.getFluidJumpThreshold(); if (!flag || this.onGround() && !(d3 > d4)) { if (!this.isInLava() || this.onGround() && !(d3 > d4)) { @@ -566,16 +540,16 @@ } } else { this.noJumpDelay = 0; -@@ -2650,6 +_,8 @@ +@@ -2725,6 +_,8 @@ boolean flag = this.getSharedFlag(7); if (flag && !this.onGround() && !this.isPassenger() && !this.hasEffect(MobEffects.LEVITATION)) { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.CHEST); + flag = itemstack.canElytraFly(this) && itemstack.elytraFlightTick(this, this.fallFlyTicks); -+ if (false) //Forge: Moved to ElytraItem ++ if (false) //Neo: Moved to ElytraItem if (itemstack.is(Items.ELYTRA) && ElytraItem.isFlyEnabled(itemstack)) { flag = true; int i = this.fallFlyTicks + 1; -@@ -2910,8 +_,11 @@ +@@ -2982,8 +_,11 @@ private void updatingUsingItem() { if (this.isUsingItem()) { @@ -589,12 +563,12 @@ this.updateUsingItem(this.useItem); } else { this.stopUsingItem(); -@@ -2920,19 +_,22 @@ +@@ -2992,12 +_,15 @@ } protected void updateUsingItem(ItemStack p_147201_) { + if (!p_147201_.isEmpty()) -+ this.useItemRemaining = net.neoforged.neoforge.event.EventHooks.onItemUseTick(this, p_147201_, this.getUseItemRemainingTicks()); ++ this.useItemRemaining = net.neoforged.neoforge.event.EventHooks.onItemUseTick(this, p_147201_, this.getUseItemRemainingTicks()); + if (this.getUseItemRemainingTicks() > 0) p_147201_.onUseTick(this.level(), this, this.getUseItemRemainingTicks()); if (this.shouldTriggerItemUseEffects()) { @@ -606,15 +580,7 @@ this.completeUsingItem(); } } - - private boolean shouldTriggerItemUseEffects() { - int i = this.getUseItemRemainingTicks(); -- FoodProperties foodproperties = this.useItem.getItem().getFoodProperties(); -+ FoodProperties foodproperties = this.useItem.getFoodProperties(this); - boolean flag = foodproperties != null && foodproperties.isFastFood(); - flag |= i <= this.useItem.getUseDuration() - 7; - return flag && i % 4 == 0; -@@ -2961,8 +_,10 @@ +@@ -3032,8 +_,10 @@ public void startUsingItem(InteractionHand p_21159_) { ItemStack itemstack = this.getItemInHand(p_21159_); if (!itemstack.isEmpty() && !this.isUsingItem()) { @@ -626,7 +592,7 @@ if (!this.level().isClientSide) { this.setLivingEntityFlag(1, true); this.setLivingEntityFlag(2, p_21159_ == InteractionHand.OFF_HAND); -@@ -3038,7 +_,8 @@ +@@ -3109,7 +_,8 @@ } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { this.triggerItemUseEffects(this.useItem, 16); @@ -636,7 +602,7 @@ if (itemstack != this.useItem) { this.setItemInHand(interactionhand, itemstack); } -@@ -3063,7 +_,11 @@ +@@ -3134,7 +_,11 @@ public void releaseUsingItem() { if (!this.useItem.isEmpty()) { @@ -648,7 +614,7 @@ if (this.useItem.useOnRelease()) { this.updatingUsingItem(); } -@@ -3073,6 +_,7 @@ +@@ -3144,6 +_,7 @@ } public void stopUsingItem() { @@ -656,16 +622,16 @@ if (!this.level().isClientSide) { boolean flag = this.isUsingItem(); this.setLivingEntityFlag(1, false); -@@ -3088,7 +_,7 @@ +@@ -3159,7 +_,7 @@ public boolean isBlocking() { if (this.isUsingItem() && !this.useItem.isEmpty()) { Item item = this.useItem.getItem(); -- if (item.getUseAnimation(this.useItem) != UseAnim.BLOCK) { -+ if (!this.useItem.canPerformAction(net.neoforged.neoforge.common.ToolActions.SHIELD_BLOCK)) { - return false; - } else { - return item.getUseDuration(this.useItem) - this.useItemRemaining >= 5; -@@ -3229,8 +_,8 @@ +- return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5; ++ return !this.useItem.canPerformAction(net.neoforged.neoforge.common.ToolActions.SHIELD_BLOCK) ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5; + } else { + return false; + } +@@ -3300,8 +_,8 @@ } BlockState blockstate = this.level().getBlockState(p_21141_); @@ -676,11 +642,11 @@ } this.setPose(Pose.SLEEPING); -@@ -3245,15 +_,17 @@ +@@ -3316,15 +_,17 @@ } private boolean checkBedExists() { -- return this.getSleepingPos().map(p_311581_ -> this.level().getBlockState(p_311581_).getBlock() instanceof BedBlock).orElse(false); +- return this.getSleepingPos().map(p_337701_ -> this.level().getBlockState(p_337701_).getBlock() instanceof BedBlock).orElse(false); + return this.getSleepingPos().map((p_289310_) -> { + return net.neoforged.neoforge.event.EventHooks.fireSleepingLocationCheck(this, p_289310_); + }).orElse(false); @@ -697,7 +663,7 @@ Vec3 vec31 = BedBlock.findStandUpPosition(this.getType(), this.level(), p_261435_, direction, this.getYRot()).orElseGet(() -> { BlockPos blockpos = p_261435_.above(); return new Vec3((double)blockpos.getX() + 0.5, (double)blockpos.getY() + 0.1, (double)blockpos.getZ() + 0.5); -@@ -3274,7 +_,9 @@ +@@ -3345,7 +_,9 @@ @Nullable public Direction getBedOrientation() { BlockPos blockpos = this.getSleepingPos().orElse(null); @@ -708,7 +674,7 @@ } @Override -@@ -3292,7 +_,7 @@ +@@ -3354,11 +_,11 @@ } public ItemStack getProjectile(ItemStack p_21272_) { @@ -717,17 +683,13 @@ } public ItemStack eat(Level p_21067_, ItemStack p_21068_) { -@@ -3321,7 +_,7 @@ - private void addEatEffect(ItemStack p_21064_, Level p_21065_, LivingEntity p_21066_) { - Item item = p_21064_.getItem(); - if (item.isEdible()) { -- for(Pair pair : item.getFoodProperties().getEffects()) { -+ for(Pair pair : p_21064_.getFoodProperties(this).getEffects()) { - if (!p_21065_.isClientSide && pair.getFirst() != null && p_21065_.random.nextFloat() < pair.getSecond()) { - p_21066_.addEffect(new MobEffectInstance(pair.getFirst())); - } -@@ -3356,6 +_,39 @@ - this.broadcastBreakEvent(p_21191_ == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND); +- FoodProperties foodproperties = p_21068_.get(DataComponents.FOOD); ++ FoodProperties foodproperties = p_21068_.getFoodProperties(this); + if (foodproperties != null) { + p_21067_.playSound( + null, +@@ -3408,6 +_,39 @@ + return p_320526_ == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND; } + /* ==== FORGE START ==== */ @@ -766,7 +728,7 @@ @Override public AABB getBoundingBoxForCulling() { if (this.getItemBySlot(EquipmentSlot.HEAD).is(Items.DRAGON_HEAD)) { -@@ -3367,6 +_,8 @@ +@@ -3419,6 +_,8 @@ } public static EquipmentSlot getEquipmentSlotForItem(ItemStack p_147234_) { @@ -775,7 +737,7 @@ Equipable equipable = Equipable.get(p_147234_); return equipable != null ? equipable.getEquipmentSlot() : EquipmentSlot.MAINHAND; } -@@ -3442,9 +_,14 @@ +@@ -3497,7 +_,7 @@ } public boolean canDisableShield() { @@ -783,11 +745,4 @@ + return this.getMainHandItem().canDisableShield(this.useItem, this, this); } -+ /** -+ * Gets the value of the legacy {@link #maxUpStep} field. -+ * @deprecated Use {@link #getStepHeight()} to get the real step height value. -+ */ -+ @Deprecated @Override - public float maxUpStep() { - float f = super.maxUpStep(); diff --git a/patches/net/minecraft/world/entity/player/Inventory.java.patch b/patches/net/minecraft/world/entity/player/Inventory.java.patch index 918da5ae93..661a168207 100644 --- a/patches/net/minecraft/world/entity/player/Inventory.java.patch +++ b/patches/net/minecraft/world/entity/player/Inventory.java.patch @@ -35,18 +35,3 @@ crashreportcategory.setDetail("Item ID", Item.getId(p_36042_.getItem())); crashreportcategory.setDetail("Item data", p_36042_.getDamageValue()); crashreportcategory.setDetail("Item name", () -> p_36042_.getHoverName().getString()); -@@ -497,12 +_,12 @@ - if (p_150074_ < 1.0F) { - p_150074_ = 1.0F; - } -- -+ net.neoforged.neoforge.common.CommonHooks.onArmorHurt(p_150073_, this.armor, p_150074_, this.player); p_150075_ = new int[0]; - for(int i : p_150075_) { - ItemStack itemstack = this.armor.get(i); - if ((!p_150073_.is(DamageTypeTags.IS_FIRE) || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { - itemstack.hurtAndBreak( -- (int)p_150074_, this.player, p_35997_ -> p_35997_.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, i)) -+ (int)p_150074_, this.player, p_35997_ -> p_35997_.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, i)) - ); - } - } diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index 620c20b69b..84a0b329f3 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -112,7 +_,8 @@ +@@ -114,7 +_,8 @@ import net.minecraft.world.scores.Team; import org.slf4j.Logger; @@ -8,32 +8,30 @@ +public abstract class Player extends LivingEntity implements net.neoforged.neoforge.common.extensions.IPlayerExtension { + public static final String PERSISTED_NBT_TAG = "PlayerPersisted"; private static final Logger LOGGER = LogUtils.getLogger(); - public static final int MAX_NAME_LENGTH = 16; public static final HumanoidArm DEFAULT_MAIN_HAND = HumanoidArm.RIGHT; -@@ -174,6 +_,9 @@ + public static final int DEFAULT_MODEL_CUSTOMIZATION = 0; +@@ -192,6 +_,9 @@ @Nullable - public FishingHook fishing; - protected float hurtDir; + public Entity currentExplosionCause; + public boolean ignoreFallDamageFromCurrentImpulse; + private final java.util.Collection prefixes = new java.util.LinkedList<>(); + private final java.util.Collection suffixes = new java.util.LinkedList<>(); + @Nullable private Pose forcedPose; public Player(Level p_250508_, BlockPos p_250289_, float p_251702_, GameProfile p_252153_) { super(EntityType.PLAYER, p_250508_); -@@ -206,7 +_,11 @@ - .add(Attributes.ATTACK_DAMAGE, 1.0) - .add(Attributes.MOVEMENT_SPEED, 0.1F) - .add(Attributes.ATTACK_SPEED) -- .add(Attributes.LUCK); -+ .add(Attributes.LUCK) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.BLOCK_REACH.value()) +@@ -224,7 +_,9 @@ + .add(Attributes.LUCK) + .add(Attributes.BLOCK_INTERACTION_RANGE, 4.5) + .add(Attributes.ENTITY_INTERACTION_RANGE, 3.0) +- .add(Attributes.BLOCK_BREAK_SPEED); ++ .add(Attributes.BLOCK_BREAK_SPEED) + .add(Attributes.ATTACK_KNOCKBACK) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.ENTITY_REACH.value()) -+ .add(net.neoforged.neoforge.common.NeoForgeMod.CREATIVE_FLIGHT.value()); ++ .add(net.neoforged.neoforge.common.NeoForgeMod.CREATIVE_FLIGHT); } @Override -@@ -222,6 +_,7 @@ +@@ -240,6 +_,7 @@ @Override public void tick() { @@ -41,7 +39,7 @@ this.noPhysics = this.isSpectator(); if (this.isSpectator()) { this.setOnGround(false); -@@ -237,7 +_,7 @@ +@@ -255,7 +_,7 @@ this.sleepCounter = 100; } @@ -50,7 +48,7 @@ this.stopSleepInBed(false, true); } } else if (this.sleepCounter > 0) { -@@ -292,6 +_,7 @@ +@@ -310,6 +_,7 @@ this.turtleHelmetTick(); this.cooldowns.tick(); this.updatePlayerPose(); @@ -58,7 +56,7 @@ } @Override -@@ -371,6 +_,10 @@ +@@ -389,6 +_,10 @@ } protected void updatePlayerPose() { @@ -69,7 +67,7 @@ if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) { Pose pose; if (this.isFallFlying()) { -@@ -613,6 +_,7 @@ +@@ -620,6 +_,7 @@ @Override public void die(DamageSource p_36152_) { @@ -77,7 +75,7 @@ super.die(p_36152_); this.reapplyPosition(); if (!this.isSpectator()) { -@@ -667,7 +_,7 @@ +@@ -674,7 +_,7 @@ @Nullable public ItemEntity drop(ItemStack p_36177_, boolean p_36178_) { @@ -86,7 +84,7 @@ } @Nullable -@@ -709,7 +_,12 @@ +@@ -716,7 +_,12 @@ } } @@ -99,7 +97,7 @@ float f = this.inventory.getDestroySpeed(p_36282_); if (f > 1.0F) { int i = EnchantmentHelper.getBlockEfficiency(this); -@@ -740,11 +_,12 @@ +@@ -748,11 +_,12 @@ f /= 5.0F; } @@ -113,7 +111,7 @@ } @Override -@@ -840,11 +_,13 @@ +@@ -860,11 +_,15 @@ if (this.isDeadOrDying()) { return false; } else { @@ -122,24 +120,24 @@ if (!this.level().isClientSide) { this.removeEntitiesOnShoulder(); } -- -- if (p_36154_.scalesWithDifficulty()) { + this.damageContainer.setNewDamage(Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, this.damageContainer.getNewDamage(), this.level().getDifficulty()))); ++ p_36155_ = Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, p_36155_, this.level().getDifficulty())); + +- if (p_36154_.scalesWithDifficulty()) { + if (false && p_36154_.scalesWithDifficulty()) { if (this.level().getDifficulty() == Difficulty.PEACEFUL) { p_36155_ = 0.0F; } -@@ -857,8 +_,7 @@ - p_36155_ = p_36155_ * 3.0F / 2.0F; +@@ -878,7 +_,7 @@ } } -- + - return p_36155_ == 0.0F ? false : super.hurt(p_36154_, p_36155_); + if (this.damageContainer.getNewDamage() == 0.0F) {this.damageContainer = null; return false;} else return super.hurt(p_36154_, this.damageContainer.getNewDamage()); } } } -@@ -898,7 +_,7 @@ +@@ -918,7 +_,7 @@ @Override protected void hurtCurrentlyUsedShield(float p_36383_) { @@ -148,20 +146,22 @@ if (!this.level().isClientSide) { this.awardStat(Stats.ITEM_USED.get(this.useItem.getItem())); } -@@ -906,7 +_,11 @@ +@@ -926,7 +_,13 @@ if (p_36383_ >= 3.0F) { int i = 1 + Mth.floor(p_36383_); InteractionHand interactionhand = this.getUsedItemHand(); -- this.useItem.hurtAndBreak(i, this, p_219739_ -> p_219739_.broadcastBreakEvent(interactionhand)); -+ this.useItem.hurtAndBreak(i, this, p_219739_ -> { -+ p_219739_.broadcastBreakEvent(interactionhand); -+ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, this.useItem, interactionhand); -+ stopUsingItem(); // Neo: Fix MC-168573 ("After breaking a shield, the player's off-hand can't finish using some items") -+ }); +- this.useItem.hurtAndBreak(i, this, getSlotForHand(interactionhand)); ++ if (!level().isClientSide && !hasInfiniteMaterials()) { ++ this.useItem.hurtAndBreak(i, getRandom(), this, () -> { ++ broadcastBreakEvent(getSlotForHand(interactionhand)); ++ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, this.useItem, interactionhand); ++ stopUsingItem(); // Neo: Fix MC-168573 ("After breaking a shield, the player's off-hand can't finish using some items") ++ }); ++ } if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -@@ -923,26 +_,27 @@ +@@ -943,12 +_,18 @@ @Override protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { @@ -171,45 +171,32 @@ - float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); - float f = p_36313_ - f1; -- if (f > 0.0F && f < 3.4028235E37F) { -- this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); -- } -- -- if (f1 != 0.0F) { -- this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); -- this.getCombatTracker().recordDamage(p_36312_, f1); -- this.setHealth(this.getHealth() - f1); -- if (f1 < 3.4028235E37F) { -- this.awardStat(Stats.DAMAGE_TAKEN, Math.round(f1 * 10.0F)); -- } -- -- this.gameEvent(GameEvent.ENTITY_DAMAGE); -- } -+ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); -+ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); -+ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); -+ if (f1 <= 0) return; -+ float f = this.damageContainer.getNewDamage() - f1; -+ if (f > 0.0F && f < 3.4028235E37F) { -+ this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); -+ } -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); -+ if (f1 != 0.0F) { -+ this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); -+ this.getCombatTracker().recordDamage(p_36312_, f1); -+ this.setHealth(this.getHealth() - f1); -+ if (f1 < 3.4028235E37F) { -+ this.awardStat(Stats.DAMAGE_TAKEN, Math.round(f1 * 10.0F)); -+ } -+ -+ this.gameEvent(GameEvent.ENTITY_DAMAGE); - } ++ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); ++ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ if (f1 <= 0) return; ++ float f = this.damageContainer.getNewDamage() - f1; ++ if (f > 0.0F && f < 3.4028235E37F) { ++ this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); ++ } ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); + if (f > 0.0F && f < 3.4028235E37F) { + this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); + } +@@ -962,8 +_,8 @@ + } + + this.gameEvent(GameEvent.ENTITY_DAMAGE); ++ this.onDamageTaken(this.damageContainer); + } +- } } -@@ -991,6 +_,8 @@ + @Override +@@ -1011,6 +_,8 @@ return InteractionResult.PASS; } else { @@ -218,7 +205,7 @@ ItemStack itemstack = this.getItemInHand(p_36159_); ItemStack itemstack1 = itemstack.copy(); InteractionResult interactionresult = p_36158_.interact(this, p_36159_); -@@ -999,6 +_,9 @@ +@@ -1019,6 +_,9 @@ itemstack.setCount(itemstack1.getCount()); } @@ -228,7 +215,7 @@ return interactionresult; } else { if (!itemstack.isEmpty() && p_36158_ instanceof LivingEntity) { -@@ -1010,6 +_,7 @@ +@@ -1030,6 +_,7 @@ if (interactionresult1.consumesAction()) { this.level().gameEvent(GameEvent.ENTITY_INTERACT, p_36158_.position(), GameEvent.Context.of(this)); if (itemstack.isEmpty() && !this.abilities.instabuild) { @@ -236,23 +223,23 @@ this.setItemInHand(p_36159_, ItemStack.EMPTY); } -@@ -1044,6 +_,7 @@ +@@ -1059,6 +_,7 @@ } @Override + // Forge: Don't update this method to use IForgeEntity#getStepHeight() - https://github.com/MinecraftForge/MinecraftForge/issues/8922 protected Vec3 maybeBackOffFromEdge(Vec3 p_36201_, MoverType p_36202_) { + float f = this.maxUpStep(); if (!this.abilities.flying - && p_36201_.y <= 0.0 -@@ -1098,6 +_,7 @@ - return p_36201_; +@@ -1108,6 +_,7 @@ + } } + // Forge: Don't update this method to use IForgeEntity#getStepHeight() - https://github.com/MinecraftForge/MinecraftForge/issues/9376 - private boolean isAboveGround() { - return this.onGround() - || this.fallDistance < this.maxUpStep() -@@ -1105,6 +_,7 @@ + private boolean isAboveGround(float p_341626_) { + return this.onGround() || this.fallDistance < p_341626_ && !this.canFallAtLeast(0.0, 0.0, p_341626_ - this.fallDistance); + } +@@ -1129,6 +_,7 @@ } public void attack(Entity p_36347_) { @@ -260,75 +247,78 @@ if (p_36347_.isAttackable()) { if (!p_36347_.skipAttackInteraction(this)) { float f = (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE); -@@ -1118,11 +_,10 @@ +@@ -1136,14 +_,13 @@ float f2 = this.getAttackStrengthScale(0.5F); f *= 0.2F + f2 * f2 * 0.8F; f1 *= f2; - this.resetAttackStrengthTicker(); - if (f > 0.0F || f1 > 0.0F) { - boolean flag = f2 > 0.9F; - boolean flag1 = false; -- int i = 0; -+ float i = (float)this.getAttributeValue(Attributes.ATTACK_KNOCKBACK); // Forge: Initialize this value to the attack knockback attribute of the player, which is by default 0 - i += EnchantmentHelper.getKnockbackBonus(this); - if (this.isSprinting() && flag) { - this.level() -@@ -1140,8 +_,10 @@ - && !this.isPassenger() - && p_36347_ instanceof LivingEntity; - flag2 = flag2 && !this.isSprinting(); -+ net.neoforged.neoforge.event.entity.player.CriticalHitEvent hitResult = net.neoforged.neoforge.common.CommonHooks.getCriticalHit(this, p_36347_, flag2, flag2 ? 1.5F : 1.0F); -+ flag2 = hitResult != null; - if (flag2) { -- f *= 1.5F; -+ f *= hitResult.getDamageModifier(); - } - - f += f1; -@@ -1149,9 +_,7 @@ - double d0 = (double)(this.walkDist - this.walkDistO); - if (flag && !flag2 && !flag1 && this.onGround() && d0 < (double)this.getSpeed()) { - ItemStack itemstack = this.getItemInHand(InteractionHand.MAIN_HAND); -- if (itemstack.getItem() instanceof SwordItem) { -- flag3 = true; -- } -+ flag3 = itemstack.canPerformAction(net.neoforged.neoforge.common.ToolActions.SWORD_SWEEP); - } + if (p_36347_.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && p_36347_ instanceof Projectile projectile) { + projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true); + } else { + if (f > 0.0F || f1 > 0.0F) { + boolean flag = f2 > 0.9F; + boolean flag1 = false; +- int i = 0; ++ float i = (float)this.getAttributeValue(Attributes.ATTACK_KNOCKBACK); // Forge: Initialize this value to the attack knockback attribute of the player, which is by default 0 + i += EnchantmentHelper.getKnockbackBonus(this); + if (this.isSprinting() && flag) { + this.level() +@@ -1162,8 +_,10 @@ + && !this.isPassenger() + && p_36347_ instanceof LivingEntity + && !this.isSprinting(); ++ net.neoforged.neoforge.event.entity.player.CriticalHitEvent hitResult = net.neoforged.neoforge.common.CommonHooks.getCriticalHit(this, p_36347_, flag2, flag2 ? 1.5F : 1.0F); ++ flag2 = hitResult != null; + if (flag2) { +- f *= 1.5F; ++ f *= hitResult.getDamageModifier(); + } - float f4 = 0.0F; -@@ -1193,11 +_,12 @@ - - for(LivingEntity livingentity : this.level() - .getEntitiesOfClass(LivingEntity.class, p_36347_.getBoundingBox().inflate(1.0, 0.25, 1.0))) { -+ double entityReachSq = Mth.square(this.getEntityReach()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. - if (livingentity != this - && livingentity != p_36347_ - && !this.isAlliedTo(livingentity) - && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).isMarker()) -- && this.distanceToSqr(livingentity) < 9.0) { -+ && this.distanceToSqr(livingentity) < entityReachSq) { - livingentity.knockback( - 0.4F, - (double)Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -@@ -1246,13 +_,15 @@ - EnchantmentHelper.doPostDamageEffects(this, p_36347_); - ItemStack itemstack1 = this.getMainHandItem(); - Entity entity = p_36347_; -- if (p_36347_ instanceof EnderDragonPart) { -- entity = ((EnderDragonPart)p_36347_).parentMob; -+ if (p_36347_ instanceof net.neoforged.neoforge.entity.PartEntity) { -+ entity = ((net.neoforged.neoforge.entity.PartEntity) p_36347_).getParent(); + f += f1; +@@ -1171,9 +_,7 @@ + double d0 = (double)(this.walkDist - this.walkDistO); + if (flag && !flag2 && !flag1 && this.onGround() && d0 < (double)this.getSpeed()) { + ItemStack itemstack = this.getItemInHand(InteractionHand.MAIN_HAND); +- if (itemstack.getItem() instanceof SwordItem) { +- flag3 = true; +- } ++ flag3 = itemstack.canPerformAction(net.neoforged.neoforge.common.ToolActions.SWORD_SWEEP); } - if (!this.level().isClientSide && !itemstack1.isEmpty() && entity instanceof LivingEntity) { -+ ItemStack copy = itemstack1.copy(); - itemstack1.hurtEnemy((LivingEntity)entity, this); - if (itemstack1.isEmpty()) { -+ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, copy, InteractionHand.MAIN_HAND); - this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); + float f4 = 0.0F; +@@ -1215,11 +_,12 @@ + + for (LivingEntity livingentity : this.level() + .getEntitiesOfClass(LivingEntity.class, p_36347_.getBoundingBox().inflate(1.0, 0.25, 1.0))) { ++ double entityReachSq = Mth.square(this.entityInteractionRange()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. + if (livingentity != this + && livingentity != p_36347_ + && !this.isAlliedTo(livingentity) + && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).isMarker()) +- && this.distanceToSqr(livingentity) < 9.0) { ++ && this.distanceToSqr(livingentity) < entityReachSq) { + livingentity.knockback( + 0.4F, + (double)Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), +@@ -1272,13 +_,15 @@ + EnchantmentHelper.doPostDamageEffects(this, p_36347_); + ItemStack itemstack1 = this.getMainHandItem(); + Entity entity = p_36347_; +- if (p_36347_ instanceof EnderDragonPart) { +- entity = ((EnderDragonPart)p_36347_).parentMob; ++ if (p_36347_ instanceof net.neoforged.neoforge.entity.PartEntity) { ++ entity = ((net.neoforged.neoforge.entity.PartEntity) p_36347_).getParent(); } - } -@@ -1280,6 +_,7 @@ + + if (!this.level().isClientSide && !itemstack1.isEmpty() && entity instanceof LivingEntity) { ++ ItemStack copy = itemstack1.copy(); + itemstack1.hurtEnemy((LivingEntity)entity, this); + if (itemstack1.isEmpty()) { ++ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, copy, InteractionHand.MAIN_HAND); + this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); + } + } +@@ -1309,6 +_,7 @@ } } } @@ -336,16 +326,16 @@ } } } -@@ -1296,7 +_,7 @@ - } +@@ -1319,7 +_,7 @@ + } - if (this.random.nextFloat() < f) { -- this.getCooldowns().addCooldown(Items.SHIELD, 100); -+ this.getCooldowns().addCooldown(this.getUseItem().getItem(), 100); - this.stopUsingItem(); - this.level().broadcastEntityEvent(this, (byte)30); - } -@@ -1358,6 +_,7 @@ + public void disableShield() { +- this.getCooldowns().addCooldown(Items.SHIELD, 100); ++ this.getCooldowns().addCooldown(this.getUseItem().getItem(), 100); + this.stopUsingItem(); + this.level().broadcastEntityEvent(this, (byte)30); + } +@@ -1385,6 +_,7 @@ } public void stopSleepInBed(boolean p_36226_, boolean p_36227_) { @@ -353,7 +343,7 @@ super.stopSleeping(); if (this.level() instanceof ServerLevel && p_36227_) { ((ServerLevel)this.level()).updateSleepingPlayerList(); -@@ -1390,7 +_,7 @@ +@@ -1417,7 +_,7 @@ } else if (block instanceof BedBlock && BedBlock.canSetSpawn(p_36131_)) { return BedBlock.findStandUpPosition(EntityType.PLAYER, p_36131_, p_36132_, blockstate.getValue(BedBlock.FACING), p_36133_); } else if (!p_36134_) { @@ -362,7 +352,7 @@ } else { boolean flag = block.isPossibleToRespawnInThis(blockstate); BlockState blockstate1 = p_36131_.getBlockState(p_36132_.above()); -@@ -1500,7 +_,8 @@ +@@ -1527,7 +_,8 @@ @Override public boolean causeFallDamage(float p_150093_, float p_150094_, DamageSource p_150095_) { @@ -372,7 +362,7 @@ return false; } else { if (p_150093_ >= 2.0F) { -@@ -1514,7 +_,7 @@ +@@ -1547,7 +_,7 @@ public boolean tryToStartFallFlying() { if (!this.onGround() && !this.isFallFlying() && !this.isInWater() && !this.hasEffect(MobEffects.LEVITATION)) { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.CHEST); @@ -381,7 +371,7 @@ this.startFallFlying(); return true; } -@@ -1543,13 +_,13 @@ +@@ -1576,13 +_,13 @@ protected void playStepSound(BlockPos p_282121_, BlockState p_282194_) { if (this.isInWater()) { this.waterSwimSound(); @@ -397,7 +387,7 @@ } else { super.playStepSound(blockpos, blockstate); } -@@ -1578,6 +_,10 @@ +@@ -1613,6 +_,10 @@ } public void giveExperiencePoints(int p_36291_) { @@ -406,9 +396,9 @@ + p_36291_ = event.getAmount(); + this.increaseScore(p_36291_); - this.experienceProgress += (float)p_36291_ / (float)this.getXpNeededForNextLevel(); + this.experienceProgress = this.experienceProgress + (float)p_36291_ / (float)this.getXpNeededForNextLevel(); this.totalExperience = Mth.clamp(this.totalExperience + p_36291_, 0, Integer.MAX_VALUE); -@@ -1605,7 +_,7 @@ +@@ -1640,7 +_,7 @@ } public void onEnchantmentPerformed(ItemStack p_36172_, int p_36173_) { @@ -417,7 +407,7 @@ if (this.experienceLevel < 0) { this.experienceLevel = 0; this.experienceProgress = 0.0F; -@@ -1616,6 +_,10 @@ +@@ -1651,6 +_,10 @@ } public void giveExperienceLevels(int p_36276_) { @@ -428,7 +418,7 @@ this.experienceLevel += p_36276_; if (this.experienceLevel < 0) { this.experienceLevel = 0; -@@ -1819,7 +_,11 @@ +@@ -1859,7 +_,11 @@ @Override public Component getDisplayName() { @@ -441,7 +431,7 @@ return this.decorateDisplayNameComponent(mutablecomponent); } -@@ -1966,25 +_,25 @@ +@@ -2024,25 +_,25 @@ Predicate predicate = ((ProjectileWeaponItem)p_36349_.getItem()).getSupportedHeldProjectiles(); ItemStack itemstack = ProjectileWeaponItem.getHeldProjectile(this, predicate); if (!itemstack.isEmpty()) { @@ -450,7 +440,7 @@ } else { predicate = ((ProjectileWeaponItem)p_36349_.getItem()).getAllSupportedProjectiles(); - for(int i = 0; i < this.inventory.getContainerSize(); ++i) { + for (int i = 0; i < this.inventory.getContainerSize(); i++) { ItemStack itemstack1 = this.inventory.getItem(i); if (predicate.test(itemstack1)) { - return itemstack1; @@ -466,12 +456,12 @@ @Override public ItemStack eat(Level p_36185_, ItemStack p_36186_) { -- this.getFoodData().eat(p_36186_.getItem(), p_36186_); -+ this.getFoodData().eat(p_36186_.getItem(), p_36186_, this); +- this.getFoodData().eat(p_36186_); ++ this.getFoodData().eat(p_36186_, this); this.awardStat(Stats.ITEM_USED.get(p_36186_.getItem())); p_36185_.playSound( null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, p_36185_.random.nextFloat() * 0.1F + 0.9F -@@ -2108,5 +_,39 @@ +@@ -2186,5 +_,39 @@ public Component getMessage() { return this.message; } diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 46fdd7299d..120a6421a2 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -10,6 +10,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import com.google.gson.JsonObject; import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -43,36 +44,28 @@ import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; -import net.minecraft.core.HolderLookup.RegistryLookup; import net.minecraft.core.HolderSet; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponents; -import net.minecraft.core.NonNullList; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; import net.minecraft.network.chat.ChatDecorator; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.TextColor; import net.minecraft.network.chat.contents.PlainTextContents; +import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.packs.PackType; import net.minecraft.stats.Stats; import net.minecraft.tags.BlockTags; -import net.minecraft.tags.DamageTypeTags; import net.minecraft.tags.TagEntry; import net.minecraft.tags.TagKey; import net.minecraft.util.CrudeIncrementalIntIdentityHashBiMap; @@ -84,7 +77,6 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffectUtil; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -96,10 +88,8 @@ import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.DefaultAttributes; -import net.minecraft.world.entity.ai.village.poi.PoiManager; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.monster.EnderMan; -import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AnvilMenu; import net.minecraft.world.inventory.ClickAction; @@ -119,9 +109,11 @@ import net.minecraft.world.item.alchemy.Potion; import net.minecraft.world.item.alchemy.PotionContents; import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.item.enchantment.ItemEnchantments; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; @@ -130,12 +122,9 @@ import net.minecraft.world.level.biome.MobSpawnSettings; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.GameMasterBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; @@ -150,17 +139,16 @@ import net.minecraft.world.phys.Vec3; import net.neoforged.fml.ModList; import net.neoforged.fml.ModLoader; -import net.neoforged.fml.i18n.MavenVersionTranslator; -import net.neoforged.fml.loading.FMLEnvironment; -import net.neoforged.neoforge.client.ClientHooks; import net.neoforged.neoforge.common.conditions.ConditionalOps; import net.neoforged.neoforge.common.damagesource.DamageContainer; import net.neoforged.neoforge.common.extensions.IEntityExtension; +import net.neoforged.neoforge.common.extensions.IItemStackExtension; import net.neoforged.neoforge.common.loot.IGlobalLootModifier; import net.neoforged.neoforge.common.loot.LootModifierManager; import net.neoforged.neoforge.common.loot.LootTableIdCondition; import net.neoforged.neoforge.common.util.BlockSnapshot; import net.neoforged.neoforge.common.util.Lazy; +import net.neoforged.neoforge.common.util.MavenVersionStringHelper; import net.neoforged.neoforge.event.AnvilUpdateEvent; import net.neoforged.neoforge.event.DifficultyChangeEvent; import net.neoforged.neoforge.event.EventHooks; @@ -200,14 +188,11 @@ import net.neoforged.neoforge.event.entity.player.CriticalHitEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; -import net.neoforged.neoforge.event.level.BlockDropsEvent; import net.neoforged.neoforge.event.level.BlockEvent; import net.neoforged.neoforge.event.level.NoteBlockEvent; -import net.neoforged.neoforge.event.level.block.CropGrowEvent; import net.neoforged.neoforge.fluids.FluidType; import net.neoforged.neoforge.registries.NeoForgeRegistries; import net.neoforged.neoforge.resource.ResourcePackLoader; -import net.neoforged.neoforge.server.ServerLifecycleHooks; import net.neoforged.neoforge.server.permission.PermissionAPI; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -232,6 +217,13 @@ public static boolean canContinueUsing(ItemStack from, ItemStack to) { return false; } + public static boolean isCorrectToolForDrops(BlockState state, Player player) { + if (!state.requiresCorrectToolForDrops()) + return EventHooks.doPlayerHarvestCheck(player, state, true); + + return player.hasCorrectToolForDrops(state); + } + public static boolean onItemStackedOn(ItemStack carriedItem, ItemStack stackedOnItem, Slot slot, ClickAction action, Player player, SlotAccess carriedSlotAccess) { return NeoForge.EVENT_BUS.post(new ItemStackedOnOtherEvent(carriedItem, stackedOnItem, slot, action, player, carriedSlotAccess)).isCanceled(); } @@ -281,27 +273,26 @@ public static void onLivingDamageTaken(LivingEntity entity, DamageContainer cont NeoForge.EVENT_BUS.post(new DamageTakenEvent(entity, new DamageContainer.ResultDamageContainer(container))); } - public static void onArmorHurt(DamageSource source, NonNullList armor, float damage, Player player) { + public static void onArmorHurt(DamageSource source, EquipmentSlot[] slots, float damage, LivingEntity armoredEntity) { EnumMap armorMap = new EnumMap<>(EquipmentSlot.class); - for (int index : Inventory.ALL_ARMOR_SLOTS) { - ItemStack armorPiece = armor.get(index); + for (EquipmentSlot slot : slots) { + ItemStack armorPiece = armoredEntity.getItemBySlot(slot); if (armorPiece.isEmpty()) continue; - float damageAfterFireResist = ((!source.is(DamageTypeTags.IS_FIRE) || !armorPiece.getItem().isFireResistant()) && armorPiece.getItem() instanceof ArmorItem) ? damage : 0; - EquipmentSlot slot = EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index); + float damageAfterFireResist = (armorPiece.getItem() instanceof ArmorItem && armorPiece.canBeHurtBy(source)) ? damage : 0; armorMap.put(slot, new ArmorHurtEvent.ArmorEntry(armorPiece, damageAfterFireResist)); } - ArmorHurtEvent event = NeoForge.EVENT_BUS.post(new ArmorHurtEvent(armorMap, player)); + ArmorHurtEvent event = NeoForge.EVENT_BUS.post(new ArmorHurtEvent(armorMap, armoredEntity)); if (event.isCanceled()) return; - event.getArmorMap().forEach((slot, entry) -> entry.armorItemStack.hurtAndBreak((int) entry.newDamage, player, p_35997_ -> p_35997_.broadcastBreakEvent(slot))); + event.getArmorMap().forEach((slot, entry) -> entry.armorItemStack.hurtAndBreak((int) entry.newDamage, armoredEntity, slot)); } public static boolean onLivingDeath(LivingEntity entity, DamageSource src) { return NeoForge.EVENT_BUS.post(new LivingDeathEvent(entity, src)).isCanceled(); } - public static boolean onLivingDrops(LivingEntity entity, DamageSource source, Collection drops, boolean recentlyHit) { - return NeoForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, recentlyHit)).isCanceled(); + public static boolean onLivingDrops(LivingEntity entity, DamageSource source, Collection drops, int lootingLevel, boolean recentlyHit) { + return NeoForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, lootingLevel, recentlyHit)).isCanceled(); } @Nullable @@ -310,6 +301,21 @@ public static float[] onLivingFall(LivingEntity entity, float distance, float da return (NeoForge.EVENT_BUS.post(event).isCanceled() ? null : new float[] { event.getDistance(), event.getDamageMultiplier() }); } + public static int getLootingLevel(Entity target, @Nullable Entity killer, @Nullable DamageSource cause) { + int looting = 0; + if (killer instanceof LivingEntity) + looting = EnchantmentHelper.getMobLooting((LivingEntity) killer); + if (target instanceof LivingEntity) + looting = getLootingLevel((LivingEntity) target, cause, looting); + return looting; + } + + public static int getLootingLevel(LivingEntity target, @Nullable DamageSource cause, int level) { + LootingLevelEvent event = new LootingLevelEvent(target, cause, level); + NeoForge.EVENT_BUS.post(event); + return event.getLootingLevel(); + } + public static double getEntityVisibilityMultiplier(LivingEntity entity, Entity lookingEntity, double originalMultiplier) { LivingEvent.LivingVisibilityEvent event = new LivingEvent.LivingVisibilityEvent(entity, lookingEntity, originalMultiplier); NeoForge.EVENT_BUS.post(event); @@ -460,72 +466,60 @@ else if (end.length() > 0) return ichat; } - /** - * Fires the {@link BlockDropsEvent} when block drops (items and experience) are determined. - * If the event is not cancelled, all drops will be added to the world, and then {@link BlockBehaviour#spawnAfterBreak} will be called. - * - * @param level The level - * @param pos The broken block's position - * @param state The broken block's state - * @param blockEntity The block entity from the given position - * @param drops The list of all items dropped by the block, captured from {@link Block#getDrops} - * @param breaker The entity who broke the block, or null if unknown - * @param tool The tool used when breaking the block; may be empty - */ - public static void handleBlockDrops(ServerLevel level, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, List drops, @Nullable Entity breaker, ItemStack tool) { - BlockDropsEvent event = new BlockDropsEvent(level, pos, state, blockEntity, drops, breaker, tool); - NeoForge.EVENT_BUS.post(event); - if (!event.isCanceled()) { - for (ItemEntity entity : event.getDrops()) { - level.addFreshEntity(entity); - } - // Always pass false for the dropXP (last) param to spawnAfterBreak since we handle XP. - state.spawnAfterBreak((ServerLevel) level, pos, tool, false); - if (event.getDroppedExperience() > 0) { - state.getBlock().popExperience(level, pos, event.getDroppedExperience()); - } - } + public static void dropXpForBlock(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack) { + int fortuneLevel = stack.getEnchantmentLevel(Enchantments.FORTUNE); + int silkTouchLevel = stack.getEnchantmentLevel(Enchantments.SILK_TOUCH); + int exp = state.getExpDrop(level, level.random, pos, fortuneLevel, silkTouchLevel); + if (exp > 0) + state.getBlock().popExperience(level, pos, exp); } - /** - * Fires {@link BlockEvent.BreakEvent}, pre-emptively canceling the event based on the conditions that will cause the block to not be broken anyway. - *

- * Note that undoing the pre-cancel will not permit breaking the block, since the vanilla conditions will always be checked. - * - * @param level The level - * @param gameType The game type of the breaking player - * @param player The breaking player - * @param pos The position of the block being broken - * @param state The state of the block being broken - * @return The event - */ - public static BlockEvent.BreakEvent fireBlockBreak(Level level, GameType gameType, ServerPlayer player, BlockPos pos, BlockState state) { + public static int onBlockBreakEvent(Level level, GameType gameType, ServerPlayer entityPlayer, BlockPos pos) { + // Logic from tryHarvestBlock for pre-canceling the event boolean preCancelEvent = false; - - ItemStack itemstack = player.getMainHandItem(); - if (!itemstack.isEmpty() && !itemstack.getItem().canAttackBlock(state, level, pos, player)) { + ItemStack itemstack = entityPlayer.getMainHandItem(); + if (!itemstack.isEmpty() && !itemstack.getItem().canAttackBlock(level.getBlockState(pos), level, pos, entityPlayer)) { preCancelEvent = true; } - if (player.blockActionRestricted(level, pos, gameType)) { - preCancelEvent = true; + if (gameType.isBlockPlacingRestricted()) { + if (gameType == GameType.SPECTATOR) + preCancelEvent = true; + + if (!entityPlayer.mayBuild()) { + AdventureModePredicate adventureModePredicate = itemstack.get(DataComponents.CAN_BREAK); + if (itemstack.isEmpty() || adventureModePredicate == null || !adventureModePredicate.test(new BlockInWorld(level, pos, false))) { + preCancelEvent = true; + } + } } - if (state.getBlock() instanceof GameMasterBlock && !player.canUseGameMasterBlocks()) { - preCancelEvent = true; + // Tell client the block is gone immediately then process events + if (level.getBlockEntity(pos) == null) { + entityPlayer.connection.send(new ClientboundBlockUpdatePacket(pos, level.getFluidState(pos).createLegacyBlock())); } // Post the block break event - BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(level, pos, state, player); + BlockState state = level.getBlockState(pos); + BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(level, pos, state, entityPlayer); event.setCanceled(preCancelEvent); NeoForge.EVENT_BUS.post(event); - // If the event is canceled, let the client know the block still exists + // Handle if the event is canceled if (event.isCanceled()) { - player.connection.send(new ClientboundBlockUpdatePacket(pos, state)); + // Let the client know the block still exists + entityPlayer.connection.send(new ClientboundBlockUpdatePacket(level, pos)); + + // Update any tile entity data for this block + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity != null) { + Packet pkt = blockEntity.getUpdatePacket(); + if (pkt != null) { + entityPlayer.connection.send(pkt); + } + } } - - return event; + return event.isCanceled() ? -1 : event.getExpToDrop(); } public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { @@ -536,14 +530,17 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { if (player != null && !player.getAbilities().mayBuild) { AdventureModePredicate adventureModePredicate = itemstack.get(DataComponents.CAN_PLACE_ON); if (adventureModePredicate == null || !adventureModePredicate.test(new BlockInWorld(level, context.getClickedPos(), false))) { - return InteractionResult.PASS; + return net.minecraft.world.InteractionResult.PASS; } } // handle all placement events here Item item = itemstack.getItem(); int size = itemstack.getCount(); - DataComponentMap components = itemstack.getComponents(); + // Porting 1.20.5 redo this for components? + //CompoundTag nbt = null; + //if (itemstack.getTag() != null) + // nbt = itemstack.getTag().copy(); if (!(itemstack.getItem() instanceof BucketItem)) // if not bucket level.captureBlockSnapshots = true; @@ -558,14 +555,17 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { if (ret.consumesAction()) { // save new item data int newSize = itemstack.getCount(); - DataComponentMap newComponents = itemstack.getComponents(); + //CompoundTag newNBT = null; + //if (itemstack.getTag() != null) { + // newNBT = itemstack.getTag().copy(); + //} @SuppressWarnings("unchecked") List blockSnapshots = (List) level.capturedBlockSnapshots.clone(); level.capturedBlockSnapshots.clear(); // make sure to set pre-placement item data for event itemstack.setCount(size); - itemstack.applyComponents(components); + //itemstack.setTag(nbt); //TODO: Set pre-placement item attachments? Direction side = context.getClickedFace(); @@ -582,17 +582,17 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { // revert back all captured blocks for (BlockSnapshot blocksnapshot : Lists.reverse(blockSnapshots)) { level.restoringBlockSnapshots = true; - blocksnapshot.restore(blocksnapshot.getFlags() | Block.UPDATE_CLIENTS); + blocksnapshot.restore(true, false); level.restoringBlockSnapshots = false; } } else { // Change the stack to its new content itemstack.setCount(newSize); - itemstack.applyComponents(newComponents); + //itemstack.setTag(newNBT); for (BlockSnapshot snap : blockSnapshots) { - int updateFlag = snap.getFlags(); - BlockState oldBlock = snap.getState(); + int updateFlag = snap.getFlag(); + BlockState oldBlock = snap.getReplacedBlock(); BlockState newBlock = level.getBlockState(snap.getPos()); newBlock.onPlace(level, snap.getPos(), oldBlock, false); @@ -719,6 +719,14 @@ public static InteractionResult onItemRightClick(Player player, InteractionHand return evt.isCanceled() ? evt.getCancellationResult() : null; } + /** + * @deprecated Use {@link #onLeftClickBlock(Player, BlockPos, Direction, ServerboundPlayerActionPacket.Action)} instead + */ + @Deprecated(since = "1.20.1", forRemoval = true) + public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(Player player, BlockPos pos, Direction face) { + return onLeftClickBlock(player, pos, face, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK); + } + public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(Player player, BlockPos pos, Direction face, ServerboundPlayerActionPacket.Action action) { PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face, PlayerInteractEvent.LeftClickBlock.Action.convert(action)); NeoForge.EVENT_BUS.post(evt); @@ -819,35 +827,24 @@ public interface BiomeCallbackFunction { Biome apply(final Biome.ClimateSettings climate, final BiomeSpecialEffects effects, final BiomeGenerationSettings gen, final MobSpawnSettings spawns); } - /** - * Checks if a crop can grow by firing {@link CropGrowEvent.Pre}. - * - * @param level The level the crop is in - * @param pos The position of the crop - * @param state The state of the crop - * @param def The result of the default checks performed by the crop. - * @return true if the crop can grow - */ - public static boolean canCropGrow(Level level, BlockPos pos, BlockState state, boolean def) { - var ev = new CropGrowEvent.Pre(level, pos, state); + public static boolean onCropsGrowPre(Level level, BlockPos pos, BlockState state, boolean def) { + BlockEvent ev = new BlockEvent.CropGrowEvent.Pre(level, pos, state); NeoForge.EVENT_BUS.post(ev); - return (ev.getResult() == CropGrowEvent.Pre.Result.GROW || (ev.getResult() == CropGrowEvent.Pre.Result.DEFAULT && def)); + return (ev.getResult() == net.neoforged.bus.api.Event.Result.ALLOW || (ev.getResult() == net.neoforged.bus.api.Event.Result.DEFAULT && def)); } - public static void fireCropGrowPost(Level level, BlockPos pos, BlockState state) { - NeoForge.EVENT_BUS.post(new CropGrowEvent.Post(level, pos, state, level.getBlockState(pos))); + public static void onCropsGrowPost(Level level, BlockPos pos, BlockState state) { + NeoForge.EVENT_BUS.post(new BlockEvent.CropGrowEvent.Post(level, pos, state, level.getBlockState(pos))); } - /** - * Fires the {@link CriticalHitEvent} and returns the resulting event. - * - * @param player The attacking player - * @param target The attack target - * @param vanillaCritical If the attack would have been a critical hit by vanilla's rules in {@link Player#attack(Entity)}. - * @param damageModifier The base damage modifier. Vanilla critical hits have a damage modifier of 1.5. - */ - public static CriticalHitEvent fireCriticalHit(Player player, Entity target, boolean vanillaCritical, float damageModifier) { - return NeoForge.EVENT_BUS.post(new CriticalHitEvent(player, target, damageModifier, vanillaCritical)); + @Nullable + public static CriticalHitEvent getCriticalHit(Player player, Entity target, boolean vanillaCritical, float damageModifier) { + CriticalHitEvent hitResult = new CriticalHitEvent(player, target, damageModifier, vanillaCritical); + NeoForge.EVENT_BUS.post(hitResult); + if (hitResult.getResult() == net.neoforged.bus.api.Event.Result.ALLOW || (vanillaCritical && hitResult.getResult() == net.neoforged.bus.api.Event.Result.DEFAULT)) { + return hitResult; + } + return null; } /** @@ -919,6 +916,9 @@ public static int onNoteChange(Level level, BlockPos pos, BlockState state, int return event.getVanillaNoteId(); } + @Deprecated(forRemoval = true, since = "1.20.1") // Tags use a codec now This was never used in 1.20 + public static void deserializeTagAdditions(List list, JsonObject json, List allList) {} + public static final int VANILLA_SERIALIZER_LIMIT = 256; @Nullable @@ -945,7 +945,17 @@ public static boolean canEntityDestroy(Level level, BlockPos pos, LivingEntity e if (!level.isLoaded(pos)) return false; BlockState state = level.getBlockState(pos); - return EventHooks.canEntityGrief(level, entity) && state.canEntityDestroy(level, pos, entity) && EventHooks.onEntityDestroyBlock(entity, pos, state); + return EventHooks.getMobGriefingEvent(level, entity) && state.canEntityDestroy(level, pos, entity) && EventHooks.onEntityDestroyBlock(entity, pos, state); + } + + /** + * Gets the burn time of this item stack. + * + * @deprecated Use {@link IItemStackExtension#getBurnTime(RecipeType)} instead. + */ + @Deprecated(forRemoval = true, since = "1.20.5") + public static int getBurnTime(ItemStack stack, @Nullable RecipeType recipeType) { + return stack.getBurnTime(recipeType); } /** @@ -988,7 +998,7 @@ public static ObjectArrayList modifyLoot(ResourceLocation lootTableId } public static List getModDataPacks() { - List modpacks = ResourcePackLoader.getPackNames(PackType.SERVER_DATA); + List modpacks = ResourcePackLoader.getDataPackNames(); if (modpacks.isEmpty()) throw new IllegalStateException("Attempted to retrieve mod packs before they were loaded in!"); return modpacks; @@ -1050,7 +1060,7 @@ public static void writeAdditionalLevelSaveData(WorldData worldData, CompoundTag ModList.get().getMods().forEach(mi -> { final CompoundTag mod = new CompoundTag(); mod.putString("ModId", mi.getModId()); - mod.putString("ModVersion", MavenVersionTranslator.artifactVersionToString(mi.getVersion())); + mod.putString("ModVersion", MavenVersionStringHelper.artifactVersionToString(mi.getVersion())); modList.add(mod); }); fmlData.put("LoadingModList", modList); @@ -1067,7 +1077,7 @@ public static void writeAdditionalLevelSaveData(WorldData worldData, CompoundTag public static void readAdditionalLevelSaveData(CompoundTag rootTag, LevelStorageSource.LevelDirectory levelDirectory) { CompoundTag tag = rootTag.getCompound("fml"); if (tag.contains("LoadingModList")) { - ListTag modList = tag.getList("LoadingModList", Tag.TAG_COMPOUND); + ListTag modList = tag.getList("LoadingModList", net.minecraft.nbt.Tag.TAG_COMPOUND); Map mismatchedVersions = new HashMap<>(modList.size()); Map missingVersions = new HashMap<>(modList.size()); for (int i = 0; i < modList.size(); i++) { @@ -1168,7 +1178,7 @@ public static MobEffect loadMobEffect(CompoundTag nbt, String key, @Nullable Mob return fallback; } try { - return BuiltInRegistries.MOB_EFFECT.get(ResourceLocation.parse(registryName)); + return BuiltInRegistries.MOB_EFFECT.get(new ResourceLocation(registryName)); } catch (ResourceLocationException e) { return fallback; } @@ -1178,7 +1188,7 @@ public static boolean shouldSuppressEnderManAnger(EnderMan enderMan, Player play return mask.isEnderMask(player, enderMan) || NeoForge.EVENT_BUS.post(new EnderManAngerEvent(enderMan, player)).isCanceled(); } - private static final Lazy> FORGE_CONVERSION_MAP = Lazy.of(() -> { + private static final Lazy> FORGE_CONVERSION_MAP = Lazy.concurrentOf(() -> { Map map = new HashMap<>(); NeoForge.EVENT_BUS.post(new RegisterStructureConversionsEvent(map)); return ImmutableMap.copyOf(map); @@ -1327,12 +1337,11 @@ public static void markComponentClassAsValid(Class clazz) { static { // Mark common singletons as valid + markComponentClassAsValid(Block.class); markComponentClassAsValid(BlockState.class); + markComponentClassAsValid(Fluid.class); markComponentClassAsValid(FluidState.class); - // Block, Fluid, Item, etc. are handled via the registry check further down - - // Mark common interned classes as valid - markComponentClassAsValid(ResourceKey.class); + markComponentClassAsValid(Item.class); } /** @@ -1353,28 +1362,10 @@ public static void validateComponent(@Nullable Object dataComponent) { if (overridesEqualsAndHashCode(clazz)) { checkedComponentClasses.add(clazz); - return; - } - - // By far the slowest check: Is this a registry object? - // If it is, we assume it must be usable as a singleton... - if (isPotentialRegistryObject(dataComponent)) { - checkedComponentClasses.add(clazz); - return; - } - - throw new IllegalArgumentException("Data components must implement equals and hashCode. Keep in mind they must also be immutable. Problematic class: " + clazz); - } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private static boolean isPotentialRegistryObject(Object value) { - for (Registry registry : BuiltInRegistries.REGISTRY) { - if (registry.containsValue(value)) { - return true; + } else { + throw new IllegalArgumentException("Data components must implement equals and hashCode. Keep in mind they must also be immutable. Problematic class: " + clazz); } } - return false; } private static boolean overridesEqualsAndHashCode(Class clazz) { @@ -1386,54 +1377,4 @@ private static boolean overridesEqualsAndHashCode(Class clazz) { throw new RuntimeException("Failed to check for component equals and hashCode", exception); } } - - /** - * The goal here is to fix the POI memory leak that happens due to - * {@link net.minecraft.world.level.chunk.storage.SectionStorage#storage} field never - * actually removing POIs long after they become irrelevant. We do it here in chunk unload event - * so that chunk that are fully unloaded now gets the POI removed from the POI cached storage map. - */ - public static void onChunkUnload(PoiManager poiManager, ChunkAccess chunkAccess) { - ChunkPos chunkPos = chunkAccess.getPos(); - poiManager.flush(chunkPos); // Make sure all POI in chunk are saved to disk first. - - // Remove the cached POIs for this chunk's location. - int SectionPosMinY = SectionPos.blockToSectionCoord(chunkAccess.getMinBuildHeight()); - for (int currentSectionY = 0; currentSectionY < chunkAccess.getSectionsCount(); currentSectionY++) { - long sectionPosKey = SectionPos.asLong(chunkPos.x, SectionPosMinY + currentSectionY, chunkPos.z); - poiManager.remove(sectionPosKey); - } - } - - /** - * Checks if a mob effect can be applied to an entity by firing {@link MobEffectEvent.Applicable}. - * - * @param entity The target entity the mob effect is being applied to. - * @param effect The mob effect being applied. - * @return True if the mob effect can be applied, otherwise false. - */ - public static boolean canMobEffectBeApplied(LivingEntity entity, MobEffectInstance effect) { - var event = new MobEffectEvent.Applicable(entity, effect); - return NeoForge.EVENT_BUS.post(event).getApplicationResult(); - } - - /** - * Attempts to resolve a {@link RegistryLookup} using the current global state. - *

- * Prioritizes the server's lookup, only attempting to retrieve it from the client if the server is unavailable. - * - * @param The type of registry being looked up - * @param key The resource key for the target registry - * @return A registry access, if one was available. - */ - @Nullable - public static RegistryLookup resolveLookup(ResourceKey> key) { - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - if (server != null) { - return server.registryAccess().lookup(key).orElse(null); - } else if (FMLEnvironment.dist.isClient()) { - return ClientHooks.resolveLookup(key); - } - return null; - } } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index ae10dd2946..9618e2ef77 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -9,23 +9,21 @@ import java.util.Map; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import net.neoforged.bus.api.ICancellableEvent; -import net.neoforged.neoforge.event.entity.player.PlayerEvent; import org.jetbrains.annotations.ApiStatus; /** - * Fired when a {@link Player}'s armor is dealt damage in {@link Player#actuallyHurt(DamageSource, float) actuallyHurt}. + * Fired when a {@link LivingEntity}'s armor is dealt damage in {@link LivingEntity#doHurtEquipment(DamageSource, float, EquipmentSlot...) doHurtEquipment}. *

- * This event is {@link ICancellableEvent cancelable}. Cancelling this event will ignore all damage modifications - * and result in the original damage being applied to the armor item. + * This event is {@link ICancellableEvent cancelable}. Cancelling this event will prevent all damage to armor. *

* This event does not have a result. *

* This event is fired on the {@link NeoForge#EVENT_BUS} */ -public class ArmorHurtEvent extends PlayerEvent implements ICancellableEvent { +public class ArmorHurtEvent extends LivingEvent implements ICancellableEvent { public static class ArmorEntry { public ItemStack armorItemStack; public final float originalDamage; @@ -41,7 +39,7 @@ public ArmorEntry(ItemStack armorStack, float damageIn) { private final EnumMap armorEntries; @ApiStatus.Internal - public ArmorHurtEvent(EnumMap armorMap, Player player) { + public ArmorHurtEvent(EnumMap armorMap, LivingEntity player) { super(player); this.armorEntries = armorMap; } diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java index 9547962096..6030eb60d7 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java @@ -18,14 +18,12 @@ import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; import net.minecraft.world.ItemInteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -34,15 +32,12 @@ import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.portal.DimensionTransition; import net.neoforged.bus.api.EventPriority; import net.neoforged.neoforge.event.StatAwardEvent; -import net.neoforged.neoforge.event.entity.player.ItemEntityPickupEvent; import net.neoforged.neoforge.event.entity.living.ArmorHurtEvent; import net.neoforged.neoforge.event.entity.player.PermissionsChangedEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; -import net.neoforged.neoforge.event.entity.player.PlayerRespawnPositionEvent; import net.neoforged.neoforge.event.entity.player.UseItemOnBlockEvent; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; @@ -133,11 +128,11 @@ static void entityInteractEvent(final DynamicTest test) { @EmptyTemplate(floor = true) @TestHolder(description = "Tests if the ItemPickupEvent fires") public static void itemPickupEvent(final DynamicTest test) { - test.eventListeners().forge().addListener((ItemEntityPickupEvent.Post event) -> { - if (event.getOriginalStack().is(Items.MELON_SEEDS)) { + test.eventListeners().forge().addListener((final PlayerEvent.ItemPickupEvent event) -> { + if (event.getStack().is(Items.MELON_SEEDS)) { // If the event is fired and detects pickup of melon seeds, the test will be considered pass // and the player will get pumpkin seeds too - event.getPlayer().addItem(new ItemStack(Items.PUMPKIN_SEEDS)); + event.getEntity().addItem(new ItemStack(Items.PUMPKIN_SEEDS)); test.pass(); } }); @@ -239,65 +234,24 @@ static void changeStatAward(final DynamicTest test, final RegistrationHelper reg }); } - @GameTest - @EmptyTemplate - @TestHolder(description = "Tests if the PlayerRespawnPositionEvent fires correctly and can change where the player respawns") - static void playerRespawnPositionEvent(final DynamicTest test, final RegistrationHelper reg) { - test.eventListeners().forge().addListener((final PlayerRespawnPositionEvent event) -> { - // Only affect the players with a custom name to not interfere with other tests - if (!Objects.equals(event.getEntity().getCustomName(), Component.literal("respawn-position-test"))) { - return; - } - - var oldTransition = event.getDimensionTransition(); - var newTransition = new DimensionTransition(oldTransition.newLevel(), - event.getEntity().position().relative(Direction.SOUTH, 1), - oldTransition.speed(), - oldTransition.xRot(), - oldTransition.yRot(), - oldTransition.missingRespawnBlock(), - oldTransition.postDimensionTransition()); - event.setDimensionTransition(newTransition); - }); - - test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) - .thenExecute(player -> player.setCustomName(Component.literal("respawn-position-test"))) - .thenExecute(player -> player.setRespawnPosition(player.getRespawnDimension(), helper.absolutePos(new BlockPos(0, 1, 0)), 0, false, true)) - .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false, Entity.RemovalReason.KILLED)) - .thenExecute(() -> helper.assertEntityPresent(EntityType.PLAYER, new BlockPos(0, 1, 1))) - .thenSucceed()); - } - - @GameTest - @EmptyTemplate - @TestHolder(description = "Tests if the PlayerRespawnEvent fires correctly and can modify the player after respawning") - static void playerRespawnEvent(final DynamicTest test, final RegistrationHelper reg) { - test.eventListeners().forge().addListener((final PlayerEvent.PlayerRespawnEvent event) -> { - event.getEntity().setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.APPLE)); - }); - - test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) - .thenExecute(player -> player.setRespawnPosition(player.getRespawnDimension(), helper.absolutePos(new BlockPos(0, 1, 1)), 0, true, true)) - .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false, Entity.RemovalReason.KILLED)) - .thenExecute(() -> helper.assertEntityIsHolding(new BlockPos(0, 1, 1), EntityType.PLAYER, Items.APPLE)) - .thenSucceed()); - } @GameTest @EmptyTemplate @TestHolder(description = "Tests if ArmorHurtEvent fires and prevents armor damage.") static void armorHurtEvent(final DynamicTest test) { test.eventListeners().forge().addListener((final ArmorHurtEvent event) -> { - if (event.getEntity() instanceof GameTestPlayer player && player.getItemBySlot(EquipmentSlot.HEAD).getItem().equals(Items.DIAMOND_HELMET)) - event.setNewDamage(EquipmentSlot.HEAD, 5); + if (event.getEntity() instanceof Player player && player.getItemBySlot(EquipmentSlot.CHEST).getItem().equals(Items.DIAMOND_CHESTPLATE)) + event.setNewDamage(EquipmentSlot.CHEST, 5); }); test.onGameTest(helper -> { DamageSource source = new DamageSource(helper.getLevel().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.MOB_ATTACK)); - helper.startSequence(() -> helper.makeTickingMockServerPlayerInLevel(GameType.SURVIVAL)) - .thenExecute(player -> player.setItemSlot(EquipmentSlot.HEAD, new ItemStack(Items.DIAMOND_HELMET))) - .thenExecute(player -> player.getInventory().hurtArmor(source, 100, Inventory.ALL_ARMOR_SLOTS)) - .thenWaitUntil(player -> helper.assertTrue(player.getItemBySlot(EquipmentSlot.HEAD).getDamageValue() == 5, - "Armor hurt not applied. %s actual but expected 5f".formatted(player.getItemBySlot(EquipmentSlot.HEAD).getDamageValue()))) + helper.startSequence(() -> helper.makeMockPlayer(GameType.SURVIVAL)) + .thenExecute(player -> player.invulnerableTime = 0) + .thenExecute(player -> player.setItemSlot(EquipmentSlot.CHEST, new ItemStack(Items.DIAMOND_CHESTPLATE))) + .thenExecute(player -> player.hurt(source, 10F)) + .thenWaitUntil(player -> helper.assertTrue(player.getItemBySlot(EquipmentSlot.CHEST).getItem().equals(Items.DIAMOND_CHESTPLATE) + && player.getItemBySlot(EquipmentSlot.CHEST).getDamageValue() == 5, + "Armor hurt not applied. %s actual but expected 5f".formatted(player.getItemBySlot(EquipmentSlot.CHEST).getDamageValue()))) .thenSucceed(); }); } From 69cb72112f71895e8ecc3b974f6e81e837aba0aa Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Tue, 30 Apr 2024 17:01:11 -0400 Subject: [PATCH 13/41] Fix branch updating errors --- src/main/java/net/neoforged/neoforge/common/CommonHooks.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 120a6421a2..998a9d5f7b 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -243,10 +243,6 @@ public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource so return NeoForge.EVENT_BUS.post(new EntityInvulnerablityCheckEvent(entity, source, isInvul)).isInvulnerable(); } - public static boolean onLivingTick(LivingEntity entity) { - return NeoForge.EVENT_BUS.post(new LivingEvent.LivingTickEvent(entity)).isCanceled(); - } - public static boolean onEntityPreDamage(LivingEntity entity, DamageContainer container) { return entity instanceof Player || !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); } From 628697e3c6004d1151601111dec20e02d88ada70 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Wed, 15 May 2024 19:07:35 -0400 Subject: [PATCH 14/41] fix porting errors --- .../world/entity/player/Player.java.patch | 55 +++++++++++-------- .../debug/entity/player/PlayerEventTests.java | 37 +++++++++++++ 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index 84a0b329f3..5cf6e46cba 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -111,19 +111,24 @@ } @Override -@@ -860,11 +_,15 @@ + public void readAdditionalSaveData(CompoundTag p_36215_) { + super.readAdditionalSaveData(p_36215_); +@@ -856,6 +_,8 @@ + } else if (this.abilities.invulnerable && !p_36154_.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { + return false; + } else { ++ this.damageContainer = new net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer(p_36154_, p_36155_); ++ if (!net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer)) return false; + this.noActionTime = 0; if (this.isDeadOrDying()) { return false; - } else { -+ this.damageContainer = new net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer(p_36154_, p_36155_); -+ if (!net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer)) return false; - if (!this.level().isClientSide) { +@@ -864,7 +_,9 @@ this.removeEntitiesOnShoulder(); } -+ this.damageContainer.setNewDamage(Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, this.damageContainer.getNewDamage(), this.level().getDifficulty()))); -+ p_36155_ = Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, p_36155_, this.level().getDifficulty())); - if (p_36154_.scalesWithDifficulty()) { ++ p_36155_ = Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, p_36155_, this.level().getDifficulty())); ++ + if (false && p_36154_.scalesWithDifficulty()) { if (this.level().getDifficulty() == Difficulty.PEACEFUL) { p_36155_ = 0.0F; @@ -161,7 +166,7 @@ if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -@@ -943,12 +_,18 @@ +@@ -943,16 +_,18 @@ @Override protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { @@ -171,21 +176,25 @@ - float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); - float f = p_36313_ - f1; -+ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); -+ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); -+ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); -+ if (f1 <= 0) return; -+ float f = this.damageContainer.getNewDamage() - f1; -+ if (f > 0.0F && f < 3.4028235E37F) { -+ this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); -+ } -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); - if (f > 0.0F && f < 3.4028235E37F) { - this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); - } +- if (f > 0.0F && f < 3.4028235E37F) { +- this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); +- } +- ++ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); ++ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ if (f1 <= 0) return; ++ float f = this.damageContainer.getNewDamage() - f1; ++ if (f > 0.0F && f < 3.4028235E37F) { ++ this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); ++ } ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); + if (f1 != 0.0F) { + this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); + this.getCombatTracker().recordDamage(p_36312_, f1); @@ -962,8 +_,8 @@ } diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java index 6030eb60d7..786c8527a8 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java @@ -38,6 +38,7 @@ import net.neoforged.neoforge.event.entity.player.PermissionsChangedEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; +import net.neoforged.neoforge.event.entity.player.PlayerRespawnPositionEvent; import net.neoforged.neoforge.event.entity.player.UseItemOnBlockEvent; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; @@ -255,4 +256,40 @@ static void armorHurtEvent(final DynamicTest test) { .thenSucceed(); }); } + + @GameTest + @EmptyTemplate + @TestHolder(description = "Tests if the PlayerRespawnPositionEvent fires correctly and can change where the player respawns") + static void playerRespawnPositionEvent(final DynamicTest test, final RegistrationHelper reg) { + test.eventListeners().forge().addListener((final PlayerRespawnPositionEvent event) -> { + // Only affect the players with a custom name to not interfere with other tests + if (!Objects.equals(event.getEntity().getCustomName(), Component.literal("respawn-position-test"))) { + return; + } + + event.setRespawnPosition(event.getEntity().position().relative(Direction.SOUTH, 1)); + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) + .thenExecute(player -> player.setCustomName(Component.literal("respawn-position-test"))) + .thenExecute(player -> player.setRespawnPosition(player.getRespawnDimension(), helper.absolutePos(new BlockPos(0, 1, 0)), 0, false, true)) + .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false)) + .thenExecute(() -> helper.assertEntityPresent(EntityType.PLAYER, new BlockPos(0, 1, 1))) + .thenSucceed()); + } + + @GameTest + @EmptyTemplate + @TestHolder(description = "Tests if the PlayerRespawnEvent fires correctly and can modify the player after respawning") + static void playerRespawnEvent(final DynamicTest test, final RegistrationHelper reg) { + test.eventListeners().forge().addListener((final PlayerEvent.PlayerRespawnEvent event) -> { + event.getEntity().setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.APPLE)); + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) + .thenExecute(player -> player.setRespawnPosition(player.getRespawnDimension(), helper.absolutePos(new BlockPos(0, 1, 1)), 0, true, true)) + .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false)) + .thenExecute(() -> helper.assertEntityIsHolding(new BlockPos(0, 1, 1), EntityType.PLAYER, Items.APPLE)) + .thenSucceed()); + } } From c932aaa32120caed8fc9ef301d2b62667b030e6f Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 16 May 2024 07:18:23 -0400 Subject: [PATCH 15/41] resolve gametest issues --- patches/net/minecraft/world/entity/player/Player.java.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index 5cf6e46cba..774c067c2d 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -127,7 +127,7 @@ } - if (p_36154_.scalesWithDifficulty()) { -+ p_36155_ = Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, p_36155_, this.level().getDifficulty())); ++ this.damageContainer.setNewDamage(Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, this.damageContainer.getNewDamage(), this.level().getDifficulty()))); + + if (false && p_36154_.scalesWithDifficulty()) { if (this.level().getDifficulty() == Difficulty.PEACEFUL) { From f1af2436e27753a3020ba8bd7021ca4f0231bb77 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Wed, 29 May 2024 07:18:04 -0400 Subject: [PATCH 16/41] Address comments --- .../world/entity/LivingEntity.java.patch | 41 +++-- .../world/entity/player/Player.java.patch | 10 +- .../neoforge/common/CommonHooks.java | 68 +++++++++ .../common/damagesource/DamageContainer.java | 128 ---------------- .../damagesource/InternalDamageContainer.java | 142 ++++++++++++++++++ .../EntityInvulnerablityCheckEvent.java | 9 +- .../event/entity/living/ArmorHurtEvent.java | 10 +- 7 files changed, 248 insertions(+), 160 deletions(-) create mode 100644 src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index dc1d222166..43311833c5 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -9,11 +9,15 @@ private static final Logger LOGGER = LogUtils.getLogger(); private static final String TAG_ACTIVE_EFFECTS = "active_effects"; private static final UUID SPEED_MODIFIER_SOUL_SPEED_UUID = UUID.fromString("87f46a96-686f-4796-b035-22e16ee9e038"); -@@ -242,6 +_,7 @@ +@@ -242,6 +_,11 @@ protected Brain brain; private boolean skipDropExperience; protected float appliedScale = 1.0F; -+ protected net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer damageContainer; ++ /**This field stores information about damage dealt to this entity. ++ * The field is instantiated via {@link #hurt(DamageSource, float)} after ++ * invulnerability checks, and is nulllified before the method's return.*/ ++ @org.jetbrains.annotations.Nullable ++ protected net.neoforged.neoforge.common.damagesource.InternalDamageContainer damageContainer; protected LivingEntity(EntityType p_20966_, Level p_20967_) { super(p_20966_, p_20967_); @@ -136,19 +140,19 @@ float f = this.getHealth(); if (f > 0.0F) { this.setHealth(f + p_21116_); -@@ -1127,23 +_,26 @@ +@@ -1127,23 +_,28 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { -+ this.damageContainer = this.damageContainer == null ? new net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer(p_21016_, p_21017_) : this.damageContainer; ++ this.damageContainer = this.damageContainer == null ? new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_21016_, p_21017_) : this.damageContainer; + if (!net.neoforged.neoforge.common.CommonHooks.onEntityPreDamage(this, this.damageContainer)) return false; if (this.isSleeping() && !this.level().isClientSide) { this.stopSleeping(); } this.noActionTime = 0; -- float f = p_21017_; -+ float f = p_21017_ = this.damageContainer.getNewDamage(); ++ p_21017_ = this.damageContainer.getNewDamage(); //Neo: enforce damage container as source of truth for damage amount + float f = p_21017_; boolean flag = false; float f1 = 0.0F; - if (p_21017_ > 0.0F && this.isDamageSourceBlocked(p_21016_)) { @@ -156,7 +160,8 @@ - f1 = p_21017_; - p_21017_ = 0.0F; + net.neoforged.neoforge.event.entity.living.DamageBlockEvent ev; -+ if (p_21017_ > 0.0F && (ev = this.damageContainer.setBlockedDamage(net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_)))).getBlocked()) { ++ if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_))).getBlocked()) { ++ this.damageContainer.setBlockedDamage(ev); + if(ev.shieldDamage() > 0) this.hurtCurrentlyUsedShield(ev.shieldDamage()); + f1 = ev.getBlockedDamage(); + p_21017_ = ev.getDamageContainer().getNewDamage(); @@ -169,6 +174,14 @@ } if (p_21016_.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { +@@ -1159,6 +_,7 @@ + boolean flag1 = true; + if ((float)this.invulnerableTime > 10.0F && !p_21016_.is(DamageTypeTags.BYPASSES_COOLDOWN)) { + if (p_21017_ <= this.lastHurt) { ++ this.damageContainer = null; + return false; + } + @@ -1167,7 +_,7 @@ flag1 = false; } else { @@ -190,7 +203,7 @@ this.lastHurtByPlayer = player; } else { this.lastHurtByPlayer = null; -@@ -1245,14 +_,14 @@ +@@ -1245,7 +_,7 @@ if (this instanceof ServerPlayer) { CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer)this, p_21016_, f, p_21017_, flag); if (f1 > 0.0F && f1 < 3.4028235E37F) { @@ -199,10 +212,10 @@ } } - if (entity instanceof ServerPlayer) { +@@ -1253,6 +_,7 @@ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)entity, this, p_21016_, f, p_21017_, flag); } -- + + this.damageContainer = null; return flag2; } @@ -342,12 +355,12 @@ this.playSound(soundtype.getFallSound(), soundtype.getVolume() * 0.5F, soundtype.getPitch() * 0.75F); } } -@@ -1641,7 +_,7 @@ - protected void doHurtEquipment(DamageSource p_330843_, float p_330394_, EquipmentSlot... p_331314_) { +@@ -1642,6 +_,8 @@ if (!(p_330394_ <= 0.0F)) { int i = (int)Math.max(1.0F, p_330394_ / 4.0F); -- -+ net.neoforged.neoforge.common.CommonHooks.onArmorHurt(p_330843_, p_331314_, p_330394_, this); p_331314_ = new EquipmentSlot[0]; + ++ net.neoforged.neoforge.common.CommonHooks.onArmorHurt(p_330843_, p_331314_, p_330394_, this); ++ p_331314_ = new EquipmentSlot[0]; //Neo: invalidates the loop. armor damage happens in common hook for (EquipmentSlot equipmentslot : p_331314_) { ItemStack itemstack = this.getItemBySlot(equipmentslot); if (itemstack.getItem() instanceof ArmorItem && itemstack.canBeHurtBy(p_330843_)) { diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index 774c067c2d..a8da3d2816 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -117,7 +117,7 @@ } else if (this.abilities.invulnerable && !p_36154_.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { return false; } else { -+ this.damageContainer = new net.neoforged.neoforge.common.damagesource.DamageContainer.InternalDamageContainer(p_36154_, p_36155_); ++ this.damageContainer = new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_36154_, p_36155_); + if (!net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer)) return false; this.noActionTime = 0; if (this.isDeadOrDying()) { @@ -133,12 +133,16 @@ if (this.level().getDifficulty() == Difficulty.PEACEFUL) { p_36155_ = 0.0F; } -@@ -878,7 +_,7 @@ +@@ -878,7 +_,11 @@ } } - return p_36155_ == 0.0F ? false : super.hurt(p_36154_, p_36155_); -+ if (this.damageContainer.getNewDamage() == 0.0F) {this.damageContainer = null; return false;} else return super.hurt(p_36154_, this.damageContainer.getNewDamage()); ++ if (this.damageContainer.getNewDamage() == 0.0F) { ++ this.damageContainer = null; ++ return false; ++ } ++ else return super.hurt(p_36154_, this.damageContainer.getNewDamage()); } } } diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 998a9d5f7b..c4ad9d9604 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -239,14 +239,43 @@ public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, return event; } + /**Creates and posts an {@link EntityInvulnerablityCheckEvent}. This is invoked in + * {@link Entity#isInvulnerableTo(DamageSource)} and returns a post-listener result + * to the invulnerability status of the entity to the damage source. + * + * @param entity the entity being checked for invulnerability + * @param source the damage source being applied for this check + * @param isInvul whether this entity is invulnerable according to preceding/vanilla logic + * @return if this entity is invulnerable + */ public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource source, boolean isInvul) { return NeoForge.EVENT_BUS.post(new EntityInvulnerablityCheckEvent(entity, source, isInvul)).isInvulnerable(); } + /**Called after invulnerability checks in {@link LivingEntity#hurt(DamageSource, float)}, + * this method creates and posts the first event in the LivingEntity damage sequence, + * {@link EntityPreDamageEvent}, FOR NON-PLAYER entities. + * + * @param entity the entity to receive damage + * @param container the newly instantiated container for damage to be dealt. Most properties of + * the container will be empty at this stage. + * @return if the event is cancelled and no damage will be applied to the entity + */ public static boolean onEntityPreDamage(LivingEntity entity, DamageContainer container) { return entity instanceof Player || !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); } + /**Called after invulnerability checks in {@link Player#hurt(DamageSource, float)}, + * {@link net.minecraft.client.player.LocalPlayer#hurt(DamageSource, float)}, and + * {@link net.minecraft.client.player.RemotePlayer#hurt(DamageSource, float)}, + * this method creates and posts the first event in the LivingEntity damage sequence, + * {@link EntityPreDamageEvent}, for player entities. + * + * @param entity the player to receive damage + * @param container the newly instantiated container for damage to be dealt. Most properties of + * the container will be empty at this stage. + * @return if the event is cancelled and no damage will be applied to the entity + */ public static boolean onPlayerEntityPreDamage(LivingEntity entity, DamageContainer container) { return !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); } @@ -261,14 +290,43 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS return !NeoForge.EVENT_BUS.post(new LivingUseTotemEvent(entity, damageSource, totem, hand)).isCanceled(); } + /**Creates and posts an {@link IncomingDamageEvent}. This is invoked in + * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} + * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. + * + * @param entity the entity to receive damage + * @param container the container object holding the final values of the damage pipeline while they are + * still mutable + * @return the current damage value to be applied to the entity's health + * + */ public static float onIncomingDamage(LivingEntity entity, DamageContainer container) { return NeoForge.EVENT_BUS.post(new IncomingDamageEvent(entity, container)).getDamageContainer().getNewDamage(); } + /**Creates and posts a {@link DamageTakenEvent}. This is invoked in + * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} + * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. + * + * @param entity the entity to receive damage + * @param container the container object holding the truly final values of the damage pipeline. This + * instance is immutable. + */ public static void onLivingDamageTaken(LivingEntity entity, DamageContainer container) { NeoForge.EVENT_BUS.post(new DamageTakenEvent(entity, new DamageContainer.ResultDamageContainer(container))); } + /**This is invoked in {@link LivingEntity#doHurtEquipment(DamageSource, float, EquipmentSlot...)} + * and replaces the existing item hurt and break logic with an event-sensitive version. + *
+ * Each armor slot is collected and passed into a {@link ArmorHurtEvent} and posted. If not cancelled, + * the final durability loss values for each equipment item from the event will be applied. + * + * @param source the damage source applied to the entity and armor + * @param slots an array of applicable slots for damage + * @param damage the durability damage individual items will receive + * @param armoredEntity the entity wearing the armor + */ public static void onArmorHurt(DamageSource source, EquipmentSlot[] slots, float damage, LivingEntity armoredEntity) { EnumMap armorMap = new EnumMap<>(EquipmentSlot.class); for (EquipmentSlot slot : slots) { @@ -1037,6 +1095,16 @@ public static void onEntityEnterSection(Entity entity, long packedOldPos, long p NeoForge.EVENT_BUS.post(new EntityEvent.EnteringSection(entity, packedOldPos, packedNewPos)); } + /**Creates, posts, and returns a {@link DamageBlockEvent}. This method is invoked in + * {@link LivingEntity#hurt(DamageSource, float)} and requires internal access to the + * protected field {@link LivingEntity#damageContainer} as a parameter. + * + * @param blocker the entity performing the block + * @param container the entity's internal damage container for accessing current values + * in the damage pipeline at the time of this invocation. + * @param originalBlocked whether this entity is blocking according to preceding/vanilla logic + * @return the event object after event listeners have been invoked. + */ public static DamageBlockEvent onDamageBlock(LivingEntity blocker, DamageContainer container, boolean originalBlocked) { DamageBlockEvent e = new DamageBlockEvent(blocker, container, originalBlocked); NeoForge.EVENT_BUS.post(e); diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 70284f8399..52f21bde4c 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -144,134 +144,6 @@ public enum Reduction { */ float getAbsorption(); - @ApiStatus.Internal - public class InternalDamageContainer implements DamageContainer { - private final EnumMap>> reductionMap = new EnumMap<>(Reduction.class); - private final float originalDamage; - private final DamageSource source; - private float newDamage; - private float armorReduction = 0f; - private float absorption = 0f; - private float enchantReduction = 0f; - private float mobEffectReduction = 0f; - private float blockedDamage = 0f; - private float shieldDamage = 0; - private int invulnerabilityTicksAfterAttack = 20; - - public InternalDamageContainer(DamageSource source, float originalDamage) { - this.source = source; - this.originalDamage = originalDamage; - this.newDamage = originalDamage; - } - - @Override - public float getOriginalDamage() { - return originalDamage; - } - - @Override - public DamageSource getSource() { - return source; - } - - @Override - public void setNewDamage(float damage) { - this.newDamage = damage; - } - - @Override - public float getNewDamage() { - return newDamage; - } - - public void addModifier(Reduction type, BiFunction operation) { - this.reductionMap.computeIfAbsent(type, a -> new ArrayList<>()).add(operation); - } - - @Override - public float getBlockedDamage() { - return blockedDamage; - } - - @Override - public float getShieldDamage() { - return shieldDamage; - } - - @Override - public void setPostAttackInvulnerabilityTicks(int ticks) { - this.invulnerabilityTicksAfterAttack = ticks; - } - - @Override - public int getPostAttackInvulnerabilityTicks() { - return invulnerabilityTicksAfterAttack; - } - - @Override - public float getArmorReduction() { - return armorReduction; - } - - @Override - public float getEnchantReduction() { - return enchantReduction; - } - - @Override - public float getMobEffectReduction() { - return mobEffectReduction; - } - - @Override - public float getAbsorption() { - return absorption; - } - - //=============INTERNAL METHODS - DO NOT USE=================== - - @ApiStatus.Internal - public DamageBlockEvent setBlockedDamage(DamageBlockEvent event) { - if (event.getBlocked()) { - this.blockedDamage = event.getBlockedDamage(); - this.shieldDamage = event.shieldDamage(); - this.newDamage -= this.blockedDamage; - } - return event; - } - - @ApiStatus.Internal - public void setAbsorption(float absorption) { - this.absorption = modifyReduction(Reduction.ABSORPTION, absorption); - this.newDamage -= Math.max(0, absorption); - } - - @ApiStatus.Internal - public void setMobEffectReduction(float reduction) { - this.mobEffectReduction = modifyReduction(Reduction.MOBEFFECT, reduction); - this.newDamage -= Math.max(0, reduction); - } - - @ApiStatus.Internal - public void setEnchantReduction(float reduction) { - this.enchantReduction = modifyReduction(Reduction.ENCHANT, reduction); - this.newDamage -= Math.max(0, reduction); - } - - @ApiStatus.Internal - public void setArmorReduction(float reduction) { - this.armorReduction = modifyReduction(Reduction.ARMOR, reduction); - this.newDamage -= Math.max(0, this.armorReduction); - } - - private float modifyReduction(Reduction type, float reduction) { - for (var func : reductionMap.getOrDefault(type, new ArrayList<>())) { - reduction = func.apply(this, reduction); - } - return reduction; - } - } - public record ResultDamageContainer( float getOriginalDamage, DamageSource getSource, diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java new file mode 100644 index 0000000000..050a2e1396 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.common.damagesource; + +import net.minecraft.world.damagesource.DamageSource; +import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.function.BiFunction; + +@ApiStatus.Internal +public class InternalDamageContainer implements DamageContainer { + private final EnumMap>> reductionMap = new EnumMap<>(Reduction.class); + private final float originalDamage; + private final DamageSource source; + private float newDamage; + private float armorReduction = 0f; + private float absorption = 0f; + private float enchantReduction = 0f; + private float mobEffectReduction = 0f; + private float blockedDamage = 0f; + private float shieldDamage = 0; + private int invulnerabilityTicksAfterAttack = 20; + + public InternalDamageContainer(DamageSource source, float originalDamage) { + this.source = source; + this.originalDamage = originalDamage; + this.newDamage = originalDamage; + } + + @Override + public float getOriginalDamage() { + return originalDamage; + } + + @Override + public DamageSource getSource() { + return source; + } + + @Override + public void setNewDamage(float damage) { + this.newDamage = damage; + } + + @Override + public float getNewDamage() { + return newDamage; + } + + public void addModifier(Reduction type, BiFunction operation) { + this.reductionMap.computeIfAbsent(type, a -> new ArrayList<>()).add(operation); + } + + @Override + public float getBlockedDamage() { + return blockedDamage; + } + + @Override + public float getShieldDamage() { + return shieldDamage; + } + + @Override + public void setPostAttackInvulnerabilityTicks(int ticks) { + this.invulnerabilityTicksAfterAttack = ticks; + } + + @Override + public int getPostAttackInvulnerabilityTicks() { + return invulnerabilityTicksAfterAttack; + } + + @Override + public float getArmorReduction() { + return armorReduction; + } + + @Override + public float getEnchantReduction() { + return enchantReduction; + } + + @Override + public float getMobEffectReduction() { + return mobEffectReduction; + } + + @Override + public float getAbsorption() { + return absorption; + } + + //=============INTERNAL METHODS - DO NOT USE=================== + + @ApiStatus.Internal + public void setBlockedDamage(DamageBlockEvent event) { + if (event.getBlocked()) { + this.blockedDamage = event.getBlockedDamage(); + this.shieldDamage = event.shieldDamage(); + this.newDamage -= this.blockedDamage; + } + } + + @ApiStatus.Internal + public void setAbsorption(float absorption) { + this.absorption = modifyReduction(Reduction.ABSORPTION, absorption); + this.newDamage -= Math.max(0, absorption); + } + + @ApiStatus.Internal + public void setMobEffectReduction(float reduction) { + this.mobEffectReduction = modifyReduction(Reduction.MOBEFFECT, reduction); + this.newDamage -= Math.max(0, reduction); + } + + @ApiStatus.Internal + public void setEnchantReduction(float reduction) { + this.enchantReduction = modifyReduction(Reduction.ENCHANT, reduction); + this.newDamage -= Math.max(0, reduction); + } + + @ApiStatus.Internal + public void setArmorReduction(float reduction) { + this.armorReduction = modifyReduction(Reduction.ARMOR, reduction); + this.newDamage -= Math.max(0, this.armorReduction); + } + + private float modifyReduction(Reduction type, float reduction) { + for (var func : reductionMap.getOrDefault(type, new ArrayList<>())) { + reduction = func.apply(this, reduction); + } + return reduction; + } +} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java index f38c38bf05..38e8a33335 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java @@ -11,13 +11,8 @@ /** * Fired when {@link Entity#hurt(DamageSource, float)} is invoked and determines if - * downstream hurt logic should apply. This event is fired in {@link Entity#isInvulnerableTo(DamageSource)} - *

- * This event cannot be cancelled. - *

- * This event does not have a result. - *

- * This event is fired on the {@link NeoForge#EVENT_BUS}. + * downstream hurt logic should apply. This event is fired on both sides in + * {@link Entity#isInvulnerableTo(DamageSource)} */ public class EntityInvulnerablityCheckEvent extends EntityEvent { private final boolean originallyInvulnerable; diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index 9618e2ef77..fdd02fe9e1 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -14,14 +14,8 @@ import net.neoforged.bus.api.ICancellableEvent; import org.jetbrains.annotations.ApiStatus; -/** - * Fired when a {@link LivingEntity}'s armor is dealt damage in {@link LivingEntity#doHurtEquipment(DamageSource, float, EquipmentSlot...) doHurtEquipment}. - *

- * This event is {@link ICancellableEvent cancelable}. Cancelling this event will prevent all damage to armor. - *

- * This event does not have a result. - *

- * This event is fired on the {@link NeoForge#EVENT_BUS} +/**Fired on both sides when a {@link LivingEntity}'s armor is dealt damage in + * {@link LivingEntity#doHurtEquipment(DamageSource, float, EquipmentSlot...) doHurtEquipment}. */ public class ArmorHurtEvent extends LivingEvent implements ICancellableEvent { public static class ArmorEntry { From a2a113604d45e60b0a05419a056f7e4732e13cdd Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Wed, 29 May 2024 07:39:52 -0400 Subject: [PATCH 17/41] fix formatting issues. --- .../neoforge/common/CommonHooks.java | 53 +++++++++++-------- .../common/damagesource/DamageContainer.java | 4 -- .../damagesource/InternalDamageContainer.java | 7 ++- .../event/entity/living/ArmorHurtEvent.java | 3 +- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index c4ad9d9604..a8b1326314 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -239,12 +239,13 @@ public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, return event; } - /**Creates and posts an {@link EntityInvulnerablityCheckEvent}. This is invoked in + /** + * Creates and posts an {@link EntityInvulnerablityCheckEvent}. This is invoked in * {@link Entity#isInvulnerableTo(DamageSource)} and returns a post-listener result * to the invulnerability status of the entity to the damage source. * - * @param entity the entity being checked for invulnerability - * @param source the damage source being applied for this check + * @param entity the entity being checked for invulnerability + * @param source the damage source being applied for this check * @param isInvul whether this entity is invulnerable according to preceding/vanilla logic * @return if this entity is invulnerable */ @@ -252,12 +253,13 @@ public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource so return NeoForge.EVENT_BUS.post(new EntityInvulnerablityCheckEvent(entity, source, isInvul)).isInvulnerable(); } - /**Called after invulnerability checks in {@link LivingEntity#hurt(DamageSource, float)}, + /** + * Called after invulnerability checks in {@link LivingEntity#hurt(DamageSource, float)}, * this method creates and posts the first event in the LivingEntity damage sequence, * {@link EntityPreDamageEvent}, FOR NON-PLAYER entities. * - * @param entity the entity to receive damage - * @param container the newly instantiated container for damage to be dealt. Most properties of + * @param entity the entity to receive damage + * @param container the newly instantiated container for damage to be dealt. Most properties of * the container will be empty at this stage. * @return if the event is cancelled and no damage will be applied to the entity */ @@ -265,14 +267,15 @@ public static boolean onEntityPreDamage(LivingEntity entity, DamageContainer con return entity instanceof Player || !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); } - /**Called after invulnerability checks in {@link Player#hurt(DamageSource, float)}, + /** + * Called after invulnerability checks in {@link Player#hurt(DamageSource, float)}, * {@link net.minecraft.client.player.LocalPlayer#hurt(DamageSource, float)}, and * {@link net.minecraft.client.player.RemotePlayer#hurt(DamageSource, float)}, * this method creates and posts the first event in the LivingEntity damage sequence, * {@link EntityPreDamageEvent}, for player entities. * - * @param entity the player to receive damage - * @param container the newly instantiated container for damage to be dealt. Most properties of + * @param entity the player to receive damage + * @param container the newly instantiated container for damage to be dealt. Most properties of * the container will be empty at this stage. * @return if the event is cancelled and no damage will be applied to the entity */ @@ -290,11 +293,12 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS return !NeoForge.EVENT_BUS.post(new LivingUseTotemEvent(entity, damageSource, totem, hand)).isCanceled(); } - /**Creates and posts an {@link IncomingDamageEvent}. This is invoked in + /** + * Creates and posts an {@link IncomingDamageEvent}. This is invoked in * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. * - * @param entity the entity to receive damage + * @param entity the entity to receive damage * @param container the container object holding the final values of the damage pipeline while they are * still mutable * @return the current damage value to be applied to the entity's health @@ -304,27 +308,29 @@ public static float onIncomingDamage(LivingEntity entity, DamageContainer contai return NeoForge.EVENT_BUS.post(new IncomingDamageEvent(entity, container)).getDamageContainer().getNewDamage(); } - /**Creates and posts a {@link DamageTakenEvent}. This is invoked in + /** + * Creates and posts a {@link DamageTakenEvent}. This is invoked in * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. * - * @param entity the entity to receive damage - * @param container the container object holding the truly final values of the damage pipeline. This + * @param entity the entity to receive damage + * @param container the container object holding the truly final values of the damage pipeline. This * instance is immutable. */ public static void onLivingDamageTaken(LivingEntity entity, DamageContainer container) { NeoForge.EVENT_BUS.post(new DamageTakenEvent(entity, new DamageContainer.ResultDamageContainer(container))); } - /**This is invoked in {@link LivingEntity#doHurtEquipment(DamageSource, float, EquipmentSlot...)} + /** + * This is invoked in {@link LivingEntity#doHurtEquipment(DamageSource, float, EquipmentSlot...)} * and replaces the existing item hurt and break logic with an event-sensitive version. *
- * Each armor slot is collected and passed into a {@link ArmorHurtEvent} and posted. If not cancelled, + * Each armor slot is collected and passed into a {@link ArmorHurtEvent} and posted. If not cancelled, * the final durability loss values for each equipment item from the event will be applied. * - * @param source the damage source applied to the entity and armor - * @param slots an array of applicable slots for damage - * @param damage the durability damage individual items will receive + * @param source the damage source applied to the entity and armor + * @param slots an array of applicable slots for damage + * @param damage the durability damage individual items will receive * @param armoredEntity the entity wearing the armor */ public static void onArmorHurt(DamageSource source, EquipmentSlot[] slots, float damage, LivingEntity armoredEntity) { @@ -1095,13 +1101,14 @@ public static void onEntityEnterSection(Entity entity, long packedOldPos, long p NeoForge.EVENT_BUS.post(new EntityEvent.EnteringSection(entity, packedOldPos, packedNewPos)); } - /**Creates, posts, and returns a {@link DamageBlockEvent}. This method is invoked in + /** + * Creates, posts, and returns a {@link DamageBlockEvent}. This method is invoked in * {@link LivingEntity#hurt(DamageSource, float)} and requires internal access to the * protected field {@link LivingEntity#damageContainer} as a parameter. * - * @param blocker the entity performing the block - * @param container the entity's internal damage container for accessing current values - * in the damage pipeline at the time of this invocation. + * @param blocker the entity performing the block + * @param container the entity's internal damage container for accessing current values + * in the damage pipeline at the time of this invocation. * @param originalBlocked whether this entity is blocking according to preceding/vanilla logic * @return the event object after event listeners have been invoked. */ diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 52f21bde4c..4cd78cea36 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -5,13 +5,9 @@ package net.neoforged.neoforge.common.damagesource; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; import java.util.function.BiFunction; import net.minecraft.world.damagesource.DamageSource; import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; -import org.jetbrains.annotations.ApiStatus; /** * DamageContainer encapsulates aspects of the entity damage sequence so that diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java index 050a2e1396..034fd5c00a 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java @@ -5,14 +5,13 @@ package net.neoforged.neoforge.common.damagesource; -import net.minecraft.world.damagesource.DamageSource; -import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; -import org.jetbrains.annotations.ApiStatus; - import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import java.util.function.BiFunction; +import net.minecraft.world.damagesource.DamageSource; +import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; +import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal public class InternalDamageContainer implements DamageContainer { diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java index fdd02fe9e1..56057ef1e4 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/ArmorHurtEvent.java @@ -14,7 +14,8 @@ import net.neoforged.bus.api.ICancellableEvent; import org.jetbrains.annotations.ApiStatus; -/**Fired on both sides when a {@link LivingEntity}'s armor is dealt damage in +/** + * Fired on both sides when a {@link LivingEntity}'s armor is dealt damage in * {@link LivingEntity#doHurtEquipment(DamageSource, float, EquipmentSlot...) doHurtEquipment}. */ public class ArmorHurtEvent extends LivingEvent implements ICancellableEvent { From f4920b771acc35871b17f1999fb9a80262bf5bfd Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Mon, 3 Jun 2024 07:17:38 -0400 Subject: [PATCH 18/41] restore actuallyHurt invul checks --- .../world/entity/LivingEntity.java.patch | 9 ++--- .../world/entity/player/Player.java.patch | 38 ++++++++----------- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index 43311833c5..78bfea9f10 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -386,11 +386,10 @@ } return p_21194_; -@@ -1698,23 +_,26 @@ - } +@@ -1699,20 +_,25 @@ protected void actuallyHurt(DamageSource p_21240_, float p_21241_) { -- if (!this.isInvulnerableTo(p_21240_)) { + if (!this.isInvulnerableTo(p_21240_)) { - p_21241_ = this.getDamageAfterArmorAbsorb(p_21240_, p_21241_); - p_21241_ = this.getDamageAfterMagicAbsorb(p_21240_, p_21241_); - float f1 = Math.max(p_21241_ - this.getAbsorptionAmount(), 0.0F); @@ -416,10 +415,8 @@ this.gameEvent(GameEvent.ENTITY_DAMAGE); + this.onDamageTaken(this.damageContainer); } -- } + } } - - public CombatTracker getCombatTracker() { @@ -1767,6 +_,8 @@ } diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index a8da3d2816..8cd2711c6a 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -170,45 +170,39 @@ if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -@@ -943,16 +_,18 @@ - +@@ -944,15 +_,18 @@ @Override protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { -- if (!this.isInvulnerableTo(p_36312_)) { + if (!this.isInvulnerableTo(p_36312_)) { - p_36313_ = this.getDamageAfterArmorAbsorb(p_36312_, p_36313_); - p_36313_ = this.getDamageAfterMagicAbsorb(p_36312_, p_36313_); - float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); - float f = p_36313_ - f1; -- if (f > 0.0F && f < 3.4028235E37F) { -- this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); -- } ++ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); ++ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ if (f1 <= 0) return; ++ float f = this.damageContainer.getNewDamage() - f1; + if (f > 0.0F && f < 3.4028235E37F) { + this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); + } - -+ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); -+ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); -+ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); -+ if (f1 <= 0) return; -+ float f = this.damageContainer.getNewDamage() - f1; -+ if (f > 0.0F && f < 3.4028235E37F) { -+ this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); -+ } -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); if (f1 != 0.0F) { this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); this.getCombatTracker().recordDamage(p_36312_, f1); -@@ -962,8 +_,8 @@ +@@ -962,6 +_,7 @@ } this.gameEvent(GameEvent.ENTITY_DAMAGE); + this.onDamageTaken(this.damageContainer); } -- } + } } - - @Override @@ -1011,6 +_,8 @@ return InteractionResult.PASS; From 3498f0df558fdcf21b4b4fd1bfb5a950b9261a9c Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Mon, 3 Jun 2024 17:06:45 -0400 Subject: [PATCH 19/41] collapse reduction methods --- .../world/entity/LivingEntity.java.patch | 12 ++-- .../world/entity/player/Player.java.patch | 8 +-- .../common/damagesource/DamageContainer.java | 55 ++++++------------- .../damagesource/InternalDamageContainer.java | 48 ++-------------- 4 files changed, 34 insertions(+), 89 deletions(-) diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index 78bfea9f10..ffa52c76d7 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -368,7 +368,7 @@ p_21194_ = Math.max(f / 25.0F, 0.0F); float f2 = f1 - p_21194_; if (f2 > 0.0F && f2 < 3.4028235E37F) { -+ this.damageContainer.setMobEffectReduction(f2); ++ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.MOB_EFFECTS, f2); if (this instanceof ServerPlayer) { - ((ServerPlayer)this).awardStat(Stats.DAMAGE_RESISTED, Math.round(f2 * 10.0F)); + ((ServerPlayer)this).awardStat(Stats.CUSTOM.get(Stats.DAMAGE_RESISTED), Math.round(f2 * 10.0F)); @@ -382,7 +382,7 @@ int k = EnchantmentHelper.getDamageProtection(this.getArmorAndBodyArmorSlots(), p_21193_); if (k > 0) { p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, (float)k); -+ this.damageContainer.setEnchantReduction(this.damageContainer.getNewDamage() - p_21194_); ++ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ENCHANTMENTS,this.damageContainer.getNewDamage() - p_21194_); } return p_21194_; @@ -395,11 +395,11 @@ - float f1 = Math.max(p_21241_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_21241_ - f1)); - float f = p_21241_ - f1; -+ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getNewDamage())); ++ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getNewDamage())); + this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainer.getNewDamage()); -+ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); ++ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getNewDamage() - f1)); + f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); + if (f1 <= 0) return; + float f = this.damageContainer.getNewDamage() - f1; diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index 8cd2711c6a..1798a2d93f 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -179,11 +179,11 @@ - float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); - float f = p_36313_ - f1; -+ this.damageContainer.setArmorReduction(this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); ++ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); + this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); -+ this.damageContainer.setAbsorption(this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getAbsorption(), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getAbsorption() - (this.damageContainer.getNewDamage() - f1)); ++ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getNewDamage() - f1)); + f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); + if (f1 <= 0) return; + float f = this.damageContainer.getNewDamage() - f1; diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 4cd78cea36..820ebb78c9 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -5,7 +5,11 @@ package net.neoforged.neoforge.common.damagesource; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.EnumMap; import java.util.function.BiFunction; +import java.util.stream.Collectors; import net.minecraft.world.damagesource.DamageSource; import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; @@ -36,9 +40,9 @@ public enum Reduction { /** Damage reduced from the effects of armor */ ARMOR, /** Damage reduced from enchantments on armor */ - ENCHANT, + ENCHANTMENTS, /** Damage reduced from active mob effects */ - MOBEFFECT, + MOB_EFFECTS, /** Damage absorbed by absorption. */ ABSORPTION } @@ -105,40 +109,14 @@ public enum Reduction { int getPostAttackInvulnerabilityTicks(); /** - * This provides a post-reduction value for armor reduction and modifiers. This will always return zero + * This provides a post-reduction value for the reduction and modifiers. This will always return zero * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all * modifiers prior to the event. * + * @param type the specific source type of the damage reduction * @return The amount of damage reduced by armor after vanilla armor reductions and added modifiers */ - float getArmorReduction(); - - /** - * This provides a post-reduction value for enchantment reduction and modifiers. This will always return zero - * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all - * modifiers prior to the event. - * - * @return the amount of damage reduced by enchantments after vanilla enchantment reductions and added modifiers - */ - float getEnchantReduction(); - - /** - * This provides a post-reduction value for mob effect reduction and modifiers. This will always return zero - * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all - * modifiers prior to the event. - * - * @return The amount of damage reduced by mob effects after vanilla mob effect reductions and added modifiers - */ - float getMobEffectReduction(); - - /** - * This provides a post-reduction value for absorption consumption and modifiers. This will always return zero - * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all - * modifiers prior to the event. - * - * @return The amount of absorption consumed after vanilla absorption consumption and added modifiers - */ - float getAbsorption(); + float getReduction(Reduction type); public record ResultDamageContainer( float getOriginalDamage, @@ -147,17 +125,15 @@ public record ResultDamageContainer( float getBlockedDamage, float getShieldDamage, int getPostAttackInvulnerabilityTicks, - float getArmorReduction, - float getEnchantReduction, - float getMobEffectReduction, - float getAbsorption + EnumMap reduction ) implements DamageContainer { public ResultDamageContainer(DamageContainer container) { this(container.getOriginalDamage(), container.getSource(), container.getNewDamage(), container.getBlockedDamage(), container.getShieldDamage(), container.getPostAttackInvulnerabilityTicks(), - container.getArmorReduction(), container.getEnchantReduction(), container.getMobEffectReduction(), - container.getAbsorption()); + new EnumMap(Arrays.stream(Reduction.values()) + .map(type -> new AbstractMap.SimpleEntry<>(type, container.getReduction(type))) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)))); } @Override @@ -168,5 +144,10 @@ public void setNewDamage(float damage) {} @Override public void setPostAttackInvulnerabilityTicks(int ticks) {} + + @Override + public float getReduction(Reduction type) { + return reduction().getOrDefault(type, 0f); + } } } diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java index 034fd5c00a..45fa386a69 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java @@ -19,10 +19,7 @@ public class InternalDamageContainer implements DamageContainer { private final float originalDamage; private final DamageSource source; private float newDamage; - private float armorReduction = 0f; - private float absorption = 0f; - private float enchantReduction = 0f; - private float mobEffectReduction = 0f; + EnumMap reductions = new EnumMap<>(Reduction.class); private float blockedDamage = 0f; private float shieldDamage = 0; private int invulnerabilityTicksAfterAttack = 20; @@ -78,23 +75,8 @@ public int getPostAttackInvulnerabilityTicks() { } @Override - public float getArmorReduction() { - return armorReduction; - } - - @Override - public float getEnchantReduction() { - return enchantReduction; - } - - @Override - public float getMobEffectReduction() { - return mobEffectReduction; - } - - @Override - public float getAbsorption() { - return absorption; + public float getReduction(Reduction type) { + return reductions.getOrDefault(type, 0f); } //=============INTERNAL METHODS - DO NOT USE=================== @@ -109,27 +91,9 @@ public void setBlockedDamage(DamageBlockEvent event) { } @ApiStatus.Internal - public void setAbsorption(float absorption) { - this.absorption = modifyReduction(Reduction.ABSORPTION, absorption); - this.newDamage -= Math.max(0, absorption); - } - - @ApiStatus.Internal - public void setMobEffectReduction(float reduction) { - this.mobEffectReduction = modifyReduction(Reduction.MOBEFFECT, reduction); - this.newDamage -= Math.max(0, reduction); - } - - @ApiStatus.Internal - public void setEnchantReduction(float reduction) { - this.enchantReduction = modifyReduction(Reduction.ENCHANT, reduction); - this.newDamage -= Math.max(0, reduction); - } - - @ApiStatus.Internal - public void setArmorReduction(float reduction) { - this.armorReduction = modifyReduction(Reduction.ARMOR, reduction); - this.newDamage -= Math.max(0, this.armorReduction); + public void setReduction(Reduction reduction, float amount) { + this.reductions.put(reduction, modifyReduction(Reduction.ABSORPTION, amount)); + this.newDamage -= Math.max(0, amount); } private float modifyReduction(Reduction type, float reduction) { From 85968d9a4a86816564a967e6b1654a84b5ad4b29 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Mon, 3 Jun 2024 17:11:25 -0400 Subject: [PATCH 20/41] remove FQNs from javadocs --- .../common/damagesource/DamageContainer.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 820ebb78c9..c11cb0b554 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -11,7 +11,12 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; +import net.neoforged.neoforge.event.entity.living.DamageTakenEvent; +import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; +import net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent; +import net.neoforged.neoforge.event.entity.living.IncomingDamageEvent; /** * DamageContainer encapsulates aspects of the entity damage sequence so that @@ -20,16 +25,16 @@ *

Note: certain values will be defaults until the stage in the sequence when they are set.

*

Damage Sequence and uses

    *
  1. Entity is hurt by a damage source
  2. - *
  3. {@link net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent EntityInvulnerablityCheckEvent} + *
  4. {@link EntityInvulnerablityCheckEvent EntityInvulnerablityCheckEvent} * fires and determines if the sequence can commence
  5. - *
  6. {@link net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent EntityPreDamageEvent} fires + *
  7. {@link EntityPreDamageEvent EntityPreDamageEvent} fires * and gives access to this. Modifiers should be added here.
  8. *
  9. {@link DamageBlockEvent} fires
  10. *
  11. armor, enchantments, mob effect, and absorption modifiers are applied to the damage
  12. - *
  13. {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent IncomingDamageEvent} fires and + *
  14. {@link IncomingDamageEvent IncomingDamageEvent} fires and * provides final values for the preceding modifiers and the last chance to negate the damage but will not * undo the preceding effects
  15. - *
  16. {@link net.neoforged.neoforge.event.entity.living.DamageTakenEvent DamageTakenEvent} fires and provides + *
  17. {@link DamageTakenEvent DamageTakenEvent} fires and provides * an immutable perspective of what the entire sequence ended with.
  18. *
* @@ -48,7 +53,7 @@ public enum Reduction { } /** - * @return the value passed into {@link net.minecraft.world.entity.LivingEntity#hurt(DamageSource, float)} before + * @return the value passed into {@link LivingEntity#hurt(DamageSource, float)} before * any modifications are made. */ float getOriginalDamage(); @@ -66,7 +71,7 @@ public enum Reduction { /** * Adds a callback modifier to the vanilla damage reductions. Each function will be performed in sequence * on the vanilla value at the time the {@link Reduction} type is set by vanilla. - *

Note: only the {@link net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent EntityPreDamageEvent} + *

Note: only the {@link EntityPreDamageEvent EntityPreDamageEvent} * happens early enough in the sequence for this method to have any effect.

* * @param type The reduction type your function will apply to @@ -86,12 +91,12 @@ public enum Reduction { void setNewDamage(float damage); /** - * @return The damage blocked during the {@link net.neoforged.neoforge.event.entity.living.DamageBlockEvent} + * @return The damage blocked during the {@link DamageBlockEvent} */ float getBlockedDamage(); /** - * @return The durability applied to the applicable shield after {@link net.neoforged.neoforge.event.entity.living.DamageBlockEvent} + * @return The durability applied to the applicable shield after {@link DamageBlockEvent} * returned a successful block */ float getShieldDamage(); @@ -110,7 +115,7 @@ public enum Reduction { /** * This provides a post-reduction value for the reduction and modifiers. This will always return zero - * before {@link net.neoforged.neoforge.event.entity.living.IncomingDamageEvent} and will consume all + * before {@link IncomingDamageEvent} and will consume all * modifiers prior to the event. * * @param type the specific source type of the damage reduction From 66d092e4159eacc2aa96c7fc1af8e9cf9b1b32f4 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Mon, 3 Jun 2024 17:50:30 -0400 Subject: [PATCH 21/41] fix missed formatting issue --- .../neoforged/neoforge/common/damagesource/DamageContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index c11cb0b554..1c1dcc19f3 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -12,9 +12,9 @@ import java.util.stream.Collectors; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; +import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; import net.neoforged.neoforge.event.entity.living.DamageTakenEvent; -import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; import net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent; import net.neoforged.neoforge.event.entity.living.IncomingDamageEvent; From 2a43729bc828e08a7b0b88d58b2b61af39b0df4b Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 6 Jun 2024 07:33:31 -0400 Subject: [PATCH 22/41] Update javadocs and formatting --- .../world/entity/LivingEntity.java.patch | 16 +++++++----- .../common/damagesource/DamageContainer.java | 8 ++++-- .../event/entity/living/DamageBlockEvent.java | 4 ++- .../event/entity/living/DamageTakenEvent.java | 25 +++++++------------ .../entity/living/EntityPreDamageEvent.java | 22 ++++++---------- .../entity/living/IncomingDamageEvent.java | 24 ++++++------------ 6 files changed, 44 insertions(+), 55 deletions(-) diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index ffa52c76d7..7a055d45a3 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -9,14 +9,16 @@ private static final Logger LOGGER = LogUtils.getLogger(); private static final String TAG_ACTIVE_EFFECTS = "active_effects"; private static final UUID SPEED_MODIFIER_SOUL_SPEED_UUID = UUID.fromString("87f46a96-686f-4796-b035-22e16ee9e038"); -@@ -242,6 +_,11 @@ +@@ -242,6 +_,13 @@ protected Brain brain; private boolean skipDropExperience; protected float appliedScale = 1.0F; -+ /**This field stores information about damage dealt to this entity. ++ /** ++ * This field stores information about damage dealt to this entity. + * The field is instantiated via {@link #hurt(DamageSource, float)} after -+ * invulnerability checks, and is nulllified before the method's return.*/ -+ @org.jetbrains.annotations.Nullable ++ * invulnerability checks, and is nulllified before the method's return. ++ * */ ++ @Nullable + protected net.neoforged.neoforge.common.damagesource.InternalDamageContainer damageContainer; protected LivingEntity(EntityType p_20966_, Level p_20967_) { @@ -140,7 +142,7 @@ float f = this.getHealth(); if (f > 0.0F) { this.setHealth(f + p_21116_); -@@ -1127,23 +_,28 @@ +@@ -1127,23 +_,30 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { @@ -162,7 +164,9 @@ + net.neoforged.neoforge.event.entity.living.DamageBlockEvent ev; + if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_))).getBlocked()) { + this.damageContainer.setBlockedDamage(ev); -+ if(ev.shieldDamage() > 0) this.hurtCurrentlyUsedShield(ev.shieldDamage()); ++ if(ev.shieldDamage() > 0) { ++ this.hurtCurrentlyUsedShield(ev.shieldDamage()); ++ } + f1 = ev.getBlockedDamage(); + p_21017_ = ev.getDamageContainer().getNewDamage(); if (!p_21016_.is(DamageTypeTags.IS_PROJECTILE) && p_21016_.getDirectEntity() instanceof LivingEntity livingentity) { diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 1c1dcc19f3..a8dd7bb1a7 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -145,10 +145,14 @@ public ResultDamageContainer(DamageContainer container) { public void addModifier(Reduction type, BiFunction function) {} @Override - public void setNewDamage(float damage) {} + public void setNewDamage(float damage) { + throw new IllegalStateException("Attempted to modify damage in an immutable context"); + } @Override - public void setPostAttackInvulnerabilityTicks(int ticks) {} + public void setPostAttackInvulnerabilityTicks(int ticks) { + throw new IllegalStateException("Attempted to modify invulnerability ticks in an immutable context"); + } @Override public float getReduction(Reduction type) { diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java index 0575be5c9a..a5ee9245f6 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java @@ -12,7 +12,7 @@ import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * The ShieldBlockEvent is fired when an entity is hurt and vanilla checks if the entity is attempting + * The DamageBlockEvent is fired when an entity is hurt and vanilla checks if the entity is attempting * to block with a shield.
* Cancelling this event will have the same impact as if the shield was not eligible to block.
* The damage blocked cannot be set lower than zero or greater than the original value.
@@ -20,6 +20,8 @@ * blocking logic is captured and passed into the event via {@link #getOriginalBlock()}. If this is * true, The shield item stack "should" be available from {@link LivingEntity#getUseItem()} at least * for players. + * + * @see DamageSequenceEvent */ public class DamageBlockEvent extends DamageSequenceEvent implements ICancellableEvent { private float dmgBlocked; diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java index f18889c21b..a66afeb682 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java @@ -5,31 +5,24 @@ package net.neoforged.neoforge.event.entity.living; -import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; -import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.CommonHooks; import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * LivingDamageEvent is fired just before damage is applied to entity.
- * At this point armor, potion and absorption modifiers have already been applied to damage - this is FINAL value.
- * Also note that appropriate resources (like armor durability and absorption extra hearths) have already been consumed.
- * This event is fired whenever an Entity is damaged in - * {@code LivingEntity#actuallyHurt(DamageSource, float)} and - * {@code Player#actuallyHurt(DamageSource, float)}.
- *
- * This event is fired via the {@link CommonHooks#onLivingDamage(LivingEntity, DamageSource, float)}.
+ * DamageTakenEvent is fired just before health is modified on the entity.
+ * At this point armor, potion and absorption modifiers have already been applied to damage. + * the {@link DamageContainer} is immutable and represents a FINAL value of what is about to + * be applied. *
- * {@link #source} contains the DamageSource that caused this Entity to be hurt.
- * {@link #amount} contains the final amount of damage that will be dealt to entity.
+ * Also note that appropriate resources (like armor durability and absorption extra hearts) have already been consumed.
+ * This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)} and + * {@code Player#actuallyHurt(DamageSource, float)}.
*
- * This event is {@link ICancellableEvent}.
- * If this event is canceled, the Entity is not hurt. Used resources WILL NOT be restored.
+ * This event is fired via {@link CommonHooks#onLivingDamageTaken(LivingEntity, DamageContainer)}.
*
- * This event does not have a result. {@link HasResult}
* - * @see IncomingDamageEvent + * @see DamageSequenceEvent **/ public class DamageTakenEvent extends DamageSequenceEvent { public DamageTakenEvent(LivingEntity entity, DamageContainer container) { diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java index ab430365bc..853ac77206 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java @@ -7,29 +7,23 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.CommonHooks; -import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * LivingAttackEvent is fired when a living Entity is attacked.
- * This event is fired whenever an Entity is attacked in - * {@link LivingEntity#hurt(DamageSource, float)} and - * {@link Player#hurt(DamageSource, float)}.
+ * LivingAttackEvent is fired when a living Entity is about to receive damage. *
- * This event is fired via the {@link CommonHooks#onLivingAttack(LivingEntity, DamageSource, float)}.
+ * This event is fired in {@link LivingEntity#hurt(DamageSource, float)} + * after invulnerability checks but before any damage processing/mitigation. *
- * {@link #source} contains the DamageSource of the attack.
- * {@link #amount} contains the amount of damage dealt to the entity.
+ * For custom posting of this event, the event expects to be fired before any + * damage reductions have been calculated. This event expects a mutable {@link DamageContainer}. *
- * This event is {@link net.neoforged.bus.api.ICancellableEvent}.
- * If this event is canceled, the Entity does not take attack damage.
+ * This event is fired via the {@link CommonHooks#onEntityPreDamage(LivingEntity, DamageContainer)}.
*
- * This event does not have a result. {@link HasResult}
- *
- * This event is fired on the {@link NeoForge#EVENT_BUS}. + * + * @see DamageSequenceEvent **/ public class EntityPreDamageEvent extends DamageSequenceEvent implements ICancellableEvent { public EntityPreDamageEvent(LivingEntity entity, DamageContainer container) { diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java index 730377575d..c9eafc8e17 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java @@ -5,31 +5,23 @@ package net.neoforged.neoforge.event.entity.living; -import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; -import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.CommonHooks; -import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * LivingHurtEvent is fired when an Entity is set to be hurt.
- * This event is fired whenever an Entity is hurt in - * {@code LivingEntity#actuallyHurt(DamageSource, float)} and - * {@code Player#actuallyHurt(DamageSource, float)}.
+ * IncomingDamageEvent is fired when an Entity is set to be hurt.
+ * This event is fired in {@code LivingEntity#hurt(DamageSource, float} and + * {@code Player#actuallyHurt(DamageSource, float)}. *
- * This event is fired via the {@link CommonHooks#onLivingHurt(LivingEntity, DamageSource, float)}.
+ * For custom posting of this event, the event expects to be fired after + * damage reductions have been calculated but before any changes to the entity + * health has been applied. This event expects a mutable {@link DamageContainer}. *
- * {@link #source} contains the DamageSource that caused this Entity to be hurt.
+ * This event is fired via the {@link CommonHooks#onIncomingDamage(LivingEntity, DamageContainer)}. *
- * This event is {@link ICancellableEvent}.
- * If this event is canceled, the Entity is not hurt.
- *
- * This event does not have a result. {@link HasResult}
- *
- * This event is fired on the {@link NeoForge#EVENT_BUS}. * - * @see DamageTakenEvent + * @see DamageSequenceEvent **/ public class IncomingDamageEvent extends DamageSequenceEvent { public IncomingDamageEvent(LivingEntity entity, DamageContainer source) { From 9fcd8ccaef3804c7beb36b1f571d1d6ac3f94cdf Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:39:43 -0400 Subject: [PATCH 23/41] refactor event names --- .../client/player/LocalPlayer.java.patch | 2 +- .../client/player/RemotePlayer.java.patch | 2 +- .../world/entity/LivingEntity.java.patch | 14 ++-- .../world/entity/player/Player.java.patch | 14 ++-- .../neoforge/common/CommonHooks.java | 37 +++++----- .../common/damagesource/DamageContainer.java | 23 +++--- .../damagesource/InternalDamageContainer.java | 4 +- .../entity/living/DamageSequenceEvent.java | 20 ++++- .../event/entity/living/DamageTakenEvent.java | 31 -------- .../entity/living/IncomingDamageEvent.java | 30 -------- .../entity/living/LivingDamageEvent.java | 74 +++++++++++++++++++ ...nt.java => LivingIncomingDamageEvent.java} | 9 ++- ...Event.java => LivingShieldBlockEvent.java} | 7 +- .../entity/living/LivingEntityEventTests.java | 4 +- 14 files changed, 149 insertions(+), 122 deletions(-) delete mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java delete mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java create mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java rename src/main/java/net/neoforged/neoforge/event/entity/living/{EntityPreDamageEvent.java => LivingIncomingDamageEvent.java} (70%) rename src/main/java/net/neoforged/neoforge/event/entity/living/{DamageBlockEvent.java => LivingShieldBlockEvent.java} (91%) diff --git a/patches/net/minecraft/client/player/LocalPlayer.java.patch b/patches/net/minecraft/client/player/LocalPlayer.java.patch index 55c270e2c6..4e7b967387 100644 --- a/patches/net/minecraft/client/player/LocalPlayer.java.patch +++ b/patches/net/minecraft/client/player/LocalPlayer.java.patch @@ -4,7 +4,7 @@ @Override public boolean hurt(DamageSource p_108662_, float p_108663_) { -+ net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer); ++ net.neoforged.neoforge.common.CommonHooks.onPlayerIncomingDamage(this, this.damageContainer); return false; } diff --git a/patches/net/minecraft/client/player/RemotePlayer.java.patch b/patches/net/minecraft/client/player/RemotePlayer.java.patch index 37a4483449..919be5f68e 100644 --- a/patches/net/minecraft/client/player/RemotePlayer.java.patch +++ b/patches/net/minecraft/client/player/RemotePlayer.java.patch @@ -4,7 +4,7 @@ @Override public boolean hurt(DamageSource p_108772_, float p_108773_) { -+ net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer); ++ net.neoforged.neoforge.common.CommonHooks.onPlayerIncomingDamage(this, this.damageContainer); return true; } diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index 7a055d45a3..54fbfceaa5 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -147,7 +147,7 @@ return false; } else { + this.damageContainer = this.damageContainer == null ? new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_21016_, p_21017_) : this.damageContainer; -+ if (!net.neoforged.neoforge.common.CommonHooks.onEntityPreDamage(this, this.damageContainer)) return false; ++ if (!net.neoforged.neoforge.common.CommonHooks.onEntityIncomingDamage(this, this.damageContainer)) return false; if (this.isSleeping() && !this.level().isClientSide) { this.stopSleeping(); } @@ -161,7 +161,7 @@ - this.hurtCurrentlyUsedShield(p_21017_); - f1 = p_21017_; - p_21017_ = 0.0F; -+ net.neoforged.neoforge.event.entity.living.DamageBlockEvent ev; ++ net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent ev; + if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_))).getBlocked()) { + this.damageContainer.setBlockedDamage(ev); + if(ev.shieldDamage() > 0) { @@ -390,7 +390,7 @@ } return p_21194_; -@@ -1699,20 +_,25 @@ +@@ -1699,11 +_,14 @@ protected void actuallyHurt(DamageSource p_21240_, float p_21241_) { if (!this.isInvulnerableTo(p_21240_)) { @@ -404,20 +404,18 @@ + this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); + float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); + this.setAbsorptionAmount(this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer); + if (f1 <= 0) return; + float f = this.damageContainer.getNewDamage() - f1; if (f > 0.0F && f < 3.4028235E37F && p_21240_.getEntity() instanceof ServerPlayer serverplayer) { serverplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f * 10.0F)); } - -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); - if (f1 != 0.0F) { - this.getCombatTracker().recordDamage(p_21240_, f1); +@@ -1713,6 +_,8 @@ this.setHealth(this.getHealth() - f1); this.setAbsorptionAmount(this.getAbsorptionAmount() - f1); this.gameEvent(GameEvent.ENTITY_DAMAGE); + this.onDamageTaken(this.damageContainer); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer); } } } diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index 1798a2d93f..ab6e420b4e 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -118,7 +118,7 @@ return false; } else { + this.damageContainer = new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_36154_, p_36155_); -+ if (!net.neoforged.neoforge.common.CommonHooks.onPlayerEntityPreDamage(this, this.damageContainer)) return false; ++ if (!net.neoforged.neoforge.common.CommonHooks.onPlayerIncomingDamage(this, this.damageContainer)) return false; this.noActionTime = 0; if (this.isDeadOrDying()) { return false; @@ -170,7 +170,7 @@ if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -@@ -944,15 +_,18 @@ +@@ -944,15 +_,17 @@ @Override protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { if (!this.isInvulnerableTo(p_36312_)) { @@ -184,22 +184,24 @@ + this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); + float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); + this.setAbsorptionAmount(this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onIncomingDamage(this, this.damageContainer); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer); + if (f1 <= 0) return; + float f = this.damageContainer.getNewDamage() - f1; if (f > 0.0F && f < 3.4028235E37F) { this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); } - -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamageTaken(this, this.damageContainer); if (f1 != 0.0F) { this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); this.getCombatTracker().recordDamage(p_36312_, f1); -@@ -962,6 +_,7 @@ +@@ -960,8 +_,9 @@ + if (f1 < 3.4028235E37F) { + this.awardStat(Stats.DAMAGE_TAKEN, Math.round(f1 * 10.0F)); } - +- this.gameEvent(GameEvent.ENTITY_DAMAGE); + this.onDamageTaken(this.damageContainer); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer); } } } diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index a8b1326314..c5f6bbae48 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -166,20 +166,19 @@ import net.neoforged.neoforge.event.entity.EntityTravelToDimensionEvent; import net.neoforged.neoforge.event.entity.item.ItemTossEvent; import net.neoforged.neoforge.event.entity.living.ArmorHurtEvent; -import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; -import net.neoforged.neoforge.event.entity.living.DamageTakenEvent; import net.neoforged.neoforge.event.entity.living.EnderManAngerEvent; -import net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent; -import net.neoforged.neoforge.event.entity.living.IncomingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingBreatheEvent; import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent; +import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingDeathEvent; import net.neoforged.neoforge.event.entity.living.LivingDropsEvent; import net.neoforged.neoforge.event.entity.living.LivingDrownEvent; import net.neoforged.neoforge.event.entity.living.LivingEvent; import net.neoforged.neoforge.event.entity.living.LivingFallEvent; import net.neoforged.neoforge.event.entity.living.LivingGetProjectileEvent; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingKnockBackEvent; +import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; import net.neoforged.neoforge.event.entity.living.LivingSwapItemsEvent; import net.neoforged.neoforge.event.entity.living.LivingUseTotemEvent; import net.neoforged.neoforge.event.entity.living.LootingLevelEvent; @@ -256,15 +255,15 @@ public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource so /** * Called after invulnerability checks in {@link LivingEntity#hurt(DamageSource, float)}, * this method creates and posts the first event in the LivingEntity damage sequence, - * {@link EntityPreDamageEvent}, FOR NON-PLAYER entities. + * {@link LivingIncomingDamageEvent}, FOR NON-PLAYER entities. * * @param entity the entity to receive damage * @param container the newly instantiated container for damage to be dealt. Most properties of * the container will be empty at this stage. * @return if the event is cancelled and no damage will be applied to the entity */ - public static boolean onEntityPreDamage(LivingEntity entity, DamageContainer container) { - return entity instanceof Player || !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); + public static boolean onEntityIncomingDamage(LivingEntity entity, DamageContainer container) { + return entity instanceof Player || !NeoForge.EVENT_BUS.post(new LivingIncomingDamageEvent(entity, container)).isCanceled(); } /** @@ -272,15 +271,15 @@ public static boolean onEntityPreDamage(LivingEntity entity, DamageContainer con * {@link net.minecraft.client.player.LocalPlayer#hurt(DamageSource, float)}, and * {@link net.minecraft.client.player.RemotePlayer#hurt(DamageSource, float)}, * this method creates and posts the first event in the LivingEntity damage sequence, - * {@link EntityPreDamageEvent}, for player entities. + * {@link LivingIncomingDamageEvent}, for player entities. * * @param entity the player to receive damage * @param container the newly instantiated container for damage to be dealt. Most properties of * the container will be empty at this stage. * @return if the event is cancelled and no damage will be applied to the entity */ - public static boolean onPlayerEntityPreDamage(LivingEntity entity, DamageContainer container) { - return !NeoForge.EVENT_BUS.post(new EntityPreDamageEvent(entity, container)).isCanceled(); + public static boolean onPlayerIncomingDamage(LivingEntity entity, DamageContainer container) { + return !NeoForge.EVENT_BUS.post(new LivingIncomingDamageEvent(entity, container)).isCanceled(); } public static LivingKnockBackEvent onLivingKnockBack(LivingEntity target, float strength, double ratioX, double ratioZ) { @@ -294,7 +293,7 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS } /** - * Creates and posts an {@link IncomingDamageEvent}. This is invoked in + * Creates and posts an {@link LivingDamageEvent.Pre}. This is invoked in * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. * @@ -304,12 +303,12 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS * @return the current damage value to be applied to the entity's health * */ - public static float onIncomingDamage(LivingEntity entity, DamageContainer container) { - return NeoForge.EVENT_BUS.post(new IncomingDamageEvent(entity, container)).getDamageContainer().getNewDamage(); + public static float onLivingDamagePre(LivingEntity entity, DamageContainer container) { + return NeoForge.EVENT_BUS.post(new LivingDamageEvent.Pre(entity, container)).getDamageContainer().getNewDamage(); } /** - * Creates and posts a {@link DamageTakenEvent}. This is invoked in + * Creates and posts a {@link LivingDamageEvent.Post}. This is invoked in * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. * @@ -317,8 +316,8 @@ public static float onIncomingDamage(LivingEntity entity, DamageContainer contai * @param container the container object holding the truly final values of the damage pipeline. This * instance is immutable. */ - public static void onLivingDamageTaken(LivingEntity entity, DamageContainer container) { - NeoForge.EVENT_BUS.post(new DamageTakenEvent(entity, new DamageContainer.ResultDamageContainer(container))); + public static void onLivingDamagePost(LivingEntity entity, DamageContainer container) { + NeoForge.EVENT_BUS.post(new LivingDamageEvent.Post(entity, new DamageContainer.ResultDamageContainer(container))); } /** @@ -1102,7 +1101,7 @@ public static void onEntityEnterSection(Entity entity, long packedOldPos, long p } /** - * Creates, posts, and returns a {@link DamageBlockEvent}. This method is invoked in + * Creates, posts, and returns a {@link LivingShieldBlockEvent}. This method is invoked in * {@link LivingEntity#hurt(DamageSource, float)} and requires internal access to the * protected field {@link LivingEntity#damageContainer} as a parameter. * @@ -1112,8 +1111,8 @@ public static void onEntityEnterSection(Entity entity, long packedOldPos, long p * @param originalBlocked whether this entity is blocking according to preceding/vanilla logic * @return the event object after event listeners have been invoked. */ - public static DamageBlockEvent onDamageBlock(LivingEntity blocker, DamageContainer container, boolean originalBlocked) { - DamageBlockEvent e = new DamageBlockEvent(blocker, container, originalBlocked); + public static LivingShieldBlockEvent onDamageBlock(LivingEntity blocker, DamageContainer container, boolean originalBlocked) { + LivingShieldBlockEvent e = new LivingShieldBlockEvent(blocker, container, originalBlocked); NeoForge.EVENT_BUS.post(e); return e; } diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index a8dd7bb1a7..b870acdf56 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -13,10 +13,9 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; -import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; -import net.neoforged.neoforge.event.entity.living.DamageTakenEvent; -import net.neoforged.neoforge.event.entity.living.EntityPreDamageEvent; -import net.neoforged.neoforge.event.entity.living.IncomingDamageEvent; +import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; +import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; /** * DamageContainer encapsulates aspects of the entity damage sequence so that @@ -27,14 +26,14 @@ *
  • Entity is hurt by a damage source
  • *
  • {@link EntityInvulnerablityCheckEvent EntityInvulnerablityCheckEvent} * fires and determines if the sequence can commence
  • - *
  • {@link EntityPreDamageEvent EntityPreDamageEvent} fires + *
  • {@link LivingIncomingDamageEvent EntityPreDamageEvent} fires * and gives access to this. Modifiers should be added here.
  • - *
  • {@link DamageBlockEvent} fires
  • + *
  • {@link LivingShieldBlockEvent} fires
  • *
  • armor, enchantments, mob effect, and absorption modifiers are applied to the damage
  • - *
  • {@link IncomingDamageEvent IncomingDamageEvent} fires and + *
  • {@link LivingDamageEvent.Pre IncomingDamageEvent} fires and * provides final values for the preceding modifiers and the last chance to negate the damage but will not * undo the preceding effects
  • - *
  • {@link DamageTakenEvent DamageTakenEvent} fires and provides + *
  • {@link LivingDamageEvent.Post DamageTakenEvent} fires and provides * an immutable perspective of what the entire sequence ended with.
  • * * @@ -71,7 +70,7 @@ public enum Reduction { /** * Adds a callback modifier to the vanilla damage reductions. Each function will be performed in sequence * on the vanilla value at the time the {@link Reduction} type is set by vanilla. - *

    Note: only the {@link EntityPreDamageEvent EntityPreDamageEvent} + *

    Note: only the {@link LivingIncomingDamageEvent EntityPreDamageEvent} * happens early enough in the sequence for this method to have any effect.

    * * @param type The reduction type your function will apply to @@ -91,12 +90,12 @@ public enum Reduction { void setNewDamage(float damage); /** - * @return The damage blocked during the {@link DamageBlockEvent} + * @return The damage blocked during the {@link LivingShieldBlockEvent} */ float getBlockedDamage(); /** - * @return The durability applied to the applicable shield after {@link DamageBlockEvent} + * @return The durability applied to the applicable shield after {@link LivingShieldBlockEvent} * returned a successful block */ float getShieldDamage(); @@ -115,7 +114,7 @@ public enum Reduction { /** * This provides a post-reduction value for the reduction and modifiers. This will always return zero - * before {@link IncomingDamageEvent} and will consume all + * before {@link LivingDamageEvent.Pre} and will consume all * modifiers prior to the event. * * @param type the specific source type of the damage reduction diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java index 45fa386a69..6156062459 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java @@ -10,7 +10,7 @@ import java.util.List; import java.util.function.BiFunction; import net.minecraft.world.damagesource.DamageSource; -import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; +import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal @@ -82,7 +82,7 @@ public float getReduction(Reduction type) { //=============INTERNAL METHODS - DO NOT USE=================== @ApiStatus.Internal - public void setBlockedDamage(DamageBlockEvent event) { + public void setBlockedDamage(LivingShieldBlockEvent event) { if (event.getBlocked()) { this.blockedDamage = event.getBlockedDamage(); this.shieldDamage = event.shieldDamage(); diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java index f6ec6735cb..a39c427d8f 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java @@ -8,11 +8,11 @@ import net.minecraft.world.entity.LivingEntity; import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.damagesource.DamageContainer; +import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; /** - * DamageSequenceEvent is not, and should not be, directly invoked. Instead, - * implementations of this class should be used to allow simple discrimination - * of where in the damage sequence the {@link DamageContainer} is. + * DamageSequenceEvent provides a DamageContainer to its subclasses. Subscribe to + * the correct subclass of DamageSequenceEvent for your use case. *
    * The {@link DamageContainer container} can be accessed to modify or obtain values * from the damage sequence. Note that depending on where in the damage sequence @@ -22,6 +22,20 @@ * This event is not {@link ICancellableEvent} by default. Implementation classes * can implement this interface if their corresponding hooks effectively terminate * the damage sequence. + *
    + *

    The Damage Sequence

    + *
      + *
    1. {@link LivingEntity#hurt} is invoked on the recipient from the source of + * the attack.
    2. + *
    3. {@link Entity#isInvulnerableTo} is invoked and fires {@link EntityInvulnerablityCheckEvent}
    4. + *
    5. After determining the entity is vulnerable, the {@link DamageContainer} in instantiated for the entity
    6. + *
    7. {@link LivingIncomingDamageEvent} is fired
    8. + *
    9. {@link LivingShieldBlockEvent} fires and the result determines if shield effects apply
    10. + *
    11. {@link LivingEntity#actuallyHurt} is called.
    12. + *
    13. armor, magic, mob_effect, and absorption reductions are captured in the DamageContainer
    14. + *
    15. {@link LivingDamageEvent.Pre} is fired
    16. + *
    17. if the damage is not zero, entity health is modified and recorded and {@link LivingDamageEvent.Post} is fired
    18. + *
    */ public abstract class DamageSequenceEvent extends LivingEvent { final DamageContainer container; diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java deleted file mode 100644 index a66afeb682..0000000000 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageTakenEvent.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.event.entity.living; - -import net.minecraft.world.entity.LivingEntity; -import net.neoforged.neoforge.common.CommonHooks; -import net.neoforged.neoforge.common.damagesource.DamageContainer; - -/** - * DamageTakenEvent is fired just before health is modified on the entity.
    - * At this point armor, potion and absorption modifiers have already been applied to damage. - * the {@link DamageContainer} is immutable and represents a FINAL value of what is about to - * be applied. - *
    - * Also note that appropriate resources (like armor durability and absorption extra hearts) have already been consumed.
    - * This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)} and - * {@code Player#actuallyHurt(DamageSource, float)}.
    - *
    - * This event is fired via {@link CommonHooks#onLivingDamageTaken(LivingEntity, DamageContainer)}.
    - *
    - * - * @see DamageSequenceEvent - **/ -public class DamageTakenEvent extends DamageSequenceEvent { - public DamageTakenEvent(LivingEntity entity, DamageContainer container) { - super(entity, container); - } -} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java deleted file mode 100644 index c9eafc8e17..0000000000 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/IncomingDamageEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.event.entity.living; - -import net.minecraft.world.entity.LivingEntity; -import net.neoforged.neoforge.common.CommonHooks; -import net.neoforged.neoforge.common.damagesource.DamageContainer; - -/** - * IncomingDamageEvent is fired when an Entity is set to be hurt.
    - * This event is fired in {@code LivingEntity#hurt(DamageSource, float} and - * {@code Player#actuallyHurt(DamageSource, float)}. - *
    - * For custom posting of this event, the event expects to be fired after - * damage reductions have been calculated but before any changes to the entity - * health has been applied. This event expects a mutable {@link DamageContainer}. - *
    - * This event is fired via the {@link CommonHooks#onIncomingDamage(LivingEntity, DamageContainer)}. - *
    - * - * @see DamageSequenceEvent - **/ -public class IncomingDamageEvent extends DamageSequenceEvent { - public IncomingDamageEvent(LivingEntity entity, DamageContainer source) { - super(entity, source); - } -} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java new file mode 100644 index 0000000000..27605cce7c --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.event.entity.living; + +import net.minecraft.world.entity.LivingEntity; +import net.neoforged.neoforge.common.CommonHooks; +import net.neoforged.neoforge.common.damagesource.DamageContainer; + +/** + * LivingDamage event captures when an entity is about to receive a loss + * of health. At this stage in the damage sequence, all reduction effects + * have been applied. + *
    + * {@link Pre} allows for modification of the damage value before it is applied + * to the entity's health. + *
    + * {@link Post} contains an immutable representation of the entire damage sequence + * and allows for reference to the values accrued at each step. + * + * For more information on the damage sequence + * + * @see DamageSequenceEvent + */ +public abstract class LivingDamageEvent extends DamageSequenceEvent { + private LivingDamageEvent(LivingEntity entity, DamageContainer container) { + super(entity, container); + } + + /** + * IncomingDamageEvent is fired when an Entity is set to be hurt.
    + * This event is fired in {@code LivingEntity#hurt(DamageSource, float} and + * {@code Player#actuallyHurt(DamageSource, float)}. + *
    + * For custom posting of this event, the event expects to be fired after + * damage reductions have been calculated but before any changes to the entity + * health has been applied. This event expects a mutable {@link DamageContainer}. + *
    + * This event is fired via the {@link CommonHooks#onLivingDamagePre(LivingEntity, DamageContainer)}. + *
    + * For more information on the damage sequence + * + * @see DamageSequenceEvent + **/ + public static class Pre extends LivingDamageEvent { + public Pre(LivingEntity entity, DamageContainer source) { + super(entity, source); + } + } + + /** + * DamageTakenEvent is fired just before health is modified on the entity.
    + * At this point armor, potion and absorption modifiers have already been applied to damage. + * the {@link DamageContainer} is immutable and represents a FINAL value of what is about to + * be applied. + *
    + * Also note that appropriate resources (like armor durability and absorption extra hearts) have already been consumed.
    + * This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)} and + * {@code Player#actuallyHurt(DamageSource, float)}.
    + *
    + * This event is fired via {@link CommonHooks#onLivingDamagePost(LivingEntity, DamageContainer)}.
    + *
    + * For more information on the damage sequence + * + * @see DamageSequenceEvent + **/ + public static class Post extends LivingDamageEvent { + public Post(LivingEntity entity, DamageContainer container) { + super(entity, container); + } + } +} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java similarity index 70% rename from src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java rename to src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java index 853ac77206..df88ecfca2 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/EntityPreDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java @@ -12,7 +12,7 @@ import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * LivingAttackEvent is fired when a living Entity is about to receive damage. + * LivingIncomingDamageEvent is fired when a LivingEntity is about to receive damage. *
    * This event is fired in {@link LivingEntity#hurt(DamageSource, float)} * after invulnerability checks but before any damage processing/mitigation. @@ -20,13 +20,14 @@ * For custom posting of this event, the event expects to be fired before any * damage reductions have been calculated. This event expects a mutable {@link DamageContainer}. *
    - * This event is fired via the {@link CommonHooks#onEntityPreDamage(LivingEntity, DamageContainer)}.
    + * This event is fired via the {@link CommonHooks#onEntityIncomingDamage(LivingEntity, DamageContainer)}.
    *
    + * For more information on the damage sequence * * @see DamageSequenceEvent **/ -public class EntityPreDamageEvent extends DamageSequenceEvent implements ICancellableEvent { - public EntityPreDamageEvent(LivingEntity entity, DamageContainer container) { +public class LivingIncomingDamageEvent extends DamageSequenceEvent implements ICancellableEvent { + public LivingIncomingDamageEvent(LivingEntity entity, DamageContainer container) { super(entity, container); } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java similarity index 91% rename from src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java rename to src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java index a5ee9245f6..750e2714ef 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java @@ -12,7 +12,7 @@ import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * The DamageBlockEvent is fired when an entity is hurt and vanilla checks if the entity is attempting + * LivingShieldBlockEvent is fired when an entity is hurt and vanilla checks if the entity is attempting * to block with a shield.
    * Cancelling this event will have the same impact as if the shield was not eligible to block.
    * The damage blocked cannot be set lower than zero or greater than the original value.
    @@ -20,16 +20,17 @@ * blocking logic is captured and passed into the event via {@link #getOriginalBlock()}. If this is * true, The shield item stack "should" be available from {@link LivingEntity#getUseItem()} at least * for players. + * For more information on the damage sequence * * @see DamageSequenceEvent */ -public class DamageBlockEvent extends DamageSequenceEvent implements ICancellableEvent { +public class LivingShieldBlockEvent extends DamageSequenceEvent implements ICancellableEvent { private float dmgBlocked; private float shieldDamage = -1; private final boolean originalBlocked; private boolean newBlocked; - public DamageBlockEvent(LivingEntity blocker, DamageContainer container, boolean originalBlockedState) { + public LivingShieldBlockEvent(LivingEntity blocker, DamageContainer container, boolean originalBlockedState) { super(blocker, container); this.dmgBlocked = container.getNewDamage(); this.originalBlocked = originalBlockedState; diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java index 3e7350b248..647ad33bd2 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java @@ -39,11 +39,11 @@ import net.minecraft.world.level.GameType; import net.neoforged.fml.util.ObfuscationReflectionHelper; import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent; -import net.neoforged.neoforge.event.entity.living.DamageBlockEvent; import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent; import net.neoforged.neoforge.event.entity.living.LivingConversionEvent; import net.neoforged.neoforge.event.entity.living.LivingEntityUseItemEvent; import net.neoforged.neoforge.event.entity.living.LivingGetProjectileEvent; +import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; import net.neoforged.neoforge.event.entity.living.LivingSwapItemsEvent; import net.neoforged.neoforge.event.entity.living.MobSplitEvent; import net.neoforged.testframework.DynamicTest; @@ -188,7 +188,7 @@ static void setAttackTargetEvent(final DynamicTest test, final RegistrationHelpe @EmptyTemplate(floor = true) @TestHolder(description = "Tests if the ShieldBlockEvent is fired") static void shieldBlockEvent(final DynamicTest test) { - test.eventListeners().forge().addListener((final DamageBlockEvent event) -> { + test.eventListeners().forge().addListener((final LivingShieldBlockEvent event) -> { if (event.getBlocked() && event.getDamageSource().getDirectEntity() instanceof AbstractArrow arrow && event.getEntity() instanceof Zombie zombie && Objects.equals(zombie.getName(), Component.literal("shieldblock"))) { zombie.setItemSlot(EquipmentSlot.OFFHAND, new ItemStack(Items.STONE)); event.setBlockedDamage(event.getOriginalBlockedDamage() / 2); From 4b092175fcd2f70fbbdee958148f128b69eadf0a Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:17:53 -0400 Subject: [PATCH 24/41] fix merge error --- .../debug/entity/EntityEventTests.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java index c70875cc7c..d793cb3ee4 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java @@ -16,10 +16,10 @@ import net.minecraft.world.entity.animal.Pig; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.phys.Vec3; -import net.minecraft.world.level.GameType; import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; import net.neoforged.neoforge.event.entity.EntityTeleportEvent; @@ -80,25 +80,6 @@ static void entityAttributeModificationEvent(final DynamicTest test, final Regis .thenSucceed()); } - @GameTest - @EmptyTemplate(value = "15x5x15", floor = true) - @TestHolder(description = "Tests if the pig only gets vertical knockback from explosion knockback event") - static void entityVerticalExplosionKnockbackEvent(final DynamicTest test) { - test.eventListeners().forge().addListener((final ExplosionKnockbackEvent event) -> { - if (event.getAffectedEntity() instanceof Pig) { - event.setKnockbackVelocity(new Vec3(0, event.getKnockbackVelocity().y(), 0)); - } - }); - - test.onGameTest(helper -> helper.startSequence(() -> helper.spawnWithNoFreeWill(EntityType.PIG, 8, 3, 7)) - .thenExecute(pig -> helper.setBlock(8, 2, 7, Blocks.ACACIA_LEAVES)) - .thenExecute(pig -> helper.getLevel().explode(null, helper.getLevel().damageSources().generic(), null, helper.absolutePos(new BlockPos(7, 2, 7)).getCenter(), 2f, false, Level.ExplosionInteraction.TNT)) - .thenExecute(pig -> helper.assertEntityProperty(pig, p -> pig.getDeltaMovement().x() == 0 && pig.getDeltaMovement().y() != 0 && pig.getDeltaMovement().z() == 0, "Check explosion Knockback")) - .thenIdle(10) - .thenExecute(helper::killAllEntities) - .thenSucceed()); - } - @GameTest @EmptyTemplate @TestHolder(description = "Tests if EntityInvulnerabilityCheckEvent prevents damage when modified.") @@ -116,4 +97,23 @@ static void entityInvulnerabilityCheckEvent(final DynamicTest test, final Regist .thenSucceed(); }); } + + @GameTest + @EmptyTemplate(value = "15x5x15", floor = true) + @TestHolder(description = "Tests if the pig only gets vertical knockback from explosion knockback event") + static void entityVerticalExplosionKnockbackEvent(final DynamicTest test) { + test.eventListeners().forge().addListener((final ExplosionKnockbackEvent event) -> { + if (event.getAffectedEntity() instanceof Pig) { + event.setKnockbackVelocity(new Vec3(0, event.getKnockbackVelocity().y(), 0)); + } + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.spawnWithNoFreeWill(EntityType.PIG, 8, 3, 7)) + .thenExecute(pig -> helper.setBlock(8, 2, 7, Blocks.ACACIA_LEAVES)) + .thenExecute(pig -> helper.getLevel().explode(null, helper.getLevel().damageSources().generic(), null, helper.absolutePos(new BlockPos(7, 2, 7)).getCenter(), 2f, false, Level.ExplosionInteraction.BLOW)) + .thenExecute(pig -> helper.assertEntityProperty(pig, p -> pig.getDeltaMovement().x() == 0 && pig.getDeltaMovement().y() != 0 && pig.getDeltaMovement().z() == 0, "Check explosion Knockback")) + .thenIdle(10) + .thenExecute(helper::killAllEntities) + .thenSucceed()); + } } From c32dc60963ee78d91407e09d8592c7be078f9886 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:23:38 -0400 Subject: [PATCH 25/41] event refactor in tests fix --- .../java/net/neoforged/neoforge/debug/data/DataMapTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java index 2810cf86cc..eb1e559dd3 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java @@ -38,7 +38,7 @@ import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.data.DataMapProvider; import net.neoforged.neoforge.debug.EventTests; -import net.neoforged.neoforge.event.entity.living.DamageTakenEvent; +import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; import net.neoforged.neoforge.event.entity.player.UseItemOnBlockEvent; import net.neoforged.neoforge.registries.datamaps.AdvancedDataMapType; import net.neoforged.neoforge.registries.datamaps.DataMapType; @@ -276,7 +276,7 @@ protected void gather() { } }); - test.eventListeners().forge().addListener((final DamageTakenEvent event) -> { + test.eventListeners().forge().addListener((final LivingDamageEvent.Post event) -> { final ExperienceGrant grant = event.getDamageContainer().getSource().typeHolder().getData(xpGrant); if (grant != null && event.getEntity() instanceof Player player) { player.giveExperiencePoints(grant.amount()); From 00d7a6577bdefb20cecbc21cf3bcfd97ba92e8a7 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 6 Jun 2024 22:19:48 -0400 Subject: [PATCH 26/41] update javadoc and fix name typo --- .../java/net/neoforged/neoforge/common/CommonHooks.java | 6 +++--- .../neoforge/common/damagesource/DamageContainer.java | 4 ++-- ...heckEvent.java => EntityInvulnerabilityCheckEvent.java} | 7 +++++-- .../neoforge/event/entity/living/DamageSequenceEvent.java | 4 ++-- .../neoforged/neoforge/debug/entity/EntityEventTests.java | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) rename src/main/java/net/neoforged/neoforge/event/entity/{EntityInvulnerablityCheckEvent.java => EntityInvulnerabilityCheckEvent.java} (81%) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index c5f6bbae48..8956d7a750 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -162,7 +162,7 @@ import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent; import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; import net.neoforged.neoforge.event.entity.EntityEvent; -import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; +import net.neoforged.neoforge.event.entity.EntityInvulnerabilityCheckEvent; import net.neoforged.neoforge.event.entity.EntityTravelToDimensionEvent; import net.neoforged.neoforge.event.entity.item.ItemTossEvent; import net.neoforged.neoforge.event.entity.living.ArmorHurtEvent; @@ -239,7 +239,7 @@ public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, } /** - * Creates and posts an {@link EntityInvulnerablityCheckEvent}. This is invoked in + * Creates and posts an {@link EntityInvulnerabilityCheckEvent}. This is invoked in * {@link Entity#isInvulnerableTo(DamageSource)} and returns a post-listener result * to the invulnerability status of the entity to the damage source. * @@ -249,7 +249,7 @@ public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, * @return if this entity is invulnerable */ public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource source, boolean isInvul) { - return NeoForge.EVENT_BUS.post(new EntityInvulnerablityCheckEvent(entity, source, isInvul)).isInvulnerable(); + return NeoForge.EVENT_BUS.post(new EntityInvulnerabilityCheckEvent(entity, source, isInvul)).isInvulnerable(); } /** diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index b870acdf56..91ac854153 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -12,7 +12,7 @@ import java.util.stream.Collectors; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; -import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; +import net.neoforged.neoforge.event.entity.EntityInvulnerabilityCheckEvent; import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; @@ -24,7 +24,7 @@ *

    Note: certain values will be defaults until the stage in the sequence when they are set.

    *

    Damage Sequence and uses

      *
    1. Entity is hurt by a damage source
    2. - *
    3. {@link EntityInvulnerablityCheckEvent EntityInvulnerablityCheckEvent} + *
    4. {@link EntityInvulnerabilityCheckEvent EntityInvulnerablityCheckEvent} * fires and determines if the sequence can commence
    5. *
    6. {@link LivingIncomingDamageEvent EntityPreDamageEvent} fires * and gives access to this. Modifiers should be added here.
    7. diff --git a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java similarity index 81% rename from src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java rename to src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java index 38e8a33335..8d1b800fe3 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerablityCheckEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java @@ -13,14 +13,17 @@ * Fired when {@link Entity#hurt(DamageSource, float)} is invoked and determines if * downstream hurt logic should apply. This event is fired on both sides in * {@link Entity#isInvulnerableTo(DamageSource)} + *
      + * Note: This event may be unable to change the invulnerable status of some entities + * that override isInvulnerableTo against certain damage sources */ -public class EntityInvulnerablityCheckEvent extends EntityEvent { +public class EntityInvulnerabilityCheckEvent extends EntityEvent { private final boolean originallyInvulnerable; private boolean isInvulnerable; private final DamageSource source; @ApiStatus.Internal - public EntityInvulnerablityCheckEvent(Entity entity, DamageSource source, boolean isVanillaInvulnerable) { + public EntityInvulnerabilityCheckEvent(Entity entity, DamageSource source, boolean isVanillaInvulnerable) { super(entity); this.originallyInvulnerable = isVanillaInvulnerable; this.isInvulnerable = isVanillaInvulnerable; diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java index a39c427d8f..6f8f02fa2a 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java @@ -8,7 +8,7 @@ import net.minecraft.world.entity.LivingEntity; import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.damagesource.DamageContainer; -import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; +import net.neoforged.neoforge.event.entity.EntityInvulnerabilityCheckEvent; /** * DamageSequenceEvent provides a DamageContainer to its subclasses. Subscribe to @@ -27,7 +27,7 @@ *
        *
      1. {@link LivingEntity#hurt} is invoked on the recipient from the source of * the attack.
      2. - *
      3. {@link Entity#isInvulnerableTo} is invoked and fires {@link EntityInvulnerablityCheckEvent}
      4. + *
      5. {@link Entity#isInvulnerableTo} is invoked and fires {@link EntityInvulnerabilityCheckEvent}
      6. *
      7. After determining the entity is vulnerable, the {@link DamageContainer} in instantiated for the entity
      8. *
      9. {@link LivingIncomingDamageEvent} is fired
      10. *
      11. {@link LivingShieldBlockEvent} fires and the result determines if shield effects apply
      12. diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java index d793cb3ee4..ee250849d5 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java @@ -21,7 +21,7 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; -import net.neoforged.neoforge.event.entity.EntityInvulnerablityCheckEvent; +import net.neoforged.neoforge.event.entity.EntityInvulnerabilityCheckEvent; import net.neoforged.neoforge.event.entity.EntityTeleportEvent; import net.neoforged.neoforge.event.level.ExplosionKnockbackEvent; import net.neoforged.testframework.DynamicTest; @@ -84,7 +84,7 @@ static void entityAttributeModificationEvent(final DynamicTest test, final Regis @EmptyTemplate @TestHolder(description = "Tests if EntityInvulnerabilityCheckEvent prevents damage when modified.") static void entityInvulnerabilityCheckEvent(final DynamicTest test, final RegistrationHelper reg) { - test.eventListeners().forge().addListener((final EntityInvulnerablityCheckEvent event) -> { + test.eventListeners().forge().addListener((final EntityInvulnerabilityCheckEvent event) -> { if (event.getEntity() instanceof GameTestPlayer entity) event.setInvulnerable(false); }); From e2719b346a6e350adef0c55f5419b9d609ef2dc6 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sat, 8 Jun 2024 16:38:14 -0400 Subject: [PATCH 27/41] update damage container as Stack --- .../client/player/RemotePlayer.java.patch | 10 ----- .../world/entity/LivingEntity.java.patch | 40 +++++++++--------- .../world/entity/player/Player.java.patch | 42 +++++-------------- 3 files changed, 30 insertions(+), 62 deletions(-) delete mode 100644 patches/net/minecraft/client/player/RemotePlayer.java.patch diff --git a/patches/net/minecraft/client/player/RemotePlayer.java.patch b/patches/net/minecraft/client/player/RemotePlayer.java.patch deleted file mode 100644 index 919be5f68e..0000000000 --- a/patches/net/minecraft/client/player/RemotePlayer.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/net/minecraft/client/player/RemotePlayer.java -+++ b/net/minecraft/client/player/RemotePlayer.java -@@ -33,6 +_,7 @@ - - @Override - public boolean hurt(DamageSource p_108772_, float p_108773_) { -+ net.neoforged.neoforge.common.CommonHooks.onPlayerIncomingDamage(this, this.damageContainer); - return true; - } - diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index 54fbfceaa5..d6a6cf90e7 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -19,7 +19,7 @@ + * invulnerability checks, and is nulllified before the method's return. + * */ + @Nullable -+ protected net.neoforged.neoforge.common.damagesource.InternalDamageContainer damageContainer; ++ protected java.util.Stack damageContainer = new java.util.Stack<>(); protected LivingEntity(EntityType p_20966_, Level p_20967_) { super(p_20966_, p_20967_); @@ -146,14 +146,14 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { -+ this.damageContainer = this.damageContainer == null ? new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_21016_, p_21017_) : this.damageContainer; -+ if (!net.neoforged.neoforge.common.CommonHooks.onEntityIncomingDamage(this, this.damageContainer)) return false; ++ this.damageContainer.add(new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_21016_, p_21017_)); ++ if (!net.neoforged.neoforge.common.CommonHooks.onEntityIncomingDamage(this, this.damageContainer.getLast())) return false; if (this.isSleeping() && !this.level().isClientSide) { this.stopSleeping(); } this.noActionTime = 0; -+ p_21017_ = this.damageContainer.getNewDamage(); //Neo: enforce damage container as source of truth for damage amount ++ p_21017_ = this.damageContainer.getLast().getNewDamage(); //Neo: enforce damage container as source of truth for damage amount float f = p_21017_; boolean flag = false; float f1 = 0.0F; @@ -162,8 +162,8 @@ - f1 = p_21017_; - p_21017_ = 0.0F; + net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent ev; -+ if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_))).getBlocked()) { -+ this.damageContainer.setBlockedDamage(ev); ++ if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer.getLast(), this.isDamageSourceBlocked(p_21016_))).getBlocked()) { ++ this.damageContainer.getLast().setBlockedDamage(ev); + if(ev.shieldDamage() > 0) { + this.hurtCurrentlyUsedShield(ev.shieldDamage()); + } @@ -182,7 +182,7 @@ boolean flag1 = true; if ((float)this.invulnerableTime > 10.0F && !p_21016_.is(DamageTypeTags.BYPASSES_COOLDOWN)) { if (p_21017_ <= this.lastHurt) { -+ this.damageContainer = null; ++ this.damageContainer.pop(); return false; } @@ -191,7 +191,7 @@ } else { this.lastHurt = p_21017_; - this.invulnerableTime = 20; -+ this.invulnerableTime = this.damageContainer.getPostAttackInvulnerabilityTicks(); ++ this.invulnerableTime = this.damageContainer.getLast().getPostAttackInvulnerabilityTicks(); this.actuallyHurt(p_21016_, p_21017_); this.hurtDuration = 10; this.hurtTime = this.hurtDuration; @@ -220,7 +220,7 @@ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)entity, this, p_21016_, f, p_21017_, flag); } -+ this.damageContainer = null; ++ this.damageContainer.pop(); return flag2; } } @@ -372,7 +372,7 @@ p_21194_ = Math.max(f / 25.0F, 0.0F); float f2 = f1 - p_21194_; if (f2 > 0.0F && f2 < 3.4028235E37F) { -+ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.MOB_EFFECTS, f2); ++ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.MOB_EFFECTS, f2); if (this instanceof ServerPlayer) { - ((ServerPlayer)this).awardStat(Stats.DAMAGE_RESISTED, Math.round(f2 * 10.0F)); + ((ServerPlayer)this).awardStat(Stats.CUSTOM.get(Stats.DAMAGE_RESISTED), Math.round(f2 * 10.0F)); @@ -386,7 +386,7 @@ int k = EnchantmentHelper.getDamageProtection(this.getArmorAndBodyArmorSlots(), p_21193_); if (k > 0) { p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, (float)k); -+ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ENCHANTMENTS,this.damageContainer.getNewDamage() - p_21194_); ++ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ENCHANTMENTS,this.damageContainer.getLast().getNewDamage() - p_21194_); } return p_21194_; @@ -399,14 +399,14 @@ - float f1 = Math.max(p_21241_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_21241_ - f1)); - float f = p_21241_ - f1; -+ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getNewDamage())); -+ this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainer.getNewDamage()); -+ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer); ++ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getLast().getNewDamage() - this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getLast().getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainer.getLast().getNewDamage()); ++ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getLast().getNewDamage() - this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getLast().getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer.getLast()); + if (f1 <= 0) return; -+ float f = this.damageContainer.getNewDamage() - f1; ++ float f = this.damageContainer.getLast().getNewDamage() - f1; if (f > 0.0F && f < 3.4028235E37F && p_21240_.getEntity() instanceof ServerPlayer serverplayer) { serverplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f * 10.0F)); } @@ -414,8 +414,8 @@ this.setHealth(this.getHealth() - f1); this.setAbsorptionAmount(this.getAbsorptionAmount() - f1); this.gameEvent(GameEvent.ENTITY_DAMAGE); -+ this.onDamageTaken(this.damageContainer); -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer); ++ this.onDamageTaken(this.damageContainer.getLast()); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer.getLast()); } } } diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index ab6e420b4e..de6396d145 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -113,39 +113,17 @@ @Override public void readAdditionalSaveData(CompoundTag p_36215_) { super.readAdditionalSaveData(p_36215_); -@@ -856,6 +_,8 @@ - } else if (this.abilities.invulnerable && !p_36154_.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { - return false; - } else { -+ this.damageContainer = new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_36154_, p_36155_); -+ if (!net.neoforged.neoforge.common.CommonHooks.onPlayerIncomingDamage(this, this.damageContainer)) return false; - this.noActionTime = 0; - if (this.isDeadOrDying()) { - return false; @@ -864,7 +_,9 @@ this.removeEntitiesOnShoulder(); } - if (p_36154_.scalesWithDifficulty()) { -+ this.damageContainer.setNewDamage(Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, this.damageContainer.getNewDamage(), this.level().getDifficulty()))); ++ p_36155_ = Math.max(0.0F, p_36154_.type().scaling().getScalingFunction().scaleDamage(p_36154_, this, p_36155_, this.level().getDifficulty())); + + if (false && p_36154_.scalesWithDifficulty()) { if (this.level().getDifficulty() == Difficulty.PEACEFUL) { p_36155_ = 0.0F; } -@@ -878,7 +_,11 @@ - } - } - -- return p_36155_ == 0.0F ? false : super.hurt(p_36154_, p_36155_); -+ if (this.damageContainer.getNewDamage() == 0.0F) { -+ this.damageContainer = null; -+ return false; -+ } -+ else return super.hurt(p_36154_, this.damageContainer.getNewDamage()); - } - } - } @@ -918,7 +_,7 @@ @Override @@ -179,14 +157,14 @@ - float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); - float f = p_36313_ - f1; -+ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getNewDamage())); -+ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getNewDamage()); -+ this.damageContainer.setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getNewDamage() - this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer); ++ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getLast().getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getLast().getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getLast().getNewDamage()); ++ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainer.getLast().getNewDamage() - this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); ++ this.setAbsorptionAmount(this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getLast().getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer.getLast()); + if (f1 <= 0) return; -+ float f = this.damageContainer.getNewDamage() - f1; ++ float f = this.damageContainer.getLast().getNewDamage() - f1; if (f > 0.0F && f < 3.4028235E37F) { this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); } @@ -200,8 +178,8 @@ } - this.gameEvent(GameEvent.ENTITY_DAMAGE); -+ this.onDamageTaken(this.damageContainer); -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer); ++ this.onDamageTaken(this.damageContainer.getLast()); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer.getLast()); } } } From ced60ab12aecf5267c746ddd7ce47cd68bf10a2e Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sun, 9 Jun 2024 06:39:59 -0400 Subject: [PATCH 28/41] update Stack method calls --- .../world/entity/LivingEntity.java.patch | 65 +++++++++++-------- .../world/entity/player/Player.java.patch | 18 ++--- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index d6a6cf90e7..798986ff26 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -9,17 +9,18 @@ private static final Logger LOGGER = LogUtils.getLogger(); private static final String TAG_ACTIVE_EFFECTS = "active_effects"; private static final UUID SPEED_MODIFIER_SOUL_SPEED_UUID = UUID.fromString("87f46a96-686f-4796-b035-22e16ee9e038"); -@@ -242,6 +_,13 @@ +@@ -242,6 +_,14 @@ protected Brain brain; private boolean skipDropExperience; protected float appliedScale = 1.0F; + /** + * This field stores information about damage dealt to this entity. -+ * The field is instantiated via {@link #hurt(DamageSource, float)} after -+ * invulnerability checks, and is nulllified before the method's return. ++ * a new {@link net.neoforged.neoforge.common.damagesource.DamageContainer} is instantiated ++ * via {@link #hurt(DamageSource, float)} after invulnerability checks, and is removed from ++ * the stack before the method's return. + * */ + @Nullable -+ protected java.util.Stack damageContainer = new java.util.Stack<>(); ++ protected java.util.Stack damageContainers = new java.util.Stack<>(); protected LivingEntity(EntityType p_20966_, Level p_20967_) { super(p_20966_, p_20967_); @@ -146,14 +147,14 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { -+ this.damageContainer.add(new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_21016_, p_21017_)); -+ if (!net.neoforged.neoforge.common.CommonHooks.onEntityIncomingDamage(this, this.damageContainer.getLast())) return false; ++ this.damageContainers.push(new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_21016_, p_21017_)); ++ if (!net.neoforged.neoforge.common.CommonHooks.onEntityIncomingDamage(this, this.damageContainers.peek())) return false; if (this.isSleeping() && !this.level().isClientSide) { this.stopSleeping(); } this.noActionTime = 0; -+ p_21017_ = this.damageContainer.getLast().getNewDamage(); //Neo: enforce damage container as source of truth for damage amount ++ p_21017_ = this.damageContainers.peek().getNewDamage(); //Neo: enforce damage container as source of truth for damage amount float f = p_21017_; boolean flag = false; float f1 = 0.0F; @@ -162,8 +163,8 @@ - f1 = p_21017_; - p_21017_ = 0.0F; + net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent ev; -+ if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer.getLast(), this.isDamageSourceBlocked(p_21016_))).getBlocked()) { -+ this.damageContainer.getLast().setBlockedDamage(ev); ++ if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainers.peek(), this.isDamageSourceBlocked(p_21016_))).getBlocked()) { ++ this.damageContainers.peek().setBlockedDamage(ev); + if(ev.shieldDamage() > 0) { + this.hurtCurrentlyUsedShield(ev.shieldDamage()); + } @@ -178,23 +179,34 @@ } if (p_21016_.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { -@@ -1159,6 +_,7 @@ +@@ -1155,10 +_,12 @@ + p_21017_ *= 0.75F; + } + ++ this.damageContainers.peek().setNewDamage(p_21017_); //update container with vanilla changes + this.walkAnimation.setSpeed(1.5F); boolean flag1 = true; if ((float)this.invulnerableTime > 10.0F && !p_21016_.is(DamageTypeTags.BYPASSES_COOLDOWN)) { if (p_21017_ <= this.lastHurt) { -+ this.damageContainer.pop(); ++ this.damageContainers.pop(); return false; } -@@ -1167,7 +_,7 @@ +@@ -1167,12 +_,13 @@ flag1 = false; } else { this.lastHurt = p_21017_; - this.invulnerableTime = 20; -+ this.invulnerableTime = this.damageContainer.getLast().getPostAttackInvulnerabilityTicks(); ++ this.invulnerableTime = this.damageContainers.peek().getPostAttackInvulnerabilityTicks(); this.actuallyHurt(p_21016_, p_21017_); this.hurtDuration = 10; this.hurtTime = this.hurtDuration; + } + ++ p_21017_ = this.damageContainers.peek().getNewDamage(); //update local with container value + Entity entity = p_21016_.getEntity(); + if (entity != null) { + if (entity instanceof LivingEntity livingentity1 @@ -1184,9 +_,9 @@ if (entity instanceof Player player1) { this.lastHurtByPlayerTime = 100; @@ -220,7 +232,7 @@ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)entity, this, p_21016_, f, p_21017_, flag); } -+ this.damageContainer.pop(); ++ this.damageContainers.pop(); return flag2; } } @@ -372,7 +384,7 @@ p_21194_ = Math.max(f / 25.0F, 0.0F); float f2 = f1 - p_21194_; if (f2 > 0.0F && f2 < 3.4028235E37F) { -+ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.MOB_EFFECTS, f2); ++ this.damageContainers.peek().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.MOB_EFFECTS, f2); if (this instanceof ServerPlayer) { - ((ServerPlayer)this).awardStat(Stats.DAMAGE_RESISTED, Math.round(f2 * 10.0F)); + ((ServerPlayer)this).awardStat(Stats.CUSTOM.get(Stats.DAMAGE_RESISTED), Math.round(f2 * 10.0F)); @@ -386,7 +398,7 @@ int k = EnchantmentHelper.getDamageProtection(this.getArmorAndBodyArmorSlots(), p_21193_); if (k > 0) { p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, (float)k); -+ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ENCHANTMENTS,this.damageContainer.getLast().getNewDamage() - p_21194_); ++ this.damageContainers.peek().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ENCHANTMENTS,this.damageContainers.peek().getNewDamage() - p_21194_); } return p_21194_; @@ -399,26 +411,27 @@ - float f1 = Math.max(p_21241_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_21241_ - f1)); - float f = p_21241_ - f1; -+ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getLast().getNewDamage() - this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainer.getLast().getNewDamage())); -+ this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainer.getLast().getNewDamage()); -+ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getLast().getNewDamage() - this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getLast().getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer.getLast()); ++ this.damageContainers.peek().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainers.peek().getNewDamage() - this.getDamageAfterArmorAbsorb(p_21240_, this.damageContainers.peek().getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainers.peek().getNewDamage()); ++ this.damageContainers.peek().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainers.peek().getNewDamage() - this.damageContainers.peek().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); ++ this.setAbsorptionAmount(this.damageContainers.peek().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainers.peek().getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainers.peek()); + if (f1 <= 0) return; -+ float f = this.damageContainer.getLast().getNewDamage() - f1; ++ float f = this.damageContainers.peek().getNewDamage() - f1; if (f > 0.0F && f < 3.4028235E37F && p_21240_.getEntity() instanceof ServerPlayer serverplayer) { serverplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f * 10.0F)); } -@@ -1713,6 +_,8 @@ +@@ -1713,7 +_,9 @@ this.setHealth(this.getHealth() - f1); this.setAbsorptionAmount(this.getAbsorptionAmount() - f1); this.gameEvent(GameEvent.ENTITY_DAMAGE); -+ this.onDamageTaken(this.damageContainer.getLast()); -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer.getLast()); ++ this.onDamageTaken(this.damageContainers.peek()); } ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainers.peek()); } } + @@ -1767,6 +_,8 @@ } diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index de6396d145..8d80330f2c 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -157,14 +157,14 @@ - float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); - this.setAbsorptionAmount(this.getAbsorptionAmount() - (p_36313_ - f1)); - float f = p_36313_ - f1; -+ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainer.getLast().getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainer.getLast().getNewDamage())); -+ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainer.getLast().getNewDamage()); -+ this.damageContainer.getLast().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); -+ float f1 = Math.max(this.damageContainer.getLast().getNewDamage() - this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); -+ this.setAbsorptionAmount(this.damageContainer.getLast().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainer.getLast().getNewDamage() - f1)); -+ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainer.getLast()); ++ this.damageContainers.peek().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ARMOR, this.damageContainers.peek().getNewDamage() - this.getDamageAfterArmorAbsorb(p_36312_, this.damageContainers.peek().getNewDamage())); ++ this.getDamageAfterMagicAbsorb(p_36312_, this.damageContainers.peek().getNewDamage()); ++ this.damageContainers.peek().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION, this.getAbsorptionAmount()); ++ float f1 = Math.max(this.damageContainers.peek().getNewDamage() - this.damageContainers.peek().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION), 0.0F); ++ this.setAbsorptionAmount(this.damageContainers.peek().getReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ABSORPTION) - (this.damageContainers.peek().getNewDamage() - f1)); ++ f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainers.peek()); + if (f1 <= 0) return; -+ float f = this.damageContainer.getLast().getNewDamage() - f1; ++ float f = this.damageContainers.peek().getNewDamage() - f1; if (f > 0.0F && f < 3.4028235E37F) { this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); } @@ -178,8 +178,8 @@ } - this.gameEvent(GameEvent.ENTITY_DAMAGE); -+ this.onDamageTaken(this.damageContainer.getLast()); -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainer.getLast()); ++ this.onDamageTaken(this.damageContainers.peek()); ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainers.peek()); } } } From 0b468a2d9d1ba9999895bdb3d639640a73bcc471 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sun, 9 Jun 2024 06:40:18 -0400 Subject: [PATCH 29/41] update javadocs and add helper methods --- .../neoforge/common/CommonHooks.java | 6 +-- .../entity/living/LivingDamageEvent.java | 20 +++++----- .../living/LivingIncomingDamageEvent.java | 37 +++++++++++++++++++ 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 8956d7a750..bb07b7dda5 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -295,7 +295,7 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS /** * Creates and posts an {@link LivingDamageEvent.Pre}. This is invoked in * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} - * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. + * and requires access to the internal field {@link LivingEntity#damageContainers} as a parameter. * * @param entity the entity to receive damage * @param container the container object holding the final values of the damage pipeline while they are @@ -310,7 +310,7 @@ public static float onLivingDamagePre(LivingEntity entity, DamageContainer conta /** * Creates and posts a {@link LivingDamageEvent.Post}. This is invoked in * {@link LivingEntity#actuallyHurt(DamageSource, float)} and {@link Player#actuallyHurt(DamageSource, float)} - * and requires access to the internal field {@link LivingEntity#damageContainer} as a parameter. + * and requires access to the internal field {@link LivingEntity#damageContainers} as a parameter. * * @param entity the entity to receive damage * @param container the container object holding the truly final values of the damage pipeline. This @@ -1103,7 +1103,7 @@ public static void onEntityEnterSection(Entity entity, long packedOldPos, long p /** * Creates, posts, and returns a {@link LivingShieldBlockEvent}. This method is invoked in * {@link LivingEntity#hurt(DamageSource, float)} and requires internal access to the - * protected field {@link LivingEntity#damageContainer} as a parameter. + * protected field {@link LivingEntity#damageContainers} as a parameter. * * @param blocker the entity performing the block * @param container the entity's internal damage container for accessing current values diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java index 27605cce7c..72505dc9b2 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java @@ -10,7 +10,7 @@ import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * LivingDamage event captures when an entity is about to receive a loss + * LivingDamageEvent captures when an entity is about to receive a loss * of health. At this stage in the damage sequence, all reduction effects * have been applied. *
        @@ -19,7 +19,7 @@ *
        * {@link Post} contains an immutable representation of the entire damage sequence * and allows for reference to the values accrued at each step. - * + *
        * For more information on the damage sequence * * @see DamageSequenceEvent @@ -30,9 +30,10 @@ private LivingDamageEvent(LivingEntity entity, DamageContainer container) { } /** - * IncomingDamageEvent is fired when an Entity is set to be hurt.
        - * This event is fired in {@code LivingEntity#hurt(DamageSource, float} and - * {@code Player#actuallyHurt(DamageSource, float)}. + * LivingDamageEvent.Pre is fired when an Entity is set to be hurt.
        + * At this point armor, potion and absorption modifiers have already been applied to the damage value + * and the entity.
        + * This event is fired in {@code LivingEntity#actuallyHurt(DamageSource, float} *
        * For custom posting of this event, the event expects to be fired after * damage reductions have been calculated but before any changes to the entity @@ -51,14 +52,11 @@ public Pre(LivingEntity entity, DamageContainer source) { } /** - * DamageTakenEvent is fired just before health is modified on the entity.
        - * At this point armor, potion and absorption modifiers have already been applied to damage. - * the {@link DamageContainer} is immutable and represents a FINAL value of what is about to - * be applied. + * LivingDamageEvent.Post is fired after health is modified on the entity.
        + * the {@link DamageContainer} is immutable and represents a FINAL value of what was applied to the entity. *
        * Also note that appropriate resources (like armor durability and absorption extra hearts) have already been consumed.
        - * This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)} and - * {@code Player#actuallyHurt(DamageSource, float)}.
        + * This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)} *
        * This event is fired via {@link CommonHooks#onLivingDamagePost(LivingEntity, DamageContainer)}.
        *
        diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java index df88ecfca2..c7e8135212 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java @@ -5,6 +5,7 @@ package net.neoforged.neoforge.event.entity.living; +import java.util.function.BiFunction; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import net.neoforged.bus.api.ICancellableEvent; @@ -38,4 +39,40 @@ public DamageSource getSource() { public float getAmount() { return this.container.getNewDamage(); } + + public float getOriginalAmount() { + return this.container.getOriginalDamage(); + } + + /** + * @param newDamage the damage value to be used in the rest of the damage sequence. + */ + public void setAmount(float newDamage) { + this.container.setNewDamage(newDamage); + } + + /** + * Reduction modifiers alter the vanilla damage reduction before it modifies the damage value. + * Modifiers are executed in sequence. + * + * @param type the reduction type to be modified + * @param reductionFunc the function to apply to the reduction value. + */ + public void addReductionModifier(DamageContainer.Reduction type, BiFunction reductionFunc) { + this.container.addModifier(type, reductionFunc); + } + + /** + * When an entity's invulnerable time is fully cooled down, 20 ticks of invulnerability is added + * on the next attack. This method allows for setting a new invulnerability tick count when those + * conditions are met. + *
        + * Note: this value will be ignored if the damage is taken while invulnerability ticks are greater + * than 10 and the damage source does not bypass invulnerability + * + * @param ticks the number of ticks for the entity to remain invulnerable to incoming damage + */ + public void setInvulnerabilityTicks(int ticks) { + this.container.setPostAttackInvulnerabilityTicks(ticks); + } } From 124a8305da322ba1f8d86a090595fac4691ee2da Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:15:54 -0400 Subject: [PATCH 30/41] update javadoc --- .../neoforge/event/entity/living/LivingDamageEvent.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java index 72505dc9b2..e8bfa09271 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java @@ -10,9 +10,8 @@ import net.neoforged.neoforge.common.damagesource.DamageContainer; /** - * LivingDamageEvent captures when an entity is about to receive a loss - * of health. At this stage in the damage sequence, all reduction effects - * have been applied. + * LivingDamageEvent captures an entity's loss of health. At this stage in + * the damage sequence, all reduction effects have been applied. *
        * {@link Pre} allows for modification of the damage value before it is applied * to the entity's health. From fa95f62788b54fe28cc548a2a4a4ff32499c4e96 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:56:11 -0400 Subject: [PATCH 31/41] rebase patches --- .../minecraft/world/entity/Entity.java.patch | 175 ++++-------- .../world/entity/LivingEntity.java.patch | 266 +++++++++--------- .../world/entity/player/Player.java.patch | 266 ++++++++---------- 3 files changed, 317 insertions(+), 390 deletions(-) diff --git a/patches/net/minecraft/world/entity/Entity.java.patch b/patches/net/minecraft/world/entity/Entity.java.patch index 8010d7aba8..6621363756 100644 --- a/patches/net/minecraft/world/entity/Entity.java.patch +++ b/patches/net/minecraft/world/entity/Entity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -126,7 +_,7 @@ +@@ -128,7 +_,7 @@ import net.minecraft.world.scores.Team; import org.slf4j.Logger; @@ -9,7 +9,7 @@ private static final Logger LOGGER = LogUtils.getLogger(); public static final String ID_TAG = "id"; public static final String PASSENGERS_TAG = "Passengers"; -@@ -147,6 +_,7 @@ +@@ -149,6 +_,7 @@ private static final double LAVA_SLOW_FLOW_SCALE = 0.0023333333333333335; public static final String UUID_TAG = "UUID"; private static double viewScale = 1.0; @@ -17,7 +17,7 @@ private final EntityType type; private int id = ENTITY_COUNTER.incrementAndGet(); public boolean blocksBuilding; -@@ -192,8 +_,10 @@ +@@ -194,8 +_,10 @@ public int tickCount; private int remainingFireTicks = -this.getFireImmuneTicks(); protected boolean wasTouchingWater; @@ -28,19 +28,19 @@ private final Set> fluidOnEyes = new HashSet<>(); public int invulnerableTime; protected boolean firstTick = true; -@@ -262,7 +_,10 @@ +@@ -263,7 +_,10 @@ this.defineSynchedData(synchedentitydata$builder); this.entityData = synchedentitydata$builder.build(); this.setPos(0.0, 0.0, 0.0); - this.eyeHeight = this.dimensions.eyeHeight(); -+ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, Pose.STANDING, this.dimensions, this.getEyeHeight(Pose.STANDING)); ++ net.neoforged.neoforge.event.entity.EntityEvent.Size sizeEvent = net.neoforged.neoforge.event.EventHooks.getEntitySizeForge(this, Pose.STANDING, this.dimensions, this.dimensions.eyeHeight()); + this.dimensions = sizeEvent.getNewSize(); + this.eyeHeight = sizeEvent.getNewEyeHeight(); + net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.EntityEvent.EntityConstructing(this)); } public boolean isColliding(BlockPos p_20040_, BlockState p_20041_) { -@@ -466,7 +_,7 @@ +@@ -467,7 +_,7 @@ if (this.isInLava()) { this.lavaHurt(); @@ -49,7 +49,7 @@ } this.checkBelowWorld(); -@@ -672,7 +_,7 @@ +@@ -673,7 +_,7 @@ double d1 = vec3.x; double d2 = vec3.y; double d3 = vec3.z; @@ -58,7 +58,7 @@ BlockPos blockpos1 = this.getOnPos(); BlockState blockstate1 = this.level().getBlockState(blockpos1); boolean flag1 = this.isStateClimbable(blockstate1); -@@ -716,16 +_,16 @@ +@@ -717,16 +_,16 @@ this.setRemainingFireTicks(-this.getFireImmuneTicks()); } @@ -78,7 +78,7 @@ } } } -@@ -811,9 +_,7 @@ +@@ -812,9 +_,7 @@ return blockpos; } else { BlockState blockstate = this.level().getBlockState(blockpos); @@ -89,7 +89,7 @@ ? blockpos.atY(Mth.floor(this.position.y - (double)p_216987_)) : blockpos; } -@@ -1039,19 +_,19 @@ +@@ -1076,19 +_,19 @@ return !blockstate.is(BlockTags.INSIDE_STEP_SOUND_BLOCKS) && !blockstate.is(BlockTags.COMBINATION_STEP_SOUND_BLOCKS) ? p_278049_ : blockpos; } @@ -115,7 +115,7 @@ this.playSound(soundtype.getStepSound(), soundtype.getVolume() * 0.15F, soundtype.getPitch()); } -@@ -1204,20 +_,23 @@ +@@ -1241,20 +_,23 @@ public void updateSwimming() { if (this.isSwimming()) { @@ -144,7 +144,7 @@ } void updateInWaterStateAndDoWaterCurrentPushing() { -@@ -1242,6 +_,7 @@ +@@ -1279,6 +_,7 @@ private void updateFluidOnEyes() { this.wasEyeInWater = this.isEyeInFluid(FluidTags.WATER); this.fluidOnEyes.clear(); @@ -152,7 +152,7 @@ double d0 = this.getEyeY(); if (this.getVehicle() instanceof Boat boat && !boat.isUnderWater() && boat.getBoundingBox().maxY >= d0 && boat.getBoundingBox().minY <= d0) { return; -@@ -1251,7 +_,7 @@ +@@ -1288,7 +_,7 @@ FluidState fluidstate = this.level().getFluidState(blockpos); double d1 = (double)((float)blockpos.getY() + fluidstate.getHeight(this.level(), blockpos)); if (d1 > d0) { @@ -161,7 +161,7 @@ } } -@@ -1296,12 +_,13 @@ +@@ -1333,12 +_,13 @@ } public boolean canSpawnSprintParticle() { @@ -176,7 +176,7 @@ if (blockstate.getRenderShape() != RenderShape.INVISIBLE) { Vec3 vec3 = this.getDeltaMovement(); BlockPos blockpos1 = this.blockPosition(); -@@ -1315,16 +_,19 @@ +@@ -1352,16 +_,19 @@ d1 = Mth.clamp(d1, (double)blockpos.getZ(), (double)blockpos.getZ() + 1.0); } @@ -198,16 +198,7 @@ } public void moveRelative(float p_19921_, Vec3 p_19922_) { -@@ -1645,6 +_,8 @@ - p_20241_.putBoolean("HasVisualFire", this.hasVisualFire); - } - -+ p_20241_.putBoolean("CanUpdate", canUpdate); -+ - if (!this.tags.isEmpty()) { - ListTag listtag = new ListTag(); - -@@ -1655,6 +_,10 @@ +@@ -1704,6 +_,10 @@ p_20241_.put("Tags", listtag); } @@ -218,17 +209,16 @@ this.addAdditionalSaveData(p_20241_); if (this.isVehicle()) { ListTag listtag1 = new ListTag(); -@@ -1735,6 +_,9 @@ +@@ -1784,6 +_,8 @@ this.setGlowingTag(p_20259_.getBoolean("Glowing")); this.setTicksFrozen(p_20259_.getInt("TicksFrozen")); this.hasVisualFire = p_20259_.getBoolean("HasVisualFire"); + if (p_20259_.contains("NeoForgeData", 10)) persistentData = p_20259_.getCompound("NeoForgeData"); -+ if (p_20259_.contains("CanUpdate", 99)) this.canUpdate(p_20259_.getBoolean("CanUpdate")); + if (p_20259_.contains(ATTACHMENTS_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) deserializeAttachments(registryAccess(), p_20259_.getCompound(ATTACHMENTS_NBT_KEY)); if (p_20259_.contains("Tags", 9)) { this.tags.clear(); ListTag listtag3 = p_20259_.getList("Tags", 8); -@@ -1819,6 +_,8 @@ +@@ -1868,6 +_,8 @@ } else { ItemEntity itementity = new ItemEntity(this.level(), this.getX(), this.getY() + (double)p_19986_, this.getZ(), p_19985_); itementity.setDefaultPickUpDelay(); @@ -237,15 +227,20 @@ this.level().addFreshEntity(itementity); return itementity; } -@@ -1865,6 +_,7 @@ +@@ -1935,7 +_,11 @@ public void rideTick() { this.setDeltaMovement(Vec3.ZERO); -+ if (canUpdate()) - this.tick(); +- this.tick(); ++ // Neo: Permit cancellation of Entity#tick via EntityTickEvent.Pre ++ if (!net.neoforged.neoforge.event.EventHooks.fireEntityTickPre(this).isCanceled()) { ++ this.tick(); ++ net.neoforged.neoforge.event.EventHooks.fireEntityTickPost(this); ++ } if (this.isPassenger()) { this.getVehicle().positionRider(this); -@@ -1923,6 +_,7 @@ + } +@@ -1993,6 +_,7 @@ } } @@ -253,7 +248,7 @@ if (p_19967_ || this.canRide(p_19966_) && p_19966_.canAddPassenger(this)) { if (this.isPassenger()) { this.stopRiding(); -@@ -1954,6 +_,7 @@ +@@ -2024,6 +_,7 @@ public void removeVehicle() { if (this.vehicle != null) { Entity entity = this.vehicle; @@ -261,7 +256,7 @@ this.vehicle = null; entity.removePassenger(this); } -@@ -2003,6 +_,8 @@ +@@ -2073,6 +_,8 @@ return this.passengers.isEmpty(); } @@ -270,7 +265,7 @@ protected boolean couldAcceptPassenger() { return true; } -@@ -2192,7 +_,7 @@ +@@ -2257,7 +_,7 @@ } public boolean isVisuallyCrawling() { @@ -279,8 +274,8 @@ } public void setSwimming(boolean p_20283_) { -@@ -2301,7 +_,7 @@ - this.igniteForSeconds(8); +@@ -2366,7 +_,7 @@ + this.igniteForSeconds(8.0F); } - this.hurt(this.damageSources().lightningBolt(), 5.0F); @@ -288,7 +283,7 @@ } public void onAboveBubbleCol(boolean p_20313_) { -@@ -2396,7 +_,7 @@ +@@ -2461,7 +_,7 @@ } protected Component getTypeName() { @@ -297,64 +292,31 @@ } public boolean is(Entity p_20356_) { -@@ -2451,10 +_,11 @@ +@@ -2516,10 +_,11 @@ } public boolean isInvulnerableTo(DamageSource p_20122_) { - return this.isRemoved() +- || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() +- || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() +- || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); + boolean isVanillaInvulnerable = this.isRemoved() - || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() - || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() - || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); ++ || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() ++ || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() ++ || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); + return net.neoforged.neoforge.common.CommonHooks.onEntityInvulnerablityCheck(this, p_20122_, isVanillaInvulnerable); } public boolean isInvulnerable() { -@@ -2479,14 +_,20 @@ +@@ -2544,6 +_,7 @@ @Nullable - public Entity changeDimension(ServerLevel p_20118_) { -+ return this.changeDimension(p_20118_, p_20118_.getPortalForcer()); -+ } -+ @Nullable -+ public Entity changeDimension(ServerLevel p_20118_, net.neoforged.neoforge.common.util.ITeleporter teleporter) { -+ if (!net.neoforged.neoforge.common.CommonHooks.onTravelToDimension(this, p_20118_.dimension())) return null; - if (this.level() instanceof ServerLevel && !this.isRemoved()) { - this.level().getProfiler().push("changeDimension"); - this.unRide(); - this.level().getProfiler().push("reposition"); -- PortalInfo portalinfo = this.findDimensionEntryPoint(p_20118_); -+ PortalInfo portalinfo = teleporter.getPortalInfo(this, p_20118_, this::findDimensionEntryPoint); - if (portalinfo == null) { - return null; - } else { -+ Entity transportedEntity = teleporter.placeEntity(this, (ServerLevel) this.level, p_20118_, this.yRot, spawnPortal -> { //Forge: Start vanilla logic - this.level().getProfiler().popPush("reloading"); - Entity entity = this.getType().create(p_20118_); - if (entity != null) { -@@ -2494,17 +_,19 @@ - entity.moveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z, portalinfo.yRot, entity.getXRot()); - entity.setDeltaMovement(portalinfo.speed); - p_20118_.addDuringTeleport(entity); -- if (p_20118_.dimension() == Level.END) { -+ if (spawnPortal && p_20118_.dimension() == Level.END) { - ServerLevel.makeObsidianPlatform(p_20118_); - } - } -+ return entity; -+ }); //Forge: End vanilla logic - - this.removeAfterChangingDimensions(); - this.level().getProfiler().pop(); - ((ServerLevel)this.level()).resetEmptyTime(); - p_20118_.resetEmptyTime(); - this.level().getProfiler().pop(); -- return entity; -+ return transportedEntity; - } - } else { - return null; -@@ -2639,6 +_,7 @@ + public Entity changeDimension(DimensionTransition p_350951_) { ++ if (!net.neoforged.neoforge.common.CommonHooks.onTravelToDimension(this, p_350951_.newLevel().dimension())) return null; + if (this.level() instanceof ServerLevel serverlevel && !this.isRemoved()) { + ServerLevel serverlevel1 = p_350951_.newLevel(); + List list = this.getPassengers(); +@@ -2667,6 +_,7 @@ return this.stringUUID; } @@ -362,7 +324,7 @@ public boolean isPushedByFluid() { return true; } -@@ -2764,6 +_,8 @@ +@@ -2783,6 +_,8 @@ EntityDimensions entitydimensions = this.dimensions; Pose pose = this.getPose(); EntityDimensions entitydimensions1 = this.getDimensions(pose); @@ -371,22 +333,8 @@ this.dimensions = entitydimensions1; this.eyeHeight = entitydimensions1.eyeHeight(); this.reapplyPosition(); -@@ -2778,11 +_,12 @@ - double d0 = (double)Math.max(0.0F, entitydimensions1.width() - entitydimensions.width()) + 1.0E-6; - double d1 = (double)Math.max(0.0F, entitydimensions1.height() - entitydimensions.height()) + 1.0E-6; - VoxelShape voxelshape = Shapes.create(AABB.ofSize(vec3, d0, d1, d0)); -+ EntityDimensions finalEntitydimensions = entitydimensions1; - this.level() - .findFreePosition( - this, voxelshape, vec3, (double)entitydimensions1.width(), (double)entitydimensions1.height(), (double)entitydimensions1.width() - ) -- .ifPresent(p_315932_ -> this.setPos(p_315932_.add(0.0, (double)(-entitydimensions1.height()) / 2.0, 0.0))); -+ .ifPresent(p_315932_ -> this.setPos(p_315932_.add(0.0, (double)(-finalEntitydimensions.height()) / 2.0, 0.0))); - } - } - -@@ -3084,9 +_,17 @@ - this.yRotO = this.getYRot(); +@@ -3110,9 +_,17 @@ + return Mth.lerp(p_352259_, this.yRotO, this.yRot); } + @Deprecated // Forge: Use no parameter version instead, only for vanilla Tags @@ -404,7 +352,7 @@ } else { AABB aabb = this.getBoundingBox().deflate(0.001); int i = Mth.floor(aabb.minX); -@@ -3101,25 +_,36 @@ +@@ -3127,25 +_,36 @@ Vec3 vec3 = Vec3.ZERO; int k1 = 0; BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(); @@ -448,7 +396,7 @@ } } } -@@ -3127,27 +_,30 @@ +@@ -3153,27 +_,30 @@ } } @@ -468,7 +416,7 @@ } Vec3 vec32 = this.getDeltaMovement(); -- vec3 = vec3.scale(p_204033_ * 1.0); +- vec3 = vec3.scale(p_204033_); + interim.flowVector = interim.flowVector.scale(this.getFluidMotionScale(fluidType)); double d2 = 0.003; - if (Math.abs(vec32.x) < 0.003 && Math.abs(vec32.z) < 0.003 && vec3.length() < 0.0045000000000000005) { @@ -489,7 +437,7 @@ } } -@@ -3160,7 +_,10 @@ +@@ -3186,7 +_,10 @@ return !this.level().hasChunksAt(i, k, j, l); } @@ -500,7 +448,7 @@ return this.fluidHeight.getDouble(p_204037_); } -@@ -3297,6 +_,7 @@ +@@ -3323,6 +_,7 @@ this.levelCallback.onMove(); } @@ -508,22 +456,13 @@ } public void checkDespawn() { -@@ -3424,6 +_,126 @@ +@@ -3450,6 +_,117 @@ public boolean mayInteract(Level p_146843_, BlockPos p_146844_) { return true; } + + /* ================================== Forge Start =====================================*/ + -+ private boolean canUpdate = true; -+ @Override -+ public void canUpdate(boolean value) { -+ this.canUpdate = value; -+ } -+ @Override -+ public boolean canUpdate() { -+ return this.canUpdate; -+ } + @Nullable + private java.util.Collection captureDrops = null; + @Override @@ -547,7 +486,7 @@ + public boolean canTrample(BlockState state, BlockPos pos, float fallDistance) { + return level.random.nextFloat() < fallDistance - 0.5F + && this instanceof LivingEntity -+ && (this instanceof Player || net.neoforged.neoforge.event.EventHooks.getMobGriefingEvent(level, this)) ++ && (this instanceof Player || net.neoforged.neoforge.event.EventHooks.canEntityGrief(level, this)) + && this.getBbWidth() * this.getBbWidth() * this.getBbHeight() > 0.512F; + } + diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index 798986ff26..0214284cb0 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java -@@ -126,7 +_,7 @@ +@@ -132,7 +_,7 @@ import net.minecraft.world.scores.Scoreboard; import org.slf4j.Logger; @@ -8,44 +8,44 @@ +public abstract class LivingEntity extends Entity implements Attackable, net.neoforged.neoforge.common.extensions.ILivingEntityExtension { private static final Logger LOGGER = LogUtils.getLogger(); private static final String TAG_ACTIVE_EFFECTS = "active_effects"; - private static final UUID SPEED_MODIFIER_SOUL_SPEED_UUID = UUID.fromString("87f46a96-686f-4796-b035-22e16ee9e038"); -@@ -242,6 +_,14 @@ - protected Brain brain; + private static final ResourceLocation SPEED_MODIFIER_POWDER_SNOW_ID = ResourceLocation.withDefaultNamespace("powder_snow"); +@@ -254,6 +_,14 @@ private boolean skipDropExperience; + private final Reference2ObjectMap> activeLocationDependentEnchantments = new Reference2ObjectArrayMap<>(); protected float appliedScale = 1.0F; + /** + * This field stores information about damage dealt to this entity. + * a new {@link net.neoforged.neoforge.common.damagesource.DamageContainer} is instantiated + * via {@link #hurt(DamageSource, float)} after invulnerability checks, and is removed from + * the stack before the method's return. -+ * */ ++ **/ + @Nullable + protected java.util.Stack damageContainers = new java.util.Stack<>(); protected LivingEntity(EntityType p_20966_, Level p_20967_) { super(p_20966_, p_20967_); -@@ -302,7 +_,9 @@ - .add(Attributes.GRAVITY) - .add(Attributes.SAFE_FALL_DISTANCE) - .add(Attributes.FALL_DAMAGE_MULTIPLIER) -- .add(Attributes.JUMP_STRENGTH); -+ .add(Attributes.JUMP_STRENGTH) +@@ -320,7 +_,9 @@ + .add(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE) + .add(Attributes.WATER_MOVEMENT_EFFICIENCY) + .add(Attributes.MOVEMENT_EFFICIENCY) +- .add(Attributes.ATTACK_KNOCKBACK); ++ .add(Attributes.ATTACK_KNOCKBACK) + .add(net.neoforged.neoforge.common.NeoForgeMod.SWIM_SPEED) + .add(net.neoforged.neoforge.common.NeoForgeMod.NAMETAG_DISTANCE); } @Override -@@ -331,7 +_,8 @@ - float f = (float)Mth.ceil((double)this.fallDistance - d0); - double d5 = Math.min((double)(0.2F + f / 15.0F), 2.5); - int i = (int)(150.0 * d5); -- ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_), d1, d2, d3, i, 0.0, 0.0, 0.0, 0.15F); +@@ -348,7 +_,8 @@ + float f = (float)Mth.ceil((double)this.fallDistance - d7); + double d4 = Math.min((double)(0.2F + f / 15.0F), 2.5); + int i = (int)(150.0 * d4); +- ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_), d0, d1, d2, i, 0.0, 0.0, 0.0, 0.15F); + if (!p_20992_.addLandingEffects((ServerLevel) this.level(), p_20993_, p_20992_, this, i)) -+ ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_).setPos(p_20993_), d1, d2, d3, i, 0.0D, 0.0D, 0.0D, 0.15F); ++ ((ServerLevel)this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, p_20992_).setPos(p_20993_), d0, d1, d2, i, 0.0, 0.0, 0.0, 0.15F); } } -@@ -341,6 +_,7 @@ +@@ -358,6 +_,7 @@ } } @@ -53,7 +53,7 @@ public final boolean canBreatheUnderwater() { return this.getType().is(EntityTypeTags.CAN_BREATHE_UNDER_WATER); } -@@ -382,6 +_,9 @@ +@@ -403,6 +_,9 @@ } } @@ -63,7 +63,7 @@ if (this.isEyeInFluid(FluidTags.WATER) && !this.level().getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) { boolean flag1 = !this.canBreatheUnderwater() -@@ -420,7 +_,7 @@ +@@ -441,7 +_,7 @@ } } @@ -72,7 +72,7 @@ this.extinguishFire(); } -@@ -813,7 +_,7 @@ +@@ -772,7 +_,7 @@ Holder holder = iterator.next(); MobEffectInstance mobeffectinstance = this.activeEffects.get(holder); if (!mobeffectinstance.tick(this, () -> this.onEffectUpdated(mobeffectinstance, true, null))) { @@ -81,15 +81,19 @@ iterator.remove(); this.onEffectRemoved(mobeffectinstance); } -@@ -861,6 +_,7 @@ - .filter(MobEffectInstance::isVisible) - .map(MobEffectInstance::getParticleOptions) +@@ -817,8 +_,9 @@ + List list = this.activeEffects + .values() + .stream() +- .filter(MobEffectInstance::isVisible) +- .map(MobEffectInstance::getParticleOptions) ++ .map(effect -> net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.entity.living.EffectParticleModificationEvent(this, effect))) ++ .filter(net.neoforged.neoforge.event.entity.living.EffectParticleModificationEvent::isVisible) ++ .map(net.neoforged.neoforge.event.entity.living.EffectParticleModificationEvent::getParticleOptions) .toList(); -+ // Porting 1.20.5 re-add or remove PotionColorCalculationEvent this.entityData.set(DATA_EFFECT_PARTICLES, list); this.entityData.set(DATA_EFFECT_AMBIENCE_ID, areAllEffectsAmbient(this.activeEffects.values())); - } -@@ -899,6 +_,7 @@ +@@ -858,6 +_,7 @@ } } @@ -97,7 +101,7 @@ return d0; } -@@ -940,7 +_,9 @@ +@@ -899,7 +_,9 @@ boolean flag; for (flag = false; iterator.hasNext(); flag = true) { @@ -108,7 +112,13 @@ iterator.remove(); } -@@ -975,6 +_,7 @@ +@@ -929,11 +_,12 @@ + } + + public boolean addEffect(MobEffectInstance p_147208_, @Nullable Entity p_147209_) { +- if (!this.canBeAffected(p_147208_)) { ++ if (!net.neoforged.neoforge.common.CommonHooks.canMobEffectBeApplied(this, p_147208_)) { + return false; } else { MobEffectInstance mobeffectinstance = this.activeEffects.get(p_147208_.getEffect()); boolean flag = false; @@ -116,17 +126,31 @@ if (mobeffectinstance == null) { this.activeEffects.put(p_147208_.getEffect(), p_147208_); this.onEffectAdded(p_147208_, p_147209_); -@@ -991,6 +_,9 @@ +@@ -949,6 +_,14 @@ + } } ++ /** ++ * Neo: Override-Only. Call via {@link net.neoforged.neoforge.common.CommonHooks#canMobEffectBeApplied(LivingEntity, MobEffectInstance)} ++ * ++ * @param p_21197_ A mob effect instance ++ * @return If the mob effect instance can be applied to this entity ++ */ ++ @Deprecated ++ @org.jetbrains.annotations.ApiStatus.OverrideOnly public boolean canBeAffected(MobEffectInstance p_21197_) { -+ net.neoforged.neoforge.event.entity.living.MobEffectEvent.Applicable event = new net.neoforged.neoforge.event.entity.living.MobEffectEvent.Applicable(this, p_21197_); -+ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(event); -+ if (event.getResult() != net.neoforged.bus.api.Event.Result.DEFAULT) return event.getResult() == net.neoforged.bus.api.Event.Result.ALLOW; if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) { return !p_21197_.is(MobEffects.INFESTED); - } else if (this.getType().is(EntityTypeTags.IMMUNE_TO_OOZING)) { -@@ -1024,6 +_,7 @@ +@@ -962,7 +_,7 @@ + } + + public void forceAddEffect(MobEffectInstance p_147216_, @Nullable Entity p_147217_) { +- if (this.canBeAffected(p_147216_)) { ++ if (net.neoforged.neoforge.common.CommonHooks.canMobEffectBeApplied(this, p_147216_)) { + MobEffectInstance mobeffectinstance = this.activeEffects.put(p_147216_.getEffect(), p_147216_); + if (mobeffectinstance == null) { + this.onEffectAdded(p_147216_, p_147217_); +@@ -983,6 +_,7 @@ } public boolean removeEffect(Holder p_316570_) { @@ -134,7 +158,7 @@ MobEffectInstance mobeffectinstance = this.removeEffectNoUpdate(p_316570_); if (mobeffectinstance != null) { this.onEffectRemoved(mobeffectinstance); -@@ -1098,6 +_,8 @@ +@@ -1061,6 +_,8 @@ } public void heal(float p_21116_) { @@ -143,7 +167,7 @@ float f = this.getHealth(); if (f > 0.0F) { this.setHealth(f + p_21116_); -@@ -1127,23 +_,30 @@ +@@ -1090,23 +_,30 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { @@ -179,7 +203,7 @@ } if (p_21016_.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { -@@ -1155,10 +_,12 @@ +@@ -1118,10 +_,12 @@ p_21017_ *= 0.75F; } @@ -192,7 +216,7 @@ return false; } -@@ -1167,12 +_,13 @@ +@@ -1130,12 +_,13 @@ flag1 = false; } else { this.lastHurt = p_21017_; @@ -207,7 +231,7 @@ Entity entity = p_21016_.getEntity(); if (entity != null) { if (entity instanceof LivingEntity livingentity1 -@@ -1184,9 +_,9 @@ +@@ -1147,9 +_,9 @@ if (entity instanceof Player player1) { this.lastHurtByPlayerTime = 100; this.lastHurtByPlayer = player1; @@ -219,7 +243,7 @@ this.lastHurtByPlayer = player; } else { this.lastHurtByPlayer = null; -@@ -1245,7 +_,7 @@ +@@ -1212,7 +_,7 @@ if (this instanceof ServerPlayer) { CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer)this, p_21016_, f, p_21017_, flag); if (f1 > 0.0F && f1 < 3.4028235E37F) { @@ -228,7 +252,7 @@ } } -@@ -1253,6 +_,7 @@ +@@ -1220,6 +_,7 @@ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)entity, this, p_21016_, f, p_21017_, flag); } @@ -236,7 +260,7 @@ return flag2; } } -@@ -1273,7 +_,7 @@ +@@ -1240,7 +_,7 @@ for (InteractionHand interactionhand : InteractionHand.values()) { ItemStack itemstack1 = this.getItemInHand(interactionhand); @@ -245,7 +269,7 @@ itemstack = itemstack1.copy(); itemstack1.shrink(1); break; -@@ -1282,13 +_,13 @@ +@@ -1249,13 +_,13 @@ if (itemstack != null) { if (this instanceof ServerPlayer serverplayer) { @@ -261,7 +285,7 @@ this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 900, 1)); this.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, 100, 1)); this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 800, 0)); -@@ -1359,6 +_,7 @@ +@@ -1326,6 +_,7 @@ } public void die(DamageSource p_21014_) { @@ -269,53 +293,45 @@ if (!this.isRemoved() && !this.dead) { Entity entity = p_21014_.getEntity(); LivingEntity livingentity = this.getKillCredit(); -@@ -1394,7 +_,7 @@ +@@ -1361,7 +_,7 @@ if (!this.level().isClientSide) { boolean flag = false; if (p_21269_ instanceof WitherBoss) { - if (this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (net.neoforged.neoforge.event.EventHooks.getMobGriefingEvent(this.level(), p_21269_)) { ++ if (net.neoforged.neoforge.event.EventHooks.canEntityGrief(this.level(), p_21269_)) { BlockPos blockpos = this.blockPosition(); BlockState blockstate = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level().getBlockState(blockpos).isAir() && blockstate.canSurvive(this.level(), blockpos)) { -@@ -1413,12 +_,9 @@ - - protected void dropAllDeathLoot(DamageSource p_21192_) { - Entity entity = p_21192_.getEntity(); -- int i; -- if (entity instanceof Player) { -- i = EnchantmentHelper.getMobLooting((LivingEntity)entity); -- } else { -- i = 0; -- } -+ -+ int i = net.neoforged.neoforge.common.CommonHooks.getLootingLevel(this, entity, p_21192_); -+ this.captureDrops(new java.util.ArrayList<>()); +@@ -1379,6 +_,7 @@ + } + protected void dropAllDeathLoot(ServerLevel p_348524_, DamageSource p_21192_) { ++ this.captureDrops(new java.util.ArrayList<>()); boolean flag = this.lastHurtByPlayerTime > 0; - if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { -@@ -1428,6 +_,10 @@ + if (this.shouldDropLoot() && p_348524_.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { + this.dropFromLootTable(p_21192_, flag); +@@ -1387,6 +_,10 @@ this.dropEquipment(); - this.dropExperience(); + this.dropExperience(p_21192_.getEntity()); + + Collection drops = captureDrops(null); -+ if (!net.neoforged.neoforge.common.CommonHooks.onLivingDrops(this, p_21192_, drops, i, lastHurtByPlayerTime > 0)) ++ if (!net.neoforged.neoforge.common.CommonHooks.onLivingDrops(this, p_21192_, drops, lastHurtByPlayerTime > 0)) + drops.forEach(e -> level().addFreshEntity(e)); } protected void dropEquipment() { -@@ -1440,7 +_,8 @@ +@@ -1399,7 +_,8 @@ this.isAlwaysExperienceDropper() || this.lastHurtByPlayerTime > 0 && this.shouldDropExperience() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT) )) { -- ExperienceOrb.award((ServerLevel)this.level(), this.position(), this.getExperienceReward()); -+ int reward = net.neoforged.neoforge.event.EventHooks.getExperienceDrop(this, this.lastHurtByPlayer, this.getExperienceReward()); +- ExperienceOrb.award(serverlevel, this.position(), this.getExperienceReward(serverlevel, p_345346_)); ++ int reward = net.neoforged.neoforge.event.EventHooks.getExperienceDrop(this, this.lastHurtByPlayer, this.getExperienceReward(serverlevel, p_345346_)); + ExperienceOrb.award((ServerLevel) this.level(), this.position(), reward); } } -@@ -1474,6 +_,11 @@ +@@ -1440,6 +_,11 @@ } public void knockback(double p_147241_, double p_147242_, double p_147243_) { @@ -327,7 +343,7 @@ p_147241_ *= 1.0 - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); if (!(p_147241_ <= 0.0)) { this.hasImpulse = true; -@@ -1545,15 +_,9 @@ +@@ -1521,15 +_,9 @@ } else { BlockPos blockpos = this.blockPosition(); BlockState blockstate = this.getInBlockState(); @@ -346,7 +362,7 @@ } } -@@ -1584,6 +_,11 @@ +@@ -1558,6 +_,11 @@ @Override public boolean causeFallDamage(float p_147187_, float p_147188_, DamageSource p_147189_) { @@ -358,7 +374,7 @@ boolean flag = super.causeFallDamage(p_147187_, p_147188_, p_147189_); int i = this.calculateFallDamage(p_147187_, p_147188_); if (i > 0) { -@@ -1611,9 +_,10 @@ +@@ -1585,9 +_,10 @@ int i = Mth.floor(this.getX()); int j = Mth.floor(this.getY() - 0.2F); int k = Mth.floor(this.getZ()); @@ -371,7 +387,7 @@ this.playSound(soundtype.getFallSound(), soundtype.getVolume() * 0.5F, soundtype.getPitch() * 0.75F); } } -@@ -1642,6 +_,8 @@ +@@ -1616,6 +_,8 @@ if (!(p_330394_ <= 0.0F)) { int i = (int)Math.max(1.0F, p_330394_ / 4.0F); @@ -380,7 +396,7 @@ for (EquipmentSlot equipmentslot : p_331314_) { ItemStack itemstack = this.getItemBySlot(equipmentslot); if (itemstack.getItem() instanceof ArmorItem && itemstack.canBeHurtBy(p_330843_)) { -@@ -1674,10 +_,11 @@ +@@ -1648,10 +_,11 @@ p_21194_ = Math.max(f / 25.0F, 0.0F); float f2 = f1 - p_21194_; if (f2 > 0.0F && f2 < 3.4028235E37F) { @@ -394,15 +410,15 @@ } } } -@@ -1690,6 +_,7 @@ - int k = EnchantmentHelper.getDamageProtection(this.getArmorAndBodyArmorSlots(), p_21193_); - if (k > 0) { - p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, (float)k); +@@ -1670,6 +_,7 @@ + + if (f3 > 0.0F) { + p_21194_ = CombatRules.getDamageAfterMagicAbsorb(p_21194_, f3); + this.damageContainers.peek().setReduction(net.neoforged.neoforge.common.damagesource.DamageContainer.Reduction.ENCHANTMENTS,this.damageContainers.peek().getNewDamage() - p_21194_); } return p_21194_; -@@ -1699,11 +_,14 @@ +@@ -1679,11 +_,14 @@ protected void actuallyHurt(DamageSource p_21240_, float p_21241_) { if (!this.isInvulnerableTo(p_21240_)) { @@ -422,7 +438,7 @@ if (f > 0.0F && f < 3.4028235E37F && p_21240_.getEntity() instanceof ServerPlayer serverplayer) { serverplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f * 10.0F)); } -@@ -1713,7 +_,9 @@ +@@ -1693,7 +_,9 @@ this.setHealth(this.getHealth() - f1); this.setAbsorptionAmount(this.getAbsorptionAmount() - f1); this.gameEvent(GameEvent.ENTITY_DAMAGE); @@ -432,7 +448,7 @@ } } -@@ -1767,6 +_,8 @@ +@@ -1747,6 +_,8 @@ } public void swing(InteractionHand p_21012_, boolean p_21013_) { @@ -441,7 +457,7 @@ if (!this.swinging || this.swingTime >= this.getCurrentSwingDuration() / 2 || this.swingTime < 0) { this.swingTime = -1; this.swinging = true; -@@ -1879,8 +_,10 @@ +@@ -1859,8 +_,10 @@ private void swapHandItems() { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.OFFHAND); @@ -454,7 +470,7 @@ } @Override -@@ -2077,15 +_,18 @@ +@@ -2064,15 +_,18 @@ } this.hasImpulse = true; @@ -475,7 +491,7 @@ } protected float getWaterSlowDown() { -@@ -2110,7 +_,8 @@ +@@ -2097,7 +_,8 @@ } FluidState fluidstate = this.level().getFluidState(this.blockPosition()); @@ -485,7 +501,7 @@ double d9 = this.getY(); float f4 = this.isSprinting() ? 0.9F : this.getWaterSlowDown(); float f5 = 0.02F; -@@ -2132,6 +_,7 @@ +@@ -2115,6 +_,7 @@ f4 = 0.96F; } @@ -493,7 +509,7 @@ this.moveRelative(f5, p_21280_); this.move(MoverType.SELF, this.getDeltaMovement()); Vec3 vec36 = this.getDeltaMovement(); -@@ -2145,6 +_,7 @@ +@@ -2128,6 +_,7 @@ if (this.horizontalCollision && this.isFree(vec32.x, vec32.y + 0.6F - this.getY() + d9, vec32.z)) { this.setDeltaMovement(vec32.x, 0.3F, vec32.z); } @@ -501,7 +517,7 @@ } else if (this.isInLava() && this.isAffectedByFluids() && !this.canStandOnFluid(fluidstate)) { double d8 = this.getY(); this.moveRelative(0.02F, p_21280_); -@@ -2207,7 +_,7 @@ +@@ -2190,7 +_,7 @@ } } else { BlockPos blockpos = this.getBlockPosBelowThatAffectsMyMovement(); @@ -510,7 +526,7 @@ float f3 = this.onGround() ? f2 * 0.91F : 0.91F; Vec3 vec35 = this.handleRelativeFrictionAndCalculateMovement(p_21280_, f2); double d2 = vec35.y; -@@ -2301,7 +_,7 @@ +@@ -2284,7 +_,7 @@ double d0 = Mth.clamp(p_21298_.x, -0.15F, 0.15F); double d1 = Mth.clamp(p_21298_.z, -0.15F, 0.15F); double d2 = Math.max(p_21298_.y, -0.15F); @@ -519,15 +535,7 @@ d2 = 0.0; } -@@ -2334,6 +_,7 @@ - - @Override - public void tick() { -+ if (net.neoforged.neoforge.common.CommonHooks.onLivingTick(this)) return; - super.tick(); - this.updatingUsingItem(); - this.updateSwimAmount(); -@@ -2483,6 +_,7 @@ +@@ -2466,6 +_,7 @@ }; ItemStack itemstack1 = this.getItemBySlot(equipmentslot); if (this.equipmentHasChanged(itemstack, itemstack1)) { @@ -535,7 +543,7 @@ if (map == null) { map = Maps.newEnumMap(EquipmentSlot.class); } -@@ -2642,6 +_,9 @@ +@@ -2637,6 +_,9 @@ this.level().getProfiler().push("jump"); if (this.jumping && this.isAffectedByFluids()) { double d3; @@ -545,7 +553,7 @@ if (this.isInLava()) { d3 = this.getFluidHeight(FluidTags.LAVA); } else { -@@ -2652,15 +_,17 @@ +@@ -2647,15 +_,17 @@ double d4 = this.getFluidJumpThreshold(); if (!flag || this.onGround() && !(d3 > d4)) { if (!this.isInLava() || this.onGround() && !(d3 > d4)) { @@ -565,7 +573,7 @@ } } else { this.noJumpDelay = 0; -@@ -2725,6 +_,8 @@ +@@ -2720,6 +_,8 @@ boolean flag = this.getSharedFlag(7); if (flag && !this.onGround() && !this.isPassenger() && !this.hasEffect(MobEffects.LEVITATION)) { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.CHEST); @@ -574,7 +582,7 @@ if (itemstack.is(Items.ELYTRA) && ElytraItem.isFlyEnabled(itemstack)) { flag = true; int i = this.fallFlyTicks + 1; -@@ -2982,8 +_,11 @@ +@@ -2979,8 +_,11 @@ private void updatingUsingItem() { if (this.isUsingItem()) { @@ -588,7 +596,7 @@ this.updateUsingItem(this.useItem); } else { this.stopUsingItem(); -@@ -2992,12 +_,15 @@ +@@ -2989,12 +_,15 @@ } protected void updateUsingItem(ItemStack p_147201_) { @@ -605,19 +613,19 @@ this.completeUsingItem(); } } -@@ -3032,8 +_,10 @@ +@@ -3029,8 +_,10 @@ public void startUsingItem(InteractionHand p_21159_) { ItemStack itemstack = this.getItemInHand(p_21159_); if (!itemstack.isEmpty() && !this.isUsingItem()) { -+ int duration = net.neoforged.neoforge.event.EventHooks.onItemUseStart(this, itemstack, itemstack.getUseDuration()); ++ int duration = net.neoforged.neoforge.event.EventHooks.onItemUseStart(this, itemstack, itemstack.getUseDuration(this)); + if (duration < 0) return; // Neo: Early return for negative values, as that indicates event cancellation. this.useItem = itemstack; -- this.useItemRemaining = itemstack.getUseDuration(); +- this.useItemRemaining = itemstack.getUseDuration(this); + this.useItemRemaining = duration; if (!this.level().isClientSide) { this.setLivingEntityFlag(1, true); this.setLivingEntityFlag(2, p_21159_ == InteractionHand.OFF_HAND); -@@ -3109,7 +_,8 @@ +@@ -3111,7 +_,8 @@ } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { this.triggerItemUseEffects(this.useItem, 16); @@ -627,7 +635,7 @@ if (itemstack != this.useItem) { this.setItemInHand(interactionhand, itemstack); } -@@ -3134,7 +_,11 @@ +@@ -3136,7 +_,11 @@ public void releaseUsingItem() { if (!this.useItem.isEmpty()) { @@ -639,7 +647,7 @@ if (this.useItem.useOnRelease()) { this.updatingUsingItem(); } -@@ -3144,6 +_,7 @@ +@@ -3146,6 +_,7 @@ } public void stopUsingItem() { @@ -647,16 +655,16 @@ if (!this.level().isClientSide) { boolean flag = this.isUsingItem(); this.setLivingEntityFlag(1, false); -@@ -3159,7 +_,7 @@ +@@ -3161,7 +_,7 @@ public boolean isBlocking() { if (this.isUsingItem() && !this.useItem.isEmpty()) { Item item = this.useItem.getItem(); -- return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5; -+ return !this.useItem.canPerformAction(net.neoforged.neoforge.common.ToolActions.SHIELD_BLOCK) ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5; +- return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem, this) - this.useItemRemaining >= 5; ++ return !this.useItem.canPerformAction(net.neoforged.neoforge.common.ToolActions.SHIELD_BLOCK) ? false : item.getUseDuration(this.useItem, this) - this.useItemRemaining >= 5; } else { return false; } -@@ -3300,8 +_,8 @@ +@@ -3302,8 +_,8 @@ } BlockState blockstate = this.level().getBlockState(p_21141_); @@ -667,14 +675,14 @@ } this.setPose(Pose.SLEEPING); -@@ -3316,15 +_,17 @@ +@@ -3318,15 +_,17 @@ } private boolean checkBedExists() { -- return this.getSleepingPos().map(p_337701_ -> this.level().getBlockState(p_337701_).getBlock() instanceof BedBlock).orElse(false); -+ return this.getSleepingPos().map((p_289310_) -> { -+ return net.neoforged.neoforge.event.EventHooks.fireSleepingLocationCheck(this, p_289310_); -+ }).orElse(false); +- return this.getSleepingPos().map(p_352707_ -> this.level().getBlockState(p_352707_).getBlock() instanceof BedBlock).orElse(false); ++ // Neo: Overwrite the vanilla instanceof BedBlock check with isBed and fire the CanContinueSleepingEvent. ++ boolean hasBed = this.getSleepingPos().map(pos -> this.level().getBlockState(pos).isBed(this.level(), pos, this)).orElse(false); ++ return net.neoforged.neoforge.event.EventHooks.canEntityContinueSleeping(this, hasBed ? null : Player.BedSleepingProblem.NOT_POSSIBLE_HERE); } public void stopSleeping() { @@ -688,7 +696,7 @@ Vec3 vec31 = BedBlock.findStandUpPosition(this.getType(), this.level(), p_261435_, direction, this.getYRot()).orElseGet(() -> { BlockPos blockpos = p_261435_.above(); return new Vec3((double)blockpos.getX() + 0.5, (double)blockpos.getY() + 0.1, (double)blockpos.getZ() + 0.5); -@@ -3345,7 +_,9 @@ +@@ -3347,7 +_,9 @@ @Nullable public Direction getBedOrientation() { BlockPos blockpos = this.getSleepingPos().orElse(null); @@ -699,7 +707,7 @@ } @Override -@@ -3354,11 +_,11 @@ +@@ -3356,11 +_,11 @@ } public ItemStack getProjectile(ItemStack p_21272_) { @@ -707,13 +715,13 @@ + return net.neoforged.neoforge.common.CommonHooks.getProjectile(this, p_21272_, ItemStack.EMPTY); } - public ItemStack eat(Level p_21067_, ItemStack p_21068_) { + public final ItemStack eat(Level p_21067_, ItemStack p_21068_) { - FoodProperties foodproperties = p_21068_.get(DataComponents.FOOD); + FoodProperties foodproperties = p_21068_.getFoodProperties(this); - if (foodproperties != null) { - p_21067_.playSound( - null, -@@ -3408,6 +_,39 @@ + return foodproperties != null ? this.eat(p_21067_, p_21068_, foodproperties) : p_21068_; + } + +@@ -3411,6 +_,39 @@ return p_320526_ == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND; } @@ -753,20 +761,20 @@ @Override public AABB getBoundingBoxForCulling() { if (this.getItemBySlot(EquipmentSlot.HEAD).is(Items.DRAGON_HEAD)) { -@@ -3419,6 +_,8 @@ +@@ -3422,6 +_,8 @@ } - public static EquipmentSlot getEquipmentSlotForItem(ItemStack p_147234_) { + public EquipmentSlot getEquipmentSlotForItem(ItemStack p_147234_) { + final EquipmentSlot slot = p_147234_.getEquipmentSlot(); + if (slot != null) return slot; // FORGE: Allow modders to set a non-default equipment slot for a stack; e.g. a non-armor chestplate-slot item Equipable equipable = Equipable.get(p_147234_); - return equipable != null ? equipable.getEquipmentSlot() : EquipmentSlot.MAINHAND; - } -@@ -3497,7 +_,7 @@ + if (equipable != null) { + EquipmentSlot equipmentslot = equipable.getEquipmentSlot(); +@@ -3507,7 +_,7 @@ } public boolean canDisableShield() { -- return this.getMainHandItem().getItem() instanceof AxeItem; +- return this.getWeaponItem().getItem() instanceof AxeItem; + return this.getMainHandItem().canDisableShield(this.useItem, this, this); } diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index 8d80330f2c..a03ffc195f 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -114,7 +_,8 @@ +@@ -113,7 +_,8 @@ import net.minecraft.world.scores.Team; import org.slf4j.Logger; @@ -10,53 +10,52 @@ private static final Logger LOGGER = LogUtils.getLogger(); public static final HumanoidArm DEFAULT_MAIN_HAND = HumanoidArm.RIGHT; public static final int DEFAULT_MODEL_CUSTOMIZATION = 0; -@@ -192,6 +_,9 @@ - @Nullable +@@ -193,6 +_,9 @@ public Entity currentExplosionCause; - public boolean ignoreFallDamageFromCurrentImpulse; + private boolean ignoreFallDamageFromCurrentImpulse; + private int currentImpulseContextResetGraceTime; + private final java.util.Collection prefixes = new java.util.LinkedList<>(); + private final java.util.Collection suffixes = new java.util.LinkedList<>(); + @Nullable private Pose forcedPose; public Player(Level p_250508_, BlockPos p_250289_, float p_251702_, GameProfile p_252153_) { super(EntityType.PLAYER, p_250508_); -@@ -224,7 +_,9 @@ - .add(Attributes.LUCK) - .add(Attributes.BLOCK_INTERACTION_RANGE, 4.5) - .add(Attributes.ENTITY_INTERACTION_RANGE, 3.0) -- .add(Attributes.BLOCK_BREAK_SPEED); -+ .add(Attributes.BLOCK_BREAK_SPEED) -+ .add(Attributes.ATTACK_KNOCKBACK) +@@ -229,7 +_,8 @@ + .add(Attributes.SUBMERGED_MINING_SPEED) + .add(Attributes.SNEAKING_SPEED) + .add(Attributes.MINING_EFFICIENCY) +- .add(Attributes.SWEEPING_DAMAGE_RATIO); ++ .add(Attributes.SWEEPING_DAMAGE_RATIO) + .add(net.neoforged.neoforge.common.NeoForgeMod.CREATIVE_FLIGHT); } @Override -@@ -240,6 +_,7 @@ +@@ -245,6 +_,7 @@ @Override public void tick() { -+ net.neoforged.neoforge.event.EventHooks.onPlayerPreTick(this); ++ net.neoforged.neoforge.event.EventHooks.firePlayerTickPre(this); this.noPhysics = this.isSpectator(); if (this.isSpectator()) { this.setOnGround(false); -@@ -255,7 +_,7 @@ +@@ -260,7 +_,7 @@ this.sleepCounter = 100; } - if (!this.level().isClientSide && this.level().isDay()) { -+ if (!this.level().isClientSide && !net.neoforged.neoforge.event.EventHooks.fireSleepingTimeCheck(this, getSleepingPos())) { ++ if (!this.level().isClientSide && !net.neoforged.neoforge.event.EventHooks.canEntityContinueSleeping(this, this.level().isDay() ? BedSleepingProblem.NOT_POSSIBLE_NOW : null)) { this.stopSleepInBed(false, true); } } else if (this.sleepCounter > 0) { -@@ -310,6 +_,7 @@ - this.turtleHelmetTick(); - this.cooldowns.tick(); - this.updatePlayerPose(); -+ net.neoforged.neoforge.event.EventHooks.onPlayerPostTick(this); +@@ -318,6 +_,7 @@ + if (this.currentImpulseContextResetGraceTime > 0) { + this.currentImpulseContextResetGraceTime--; + } ++ net.neoforged.neoforge.event.EventHooks.firePlayerTickPost(this); } @Override -@@ -389,6 +_,10 @@ +@@ -397,6 +_,10 @@ } protected void updatePlayerPose() { @@ -67,15 +66,15 @@ if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) { Pose pose; if (this.isFallFlying()) { -@@ -620,6 +_,7 @@ +@@ -630,6 +_,7 @@ @Override public void die(DamageSource p_36152_) { + if (net.neoforged.neoforge.common.CommonHooks.onLivingDeath(this, p_36152_)) return; super.die(p_36152_); this.reapplyPosition(); - if (!this.isSpectator()) { -@@ -674,7 +_,7 @@ + if (!this.isSpectator() && this.level() instanceof ServerLevel serverlevel) { +@@ -684,7 +_,7 @@ @Nullable public ItemEntity drop(ItemStack p_36177_, boolean p_36178_) { @@ -84,7 +83,7 @@ } @Nullable -@@ -716,7 +_,12 @@ +@@ -726,7 +_,12 @@ } } @@ -96,8 +95,8 @@ + public float getDigSpeed(BlockState p_36282_, @Nullable BlockPos pos) { float f = this.inventory.getDestroySpeed(p_36282_); if (f > 1.0F) { - int i = EnchantmentHelper.getBlockEfficiency(this); -@@ -748,11 +_,12 @@ + f += (float)this.getAttributeValue(Attributes.MINING_EFFICIENCY); +@@ -754,13 +_,19 @@ f /= 5.0F; } @@ -105,15 +104,19 @@ return f; } ++ @Deprecated // Neo: use position sensitive version below public boolean hasCorrectToolForDrops(BlockState p_36299_) { -- return !p_36299_.requiresCorrectToolForDrops() || this.inventory.getSelected().isCorrectToolForDrops(p_36299_); -+ return net.neoforged.neoforge.event.EventHooks.doPlayerHarvestCheck(this, p_36299_, !p_36299_.requiresCorrectToolForDrops() || this.inventory.getSelected().isCorrectToolForDrops(p_36299_)); + return !p_36299_.requiresCorrectToolForDrops() || this.inventory.getSelected().isCorrectToolForDrops(p_36299_); } ++ public boolean hasCorrectToolForDrops(BlockState state, Level level, BlockPos pos) { ++ return net.neoforged.neoforge.event.EventHooks.doPlayerHarvestCheck(this, state, level, pos); ++ } ++ @Override public void readAdditionalSaveData(CompoundTag p_36215_) { super.readAdditionalSaveData(p_36215_); -@@ -864,7 +_,9 @@ +@@ -872,7 +_,9 @@ this.removeEntitiesOnShoulder(); } @@ -124,7 +127,7 @@ if (this.level().getDifficulty() == Difficulty.PEACEFUL) { p_36155_ = 0.0F; } -@@ -918,7 +_,7 @@ +@@ -926,7 +_,7 @@ @Override protected void hurtCurrentlyUsedShield(float p_36383_) { @@ -133,14 +136,14 @@ if (!this.level().isClientSide) { this.awardStat(Stats.ITEM_USED.get(this.useItem.getItem())); } -@@ -926,7 +_,13 @@ +@@ -934,7 +_,13 @@ if (p_36383_ >= 3.0F) { int i = 1 + Mth.floor(p_36383_); InteractionHand interactionhand = this.getUsedItemHand(); - this.useItem.hurtAndBreak(i, this, getSlotForHand(interactionhand)); -+ if (!level().isClientSide && !hasInfiniteMaterials()) { -+ this.useItem.hurtAndBreak(i, getRandom(), this, () -> { -+ broadcastBreakEvent(getSlotForHand(interactionhand)); ++ if (this.level() instanceof ServerLevel serverlevel && !hasInfiniteMaterials()) { ++ this.useItem.hurtAndBreak(i, serverlevel, this, item -> { ++ this.onEquippedItemBroken(item, getSlotForHand(interactionhand)); + net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, this.useItem, interactionhand); + stopUsingItem(); // Neo: Fix MC-168573 ("After breaking a shield, the player's off-hand can't finish using some items") + }); @@ -148,7 +151,7 @@ if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -@@ -944,15 +_,17 @@ +@@ -952,11 +_,14 @@ @Override protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { if (!this.isInvulnerableTo(p_36312_)) { @@ -168,22 +171,17 @@ if (f > 0.0F && f < 3.4028235E37F) { this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); } -- - if (f1 != 0.0F) { - this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); - this.getCombatTracker().recordDamage(p_36312_, f1); -@@ -960,8 +_,9 @@ - if (f1 < 3.4028235E37F) { - this.awardStat(Stats.DAMAGE_TAKEN, Math.round(f1 * 10.0F)); +@@ -970,7 +_,9 @@ } -- + this.gameEvent(GameEvent.ENTITY_DAMAGE); + this.onDamageTaken(this.damageContainers.peek()); -+ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainers.peek()); } ++ net.neoforged.neoforge.common.CommonHooks.onLivingDamagePost(this, this.damageContainers.peek()); } } -@@ -1011,6 +_,8 @@ + +@@ -1014,6 +_,8 @@ return InteractionResult.PASS; } else { @@ -192,7 +190,7 @@ ItemStack itemstack = this.getItemInHand(p_36159_); ItemStack itemstack1 = itemstack.copy(); InteractionResult interactionresult = p_36158_.interact(this, p_36159_); -@@ -1019,6 +_,9 @@ +@@ -1022,6 +_,9 @@ itemstack.setCount(itemstack1.getCount()); } @@ -202,7 +200,7 @@ return interactionresult; } else { if (!itemstack.isEmpty() && p_36158_ instanceof LivingEntity) { -@@ -1030,6 +_,7 @@ +@@ -1033,6 +_,7 @@ if (interactionresult1.consumesAction()) { this.level().gameEvent(GameEvent.ENTITY_INTERACT, p_36158_.position(), GameEvent.Context.of(this)); if (itemstack.isEmpty() && !this.abilities.instabuild) { @@ -210,7 +208,7 @@ this.setItemInHand(p_36159_, ItemStack.EMPTY); } -@@ -1059,6 +_,7 @@ +@@ -1062,6 +_,7 @@ } @Override @@ -218,7 +216,7 @@ protected Vec3 maybeBackOffFromEdge(Vec3 p_36201_, MoverType p_36202_) { float f = this.maxUpStep(); if (!this.abilities.flying -@@ -1108,6 +_,7 @@ +@@ -1111,6 +_,7 @@ } } @@ -226,94 +224,93 @@ private boolean isAboveGround(float p_341626_) { return this.onGround() || this.fallDistance < p_341626_ && !this.canFallAtLeast(0.0, 0.0, p_341626_ - this.fallDistance); } -@@ -1129,6 +_,7 @@ +@@ -1132,6 +_,7 @@ } public void attack(Entity p_36347_) { + if (!net.neoforged.neoforge.common.CommonHooks.onPlayerAttackTarget(this, p_36347_)) return; if (p_36347_.isAttackable()) { if (!p_36347_.skipAttackInteraction(this)) { - float f = (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE); -@@ -1136,14 +_,13 @@ + float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE); +@@ -1141,7 +_,6 @@ float f2 = this.getAttackStrengthScale(0.5F); f *= 0.2F + f2 * f2 * 0.8F; f1 *= f2; - this.resetAttackStrengthTicker(); - if (p_36347_.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && p_36347_ instanceof Projectile projectile) { - projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true); - } else { - if (f > 0.0F || f1 > 0.0F) { - boolean flag = f2 > 0.9F; - boolean flag1 = false; -- int i = 0; -+ float i = (float)this.getAttributeValue(Attributes.ATTACK_KNOCKBACK); // Forge: Initialize this value to the attack knockback attribute of the player, which is by default 0 - i += EnchantmentHelper.getKnockbackBonus(this); - if (this.isSprinting() && flag) { - this.level() -@@ -1162,8 +_,10 @@ - && !this.isPassenger() - && p_36347_ instanceof LivingEntity - && !this.isSprinting(); -+ net.neoforged.neoforge.event.entity.player.CriticalHitEvent hitResult = net.neoforged.neoforge.common.CommonHooks.getCriticalHit(this, p_36347_, flag2, flag2 ? 1.5F : 1.0F); -+ flag2 = hitResult != null; - if (flag2) { -- f *= 1.5F; -+ f *= hitResult.getDamageModifier(); - } + if (p_36347_.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) + && p_36347_ instanceof Projectile projectile + && projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true)) { +@@ -1170,8 +_,12 @@ + && !this.isPassenger() + && p_36347_ instanceof LivingEntity + && !this.isSprinting(); ++ // Neo: Fire the critical hit event and override the critical hit status and damage multiplier based on the event. ++ // The boolean local above (flag2) is the vanilla critical hit result. ++ var critEvent = net.neoforged.neoforge.common.CommonHooks.fireCriticalHit(this, p_36347_, flag1, flag1 ? 1.5F : 1.0F); ++ flag1 = critEvent.isCriticalHit(); + if (flag1) { +- f *= 1.5F; ++ f *= critEvent.getDamageMultiplier(); + } + + float f3 = f + f1; +@@ -1179,9 +_,7 @@ + double d0 = (double)(this.walkDist - this.walkDistO); + if (flag4 && !flag1 && !flag && this.onGround() && d0 < (double)this.getSpeed()) { + ItemStack itemstack1 = this.getItemInHand(InteractionHand.MAIN_HAND); +- if (itemstack1.getItem() instanceof SwordItem) { +- flag2 = true; +- } ++ flag2 = itemstack1.canPerformAction(net.neoforged.neoforge.common.ToolActions.SWORD_SWEEP); + } - f += f1; -@@ -1171,9 +_,7 @@ - double d0 = (double)(this.walkDist - this.walkDistO); - if (flag && !flag2 && !flag1 && this.onGround() && d0 < (double)this.getSpeed()) { - ItemStack itemstack = this.getItemInHand(InteractionHand.MAIN_HAND); -- if (itemstack.getItem() instanceof SwordItem) { -- flag3 = true; -- } -+ flag3 = itemstack.canPerformAction(net.neoforged.neoforge.common.ToolActions.SWORD_SWEEP); + float f6 = 0.0F; +@@ -1217,11 +_,12 @@ + + for (LivingEntity livingentity2 : this.level() + .getEntitiesOfClass(LivingEntity.class, p_36347_.getBoundingBox().inflate(1.0, 0.25, 1.0))) { ++ double entityReachSq = Mth.square(this.entityInteractionRange()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. + if (livingentity2 != this + && livingentity2 != p_36347_ + && !this.isAlliedTo(livingentity2) + && (!(livingentity2 instanceof ArmorStand) || !((ArmorStand)livingentity2).isMarker()) +- && this.distanceToSqr(livingentity2) < 9.0) { ++ && this.distanceToSqr(livingentity2) < entityReachSq) { + float f5 = this.getEnchantedDamage(livingentity2, f7, damagesource) * f2; + livingentity2.knockback( + 0.4F, +@@ -1268,11 +_,12 @@ + + this.setLastHurtMob(p_36347_); + Entity entity = p_36347_; +- if (p_36347_ instanceof EnderDragonPart) { +- entity = ((EnderDragonPart)p_36347_).parentMob; ++ if (p_36347_ instanceof net.neoforged.neoforge.entity.PartEntity) { ++ entity = ((net.neoforged.neoforge.entity.PartEntity) p_36347_).getParent(); } - float f4 = 0.0F; -@@ -1215,11 +_,12 @@ - - for (LivingEntity livingentity : this.level() - .getEntitiesOfClass(LivingEntity.class, p_36347_.getBoundingBox().inflate(1.0, 0.25, 1.0))) { -+ double entityReachSq = Mth.square(this.entityInteractionRange()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. - if (livingentity != this - && livingentity != p_36347_ - && !this.isAlliedTo(livingentity) - && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).isMarker()) -- && this.distanceToSqr(livingentity) < 9.0) { -+ && this.distanceToSqr(livingentity) < entityReachSq) { - livingentity.knockback( - 0.4F, - (double)Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -@@ -1272,13 +_,15 @@ - EnchantmentHelper.doPostDamageEffects(this, p_36347_); - ItemStack itemstack1 = this.getMainHandItem(); - Entity entity = p_36347_; -- if (p_36347_ instanceof EnderDragonPart) { -- entity = ((EnderDragonPart)p_36347_).parentMob; -+ if (p_36347_ instanceof net.neoforged.neoforge.entity.PartEntity) { -+ entity = ((net.neoforged.neoforge.entity.PartEntity) p_36347_).getParent(); + boolean flag5 = false; ++ ItemStack copy = itemstack.copy(); + if (this.level() instanceof ServerLevel serverlevel1) { + if (entity instanceof LivingEntity livingentity3) { + flag5 = itemstack.hurtEnemy(livingentity3, this); +@@ -1287,6 +_,7 @@ } - if (!this.level().isClientSide && !itemstack1.isEmpty() && entity instanceof LivingEntity) { -+ ItemStack copy = itemstack1.copy(); - itemstack1.hurtEnemy((LivingEntity)entity, this); - if (itemstack1.isEmpty()) { -+ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, copy, InteractionHand.MAIN_HAND); + if (itemstack.isEmpty()) { ++ net.neoforged.neoforge.event.EventHooks.onPlayerDestroyItem(this, copy, itemstack == this.getMainHandItem() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); + if (itemstack == this.getMainHandItem()) { this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); - } - } -@@ -1309,6 +_,7 @@ - } + } else { +@@ -1311,6 +_,7 @@ + .playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F); } } + this.resetAttackStrengthTicker(); // FORGE: Moved from beginning of attack() so that getAttackStrengthScale() returns an accurate value during all attack events } } } -@@ -1319,7 +_,7 @@ +@@ -1325,7 +_,7 @@ } public void disableShield() { @@ -322,7 +319,7 @@ this.stopUsingItem(); this.level().broadcastEntityEvent(this, (byte)30); } -@@ -1385,6 +_,7 @@ +@@ -1391,6 +_,7 @@ } public void stopSleepInBed(boolean p_36226_, boolean p_36227_) { @@ -330,16 +327,7 @@ super.stopSleeping(); if (this.level() instanceof ServerLevel && p_36227_) { ((ServerLevel)this.level()).updateSleepingPlayerList(); -@@ -1417,7 +_,7 @@ - } else if (block instanceof BedBlock && BedBlock.canSetSpawn(p_36131_)) { - return BedBlock.findStandUpPosition(EntityType.PLAYER, p_36131_, p_36132_, blockstate.getValue(BedBlock.FACING), p_36133_); - } else if (!p_36134_) { -- return Optional.empty(); -+ return blockstate.getRespawnPosition(EntityType.PLAYER, p_36131_, p_36132_, p_36133_, null); - } else { - boolean flag = block.isPossibleToRespawnInThis(blockstate); - BlockState blockstate1 = p_36131_.getBlockState(p_36132_.above()); -@@ -1527,7 +_,8 @@ +@@ -1503,7 +_,8 @@ @Override public boolean causeFallDamage(float p_150093_, float p_150094_, DamageSource p_150095_) { @@ -349,7 +337,7 @@ return false; } else { if (p_150093_ >= 2.0F) { -@@ -1547,7 +_,7 @@ +@@ -1535,7 +_,7 @@ public boolean tryToStartFallFlying() { if (!this.onGround() && !this.isFallFlying() && !this.isInWater() && !this.hasEffect(MobEffects.LEVITATION)) { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.CHEST); @@ -358,7 +346,7 @@ this.startFallFlying(); return true; } -@@ -1576,13 +_,13 @@ +@@ -1564,13 +_,13 @@ protected void playStepSound(BlockPos p_282121_, BlockState p_282194_) { if (this.isInWater()) { this.waterSwimSound(); @@ -374,7 +362,7 @@ } else { super.playStepSound(blockpos, blockstate); } -@@ -1613,6 +_,10 @@ +@@ -1601,6 +_,10 @@ } public void giveExperiencePoints(int p_36291_) { @@ -385,7 +373,7 @@ this.increaseScore(p_36291_); this.experienceProgress = this.experienceProgress + (float)p_36291_ / (float)this.getXpNeededForNextLevel(); this.totalExperience = Mth.clamp(this.totalExperience + p_36291_, 0, Integer.MAX_VALUE); -@@ -1640,7 +_,7 @@ +@@ -1628,7 +_,7 @@ } public void onEnchantmentPerformed(ItemStack p_36172_, int p_36173_) { @@ -394,7 +382,7 @@ if (this.experienceLevel < 0) { this.experienceLevel = 0; this.experienceProgress = 0.0F; -@@ -1651,6 +_,10 @@ +@@ -1639,6 +_,10 @@ } public void giveExperienceLevels(int p_36276_) { @@ -405,7 +393,7 @@ this.experienceLevel += p_36276_; if (this.experienceLevel < 0) { this.experienceLevel = 0; -@@ -1859,7 +_,11 @@ +@@ -1847,7 +_,11 @@ @Override public Component getDisplayName() { @@ -418,7 +406,7 @@ return this.decorateDisplayNameComponent(mutablecomponent); } -@@ -2024,25 +_,25 @@ +@@ -2012,18 +_,18 @@ Predicate predicate = ((ProjectileWeaponItem)p_36349_.getItem()).getSupportedHeldProjectiles(); ItemStack itemstack = ProjectileWeaponItem.getHeldProjectile(this, predicate); if (!itemstack.isEmpty()) { @@ -440,15 +428,7 @@ } } } - - @Override - public ItemStack eat(Level p_36185_, ItemStack p_36186_) { -- this.getFoodData().eat(p_36186_); -+ this.getFoodData().eat(p_36186_, this); - this.awardStat(Stats.ITEM_USED.get(p_36186_.getItem())); - p_36185_.playSound( - null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, p_36185_.random.nextFloat() * 0.1F + 0.9F -@@ -2186,5 +_,39 @@ +@@ -2201,5 +_,39 @@ public Component getMessage() { return this.message; } From 9438989d0df901fe1e8ee42edb52340a7d04f861 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 13 Jun 2024 18:51:27 -0400 Subject: [PATCH 32/41] more rebase fixes --- .../client/player/LocalPlayer.java.patch | 8 - .../neoforge/common/CommonHooks.java | 309 +++++++++++------- 2 files changed, 183 insertions(+), 134 deletions(-) diff --git a/patches/net/minecraft/client/player/LocalPlayer.java.patch b/patches/net/minecraft/client/player/LocalPlayer.java.patch index 4e7b967387..632b558ef9 100644 --- a/patches/net/minecraft/client/player/LocalPlayer.java.patch +++ b/patches/net/minecraft/client/player/LocalPlayer.java.patch @@ -1,13 +1,5 @@ --- a/net/minecraft/client/player/LocalPlayer.java +++ b/net/minecraft/client/player/LocalPlayer.java -@@ -161,6 +_,7 @@ - - @Override - public boolean hurt(DamageSource p_108662_, float p_108663_) { -+ net.neoforged.neoforge.common.CommonHooks.onPlayerIncomingDamage(this, this.damageContainer); - return false; - } - @@ -297,6 +_,7 @@ ServerboundPlayerActionPacket.Action serverboundplayeractionpacket$action = p_108701_ ? ServerboundPlayerActionPacket.Action.DROP_ALL_ITEMS diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index bb07b7dda5..57d2cb277f 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -10,7 +10,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; -import com.google.gson.JsonObject; import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -45,28 +44,32 @@ import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderSet; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.chat.ChatDecorator; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.TextColor; import net.minecraft.network.chat.contents.PlainTextContents; -import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.packs.PackType; import net.minecraft.stats.Stats; import net.minecraft.tags.BlockTags; -import net.minecraft.tags.TagEntry; import net.minecraft.tags.TagKey; import net.minecraft.util.CrudeIncrementalIntIdentityHashBiMap; import net.minecraft.util.Mth; @@ -77,6 +80,7 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffectUtil; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -88,6 +92,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.DefaultAttributes; +import net.minecraft.world.entity.ai.village.poi.PoiManager; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.monster.EnderMan; import net.minecraft.world.entity.player.Player; @@ -109,11 +114,9 @@ import net.minecraft.world.item.alchemy.Potion; import net.minecraft.world.item.alchemy.PotionContents; import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.item.enchantment.ItemEnchantments; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; @@ -122,9 +125,11 @@ import net.minecraft.world.level.biome.MobSpawnSettings; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.GameMasterBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; @@ -139,16 +144,17 @@ import net.minecraft.world.phys.Vec3; import net.neoforged.fml.ModList; import net.neoforged.fml.ModLoader; +import net.neoforged.fml.i18n.MavenVersionTranslator; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.client.ClientHooks; import net.neoforged.neoforge.common.conditions.ConditionalOps; import net.neoforged.neoforge.common.damagesource.DamageContainer; import net.neoforged.neoforge.common.extensions.IEntityExtension; -import net.neoforged.neoforge.common.extensions.IItemStackExtension; import net.neoforged.neoforge.common.loot.IGlobalLootModifier; import net.neoforged.neoforge.common.loot.LootModifierManager; import net.neoforged.neoforge.common.loot.LootTableIdCondition; import net.neoforged.neoforge.common.util.BlockSnapshot; import net.neoforged.neoforge.common.util.Lazy; -import net.neoforged.neoforge.common.util.MavenVersionStringHelper; import net.neoforged.neoforge.event.AnvilUpdateEvent; import net.neoforged.neoforge.event.DifficultyChangeEvent; import net.neoforged.neoforge.event.EventHooks; @@ -181,17 +187,20 @@ import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; import net.neoforged.neoforge.event.entity.living.LivingSwapItemsEvent; import net.neoforged.neoforge.event.entity.living.LivingUseTotemEvent; -import net.neoforged.neoforge.event.entity.living.LootingLevelEvent; +import net.neoforged.neoforge.event.entity.living.MobEffectEvent; import net.neoforged.neoforge.event.entity.player.AnvilRepairEvent; import net.neoforged.neoforge.event.entity.player.AttackEntityEvent; import net.neoforged.neoforge.event.entity.player.CriticalHitEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; +import net.neoforged.neoforge.event.level.BlockDropsEvent; import net.neoforged.neoforge.event.level.BlockEvent; import net.neoforged.neoforge.event.level.NoteBlockEvent; +import net.neoforged.neoforge.event.level.block.CropGrowEvent; import net.neoforged.neoforge.fluids.FluidType; import net.neoforged.neoforge.registries.NeoForgeRegistries; import net.neoforged.neoforge.resource.ResourcePackLoader; +import net.neoforged.neoforge.server.ServerLifecycleHooks; import net.neoforged.neoforge.server.permission.PermissionAPI; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -216,13 +225,6 @@ public static boolean canContinueUsing(ItemStack from, ItemStack to) { return false; } - public static boolean isCorrectToolForDrops(BlockState state, Player player) { - if (!state.requiresCorrectToolForDrops()) - return EventHooks.doPlayerHarvestCheck(player, state, true); - - return player.hasCorrectToolForDrops(state); - } - public static boolean onItemStackedOn(ItemStack carriedItem, ItemStack stackedOnItem, Slot slot, ClickAction action, Player player, SlotAccess carriedSlotAccess) { return NeoForge.EVENT_BUS.post(new ItemStackedOnOtherEvent(carriedItem, stackedOnItem, slot, action, player, carriedSlotAccess)).isCanceled(); } @@ -350,8 +352,8 @@ public static boolean onLivingDeath(LivingEntity entity, DamageSource src) { return NeoForge.EVENT_BUS.post(new LivingDeathEvent(entity, src)).isCanceled(); } - public static boolean onLivingDrops(LivingEntity entity, DamageSource source, Collection drops, int lootingLevel, boolean recentlyHit) { - return NeoForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, lootingLevel, recentlyHit)).isCanceled(); + public static boolean onLivingDrops(LivingEntity entity, DamageSource source, Collection drops, boolean recentlyHit) { + return NeoForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, recentlyHit)).isCanceled(); } @Nullable @@ -360,21 +362,6 @@ public static float[] onLivingFall(LivingEntity entity, float distance, float da return (NeoForge.EVENT_BUS.post(event).isCanceled() ? null : new float[] { event.getDistance(), event.getDamageMultiplier() }); } - public static int getLootingLevel(Entity target, @Nullable Entity killer, @Nullable DamageSource cause) { - int looting = 0; - if (killer instanceof LivingEntity) - looting = EnchantmentHelper.getMobLooting((LivingEntity) killer); - if (target instanceof LivingEntity) - looting = getLootingLevel((LivingEntity) target, cause, looting); - return looting; - } - - public static int getLootingLevel(LivingEntity target, @Nullable DamageSource cause, int level) { - LootingLevelEvent event = new LootingLevelEvent(target, cause, level); - NeoForge.EVENT_BUS.post(event); - return event.getLootingLevel(); - } - public static double getEntityVisibilityMultiplier(LivingEntity entity, Entity lookingEntity, double originalMultiplier) { LivingEvent.LivingVisibilityEvent event = new LivingEvent.LivingVisibilityEvent(entity, lookingEntity, originalMultiplier); NeoForge.EVENT_BUS.post(event); @@ -525,60 +512,72 @@ else if (end.length() > 0) return ichat; } - public static void dropXpForBlock(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack) { - int fortuneLevel = stack.getEnchantmentLevel(Enchantments.FORTUNE); - int silkTouchLevel = stack.getEnchantmentLevel(Enchantments.SILK_TOUCH); - int exp = state.getExpDrop(level, level.random, pos, fortuneLevel, silkTouchLevel); - if (exp > 0) - state.getBlock().popExperience(level, pos, exp); + /** + * Fires the {@link BlockDropsEvent} when block drops (items and experience) are determined. + * If the event is not cancelled, all drops will be added to the world, and then {@link BlockBehaviour#spawnAfterBreak} will be called. + * + * @param level The level + * @param pos The broken block's position + * @param state The broken block's state + * @param blockEntity The block entity from the given position + * @param drops The list of all items dropped by the block, captured from {@link Block#getDrops} + * @param breaker The entity who broke the block, or null if unknown + * @param tool The tool used when breaking the block; may be empty + */ + public static void handleBlockDrops(ServerLevel level, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, List drops, @Nullable Entity breaker, ItemStack tool) { + BlockDropsEvent event = new BlockDropsEvent(level, pos, state, blockEntity, drops, breaker, tool); + NeoForge.EVENT_BUS.post(event); + if (!event.isCanceled()) { + for (ItemEntity entity : event.getDrops()) { + level.addFreshEntity(entity); + } + // Always pass false for the dropXP (last) param to spawnAfterBreak since we handle XP. + state.spawnAfterBreak((ServerLevel) level, pos, tool, false); + if (event.getDroppedExperience() > 0) { + state.getBlock().popExperience(level, pos, event.getDroppedExperience()); + } + } } - public static int onBlockBreakEvent(Level level, GameType gameType, ServerPlayer entityPlayer, BlockPos pos) { - // Logic from tryHarvestBlock for pre-canceling the event + /** + * Fires {@link BlockEvent.BreakEvent}, pre-emptively canceling the event based on the conditions that will cause the block to not be broken anyway. + *

        + * Note that undoing the pre-cancel will not permit breaking the block, since the vanilla conditions will always be checked. + * + * @param level The level + * @param gameType The game type of the breaking player + * @param player The breaking player + * @param pos The position of the block being broken + * @param state The state of the block being broken + * @return The event + */ + public static BlockEvent.BreakEvent fireBlockBreak(Level level, GameType gameType, ServerPlayer player, BlockPos pos, BlockState state) { boolean preCancelEvent = false; - ItemStack itemstack = entityPlayer.getMainHandItem(); - if (!itemstack.isEmpty() && !itemstack.getItem().canAttackBlock(level.getBlockState(pos), level, pos, entityPlayer)) { + + ItemStack itemstack = player.getMainHandItem(); + if (!itemstack.isEmpty() && !itemstack.getItem().canAttackBlock(state, level, pos, player)) { preCancelEvent = true; } - if (gameType.isBlockPlacingRestricted()) { - if (gameType == GameType.SPECTATOR) - preCancelEvent = true; - - if (!entityPlayer.mayBuild()) { - AdventureModePredicate adventureModePredicate = itemstack.get(DataComponents.CAN_BREAK); - if (itemstack.isEmpty() || adventureModePredicate == null || !adventureModePredicate.test(new BlockInWorld(level, pos, false))) { - preCancelEvent = true; - } - } + if (player.blockActionRestricted(level, pos, gameType)) { + preCancelEvent = true; } - // Tell client the block is gone immediately then process events - if (level.getBlockEntity(pos) == null) { - entityPlayer.connection.send(new ClientboundBlockUpdatePacket(pos, level.getFluidState(pos).createLegacyBlock())); + if (state.getBlock() instanceof GameMasterBlock && !player.canUseGameMasterBlocks()) { + preCancelEvent = true; } // Post the block break event - BlockState state = level.getBlockState(pos); - BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(level, pos, state, entityPlayer); + BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(level, pos, state, player); event.setCanceled(preCancelEvent); NeoForge.EVENT_BUS.post(event); - // Handle if the event is canceled + // If the event is canceled, let the client know the block still exists if (event.isCanceled()) { - // Let the client know the block still exists - entityPlayer.connection.send(new ClientboundBlockUpdatePacket(level, pos)); - - // Update any tile entity data for this block - BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity != null) { - Packet pkt = blockEntity.getUpdatePacket(); - if (pkt != null) { - entityPlayer.connection.send(pkt); - } - } + player.connection.send(new ClientboundBlockUpdatePacket(pos, state)); } - return event.isCanceled() ? -1 : event.getExpToDrop(); + + return event; } public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { @@ -589,13 +588,14 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { if (player != null && !player.getAbilities().mayBuild) { AdventureModePredicate adventureModePredicate = itemstack.get(DataComponents.CAN_PLACE_ON); if (adventureModePredicate == null || !adventureModePredicate.test(new BlockInWorld(level, context.getClickedPos(), false))) { - return net.minecraft.world.InteractionResult.PASS; + return InteractionResult.PASS; } } // handle all placement events here Item item = itemstack.getItem(); int size = itemstack.getCount(); + DataComponentMap components = itemstack.getComponents(); // Porting 1.20.5 redo this for components? //CompoundTag nbt = null; //if (itemstack.getTag() != null) @@ -614,17 +614,14 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { if (ret.consumesAction()) { // save new item data int newSize = itemstack.getCount(); - //CompoundTag newNBT = null; - //if (itemstack.getTag() != null) { - // newNBT = itemstack.getTag().copy(); - //} + DataComponentMap newComponents = itemstack.getComponents(); @SuppressWarnings("unchecked") List blockSnapshots = (List) level.capturedBlockSnapshots.clone(); level.capturedBlockSnapshots.clear(); // make sure to set pre-placement item data for event itemstack.setCount(size); - //itemstack.setTag(nbt); + itemstack.applyComponents(components); //TODO: Set pre-placement item attachments? Direction side = context.getClickedFace(); @@ -641,17 +638,17 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { // revert back all captured blocks for (BlockSnapshot blocksnapshot : Lists.reverse(blockSnapshots)) { level.restoringBlockSnapshots = true; - blocksnapshot.restore(true, false); + blocksnapshot.restore(blocksnapshot.getFlags() | Block.UPDATE_CLIENTS); level.restoringBlockSnapshots = false; } } else { // Change the stack to its new content itemstack.setCount(newSize); - //itemstack.setTag(newNBT); + itemstack.applyComponents(newComponents); for (BlockSnapshot snap : blockSnapshots) { - int updateFlag = snap.getFlag(); - BlockState oldBlock = snap.getReplacedBlock(); + int updateFlag = snap.getFlags(); + BlockState oldBlock = snap.getState(); BlockState newBlock = level.getBlockState(snap.getPos()); newBlock.onPlace(level, snap.getPos(), oldBlock, false); @@ -778,14 +775,6 @@ public static InteractionResult onItemRightClick(Player player, InteractionHand return evt.isCanceled() ? evt.getCancellationResult() : null; } - /** - * @deprecated Use {@link #onLeftClickBlock(Player, BlockPos, Direction, ServerboundPlayerActionPacket.Action)} instead - */ - @Deprecated(since = "1.20.1", forRemoval = true) - public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(Player player, BlockPos pos, Direction face) { - return onLeftClickBlock(player, pos, face, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK); - } - public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(Player player, BlockPos pos, Direction face, ServerboundPlayerActionPacket.Action action) { PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face, PlayerInteractEvent.LeftClickBlock.Action.convert(action)); NeoForge.EVENT_BUS.post(evt); @@ -886,24 +875,35 @@ public interface BiomeCallbackFunction { Biome apply(final Biome.ClimateSettings climate, final BiomeSpecialEffects effects, final BiomeGenerationSettings gen, final MobSpawnSettings spawns); } - public static boolean onCropsGrowPre(Level level, BlockPos pos, BlockState state, boolean def) { - BlockEvent ev = new BlockEvent.CropGrowEvent.Pre(level, pos, state); + /** + * Checks if a crop can grow by firing {@link CropGrowEvent.Pre}. + * + * @param level The level the crop is in + * @param pos The position of the crop + * @param state The state of the crop + * @param def The result of the default checks performed by the crop. + * @return true if the crop can grow + */ + public static boolean canCropGrow(Level level, BlockPos pos, BlockState state, boolean def) { + var ev = new CropGrowEvent.Pre(level, pos, state); NeoForge.EVENT_BUS.post(ev); - return (ev.getResult() == net.neoforged.bus.api.Event.Result.ALLOW || (ev.getResult() == net.neoforged.bus.api.Event.Result.DEFAULT && def)); + return (ev.getResult() == CropGrowEvent.Pre.Result.GROW || (ev.getResult() == CropGrowEvent.Pre.Result.DEFAULT && def)); } - public static void onCropsGrowPost(Level level, BlockPos pos, BlockState state) { - NeoForge.EVENT_BUS.post(new BlockEvent.CropGrowEvent.Post(level, pos, state, level.getBlockState(pos))); + public static void fireCropGrowPost(Level level, BlockPos pos, BlockState state) { + NeoForge.EVENT_BUS.post(new CropGrowEvent.Post(level, pos, state, level.getBlockState(pos))); } - @Nullable - public static CriticalHitEvent getCriticalHit(Player player, Entity target, boolean vanillaCritical, float damageModifier) { - CriticalHitEvent hitResult = new CriticalHitEvent(player, target, damageModifier, vanillaCritical); - NeoForge.EVENT_BUS.post(hitResult); - if (hitResult.getResult() == net.neoforged.bus.api.Event.Result.ALLOW || (vanillaCritical && hitResult.getResult() == net.neoforged.bus.api.Event.Result.DEFAULT)) { - return hitResult; - } - return null; + /** + * Fires the {@link CriticalHitEvent} and returns the resulting event. + * + * @param player The attacking player + * @param target The attack target + * @param vanillaCritical If the attack would have been a critical hit by vanilla's rules in {@link Player#attack(Entity)}. + * @param damageModifier The base damage modifier. Vanilla critical hits have a damage modifier of 1.5. + */ + public static CriticalHitEvent fireCriticalHit(Player player, Entity target, boolean vanillaCritical, float damageModifier) { + return NeoForge.EVENT_BUS.post(new CriticalHitEvent(player, target, damageModifier, vanillaCritical)); } /** @@ -975,9 +975,6 @@ public static int onNoteChange(Level level, BlockPos pos, BlockState state, int return event.getVanillaNoteId(); } - @Deprecated(forRemoval = true, since = "1.20.1") // Tags use a codec now This was never used in 1.20 - public static void deserializeTagAdditions(List list, JsonObject json, List allList) {} - public static final int VANILLA_SERIALIZER_LIMIT = 256; @Nullable @@ -1004,17 +1001,7 @@ public static boolean canEntityDestroy(Level level, BlockPos pos, LivingEntity e if (!level.isLoaded(pos)) return false; BlockState state = level.getBlockState(pos); - return EventHooks.getMobGriefingEvent(level, entity) && state.canEntityDestroy(level, pos, entity) && EventHooks.onEntityDestroyBlock(entity, pos, state); - } - - /** - * Gets the burn time of this item stack. - * - * @deprecated Use {@link IItemStackExtension#getBurnTime(RecipeType)} instead. - */ - @Deprecated(forRemoval = true, since = "1.20.5") - public static int getBurnTime(ItemStack stack, @Nullable RecipeType recipeType) { - return stack.getBurnTime(recipeType); + return EventHooks.canEntityGrief(level, entity) && state.canEntityDestroy(level, pos, entity) && EventHooks.onEntityDestroyBlock(entity, pos, state); } /** @@ -1057,7 +1044,7 @@ public static ObjectArrayList modifyLoot(ResourceLocation lootTableId } public static List getModDataPacks() { - List modpacks = ResourcePackLoader.getDataPackNames(); + List modpacks = ResourcePackLoader.getPackNames(PackType.SERVER_DATA); if (modpacks.isEmpty()) throw new IllegalStateException("Attempted to retrieve mod packs before they were loaded in!"); return modpacks; @@ -1130,7 +1117,7 @@ public static void writeAdditionalLevelSaveData(WorldData worldData, CompoundTag ModList.get().getMods().forEach(mi -> { final CompoundTag mod = new CompoundTag(); mod.putString("ModId", mi.getModId()); - mod.putString("ModVersion", MavenVersionStringHelper.artifactVersionToString(mi.getVersion())); + mod.putString("ModVersion", MavenVersionTranslator.artifactVersionToString(mi.getVersion())); modList.add(mod); }); fmlData.put("LoadingModList", modList); @@ -1147,7 +1134,7 @@ public static void writeAdditionalLevelSaveData(WorldData worldData, CompoundTag public static void readAdditionalLevelSaveData(CompoundTag rootTag, LevelStorageSource.LevelDirectory levelDirectory) { CompoundTag tag = rootTag.getCompound("fml"); if (tag.contains("LoadingModList")) { - ListTag modList = tag.getList("LoadingModList", net.minecraft.nbt.Tag.TAG_COMPOUND); + ListTag modList = tag.getList("LoadingModList", Tag.TAG_COMPOUND); Map mismatchedVersions = new HashMap<>(modList.size()); Map missingVersions = new HashMap<>(modList.size()); for (int i = 0; i < modList.size(); i++) { @@ -1248,7 +1235,7 @@ public static MobEffect loadMobEffect(CompoundTag nbt, String key, @Nullable Mob return fallback; } try { - return BuiltInRegistries.MOB_EFFECT.get(new ResourceLocation(registryName)); + return BuiltInRegistries.MOB_EFFECT.get(ResourceLocation.parse(registryName)); } catch (ResourceLocationException e) { return fallback; } @@ -1258,7 +1245,7 @@ public static boolean shouldSuppressEnderManAnger(EnderMan enderMan, Player play return mask.isEnderMask(player, enderMan) || NeoForge.EVENT_BUS.post(new EnderManAngerEvent(enderMan, player)).isCanceled(); } - private static final Lazy> FORGE_CONVERSION_MAP = Lazy.concurrentOf(() -> { + private static final Lazy> FORGE_CONVERSION_MAP = Lazy.of(() -> { Map map = new HashMap<>(); NeoForge.EVENT_BUS.post(new RegisterStructureConversionsEvent(map)); return ImmutableMap.copyOf(map); @@ -1407,11 +1394,12 @@ public static void markComponentClassAsValid(Class clazz) { static { // Mark common singletons as valid - markComponentClassAsValid(Block.class); markComponentClassAsValid(BlockState.class); - markComponentClassAsValid(Fluid.class); markComponentClassAsValid(FluidState.class); - markComponentClassAsValid(Item.class); + // Block, Fluid, Item, etc. are handled via the registry check further down + + // Mark common interned classes as valid + markComponentClassAsValid(ResourceKey.class); } /** @@ -1432,12 +1420,30 @@ public static void validateComponent(@Nullable Object dataComponent) { if (overridesEqualsAndHashCode(clazz)) { checkedComponentClasses.add(clazz); - } else { - throw new IllegalArgumentException("Data components must implement equals and hashCode. Keep in mind they must also be immutable. Problematic class: " + clazz); + return; } + + // By far the slowest check: Is this a registry object? + // If it is, we assume it must be usable as a singleton... + if (isPotentialRegistryObject(dataComponent)) { + checkedComponentClasses.add(clazz); + return; + } + + throw new IllegalArgumentException("Data components must implement equals and hashCode. Keep in mind they must also be immutable. Problematic class: " + clazz); } } + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static boolean isPotentialRegistryObject(Object value) { + for (Registry registry : BuiltInRegistries.REGISTRY) { + if (registry.containsValue(value)) { + return true; + } + } + return false; + } + private static boolean overridesEqualsAndHashCode(Class clazz) { try { Method equals = clazz.getMethod("equals", Object.class); @@ -1447,4 +1453,55 @@ private static boolean overridesEqualsAndHashCode(Class clazz) { throw new RuntimeException("Failed to check for component equals and hashCode", exception); } } + + + /** + * The goal here is to fix the POI memory leak that happens due to + * {@link net.minecraft.world.level.chunk.storage.SectionStorage#storage} field never + * actually removing POIs long after they become irrelevant. We do it here in chunk unload event + * so that chunk that are fully unloaded now gets the POI removed from the POI cached storage map. + */ + public static void onChunkUnload(PoiManager poiManager, ChunkAccess chunkAccess) { + ChunkPos chunkPos = chunkAccess.getPos(); + poiManager.flush(chunkPos); // Make sure all POI in chunk are saved to disk first. + + // Remove the cached POIs for this chunk's location. + int SectionPosMinY = SectionPos.blockToSectionCoord(chunkAccess.getMinBuildHeight()); + for (int currentSectionY = 0; currentSectionY < chunkAccess.getSectionsCount(); currentSectionY++) { + long sectionPosKey = SectionPos.asLong(chunkPos.x, SectionPosMinY + currentSectionY, chunkPos.z); + poiManager.remove(sectionPosKey); + } + } + + /** + * Checks if a mob effect can be applied to an entity by firing {@link MobEffectEvent.Applicable}. + * + * @param entity The target entity the mob effect is being applied to. + * @param effect The mob effect being applied. + * @return True if the mob effect can be applied, otherwise false. + */ + public static boolean canMobEffectBeApplied(LivingEntity entity, MobEffectInstance effect) { + var event = new MobEffectEvent.Applicable(entity, effect); + return NeoForge.EVENT_BUS.post(event).getApplicationResult(); + } + + /** + * Attempts to resolve a {@link RegistryLookup} using the current global state. + *

        + * Prioritizes the server's lookup, only attempting to retrieve it from the client if the server is unavailable. + * + * @param The type of registry being looked up + * @param key The resource key for the target registry + * @return A registry access, if one was available. + */ + @Nullable + public static HolderLookup.RegistryLookup resolveLookup(ResourceKey> key) { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + return server.registryAccess().lookup(key).orElse(null); + } else if (FMLEnvironment.dist.isClient()) { + return ClientHooks.resolveLookup(key); + } + return null; + } } From 6fe17c2599ae46323be007ab04f051f77b63fa3d Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 13 Jun 2024 19:04:06 -0400 Subject: [PATCH 33/41] final rebase fixes --- .../debug/entity/EntityEventTests.java | 2 +- .../debug/entity/player/PlayerEventTests.java | 23 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java index ee250849d5..08aa008162 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java @@ -110,7 +110,7 @@ static void entityVerticalExplosionKnockbackEvent(final DynamicTest test) { test.onGameTest(helper -> helper.startSequence(() -> helper.spawnWithNoFreeWill(EntityType.PIG, 8, 3, 7)) .thenExecute(pig -> helper.setBlock(8, 2, 7, Blocks.ACACIA_LEAVES)) - .thenExecute(pig -> helper.getLevel().explode(null, helper.getLevel().damageSources().generic(), null, helper.absolutePos(new BlockPos(7, 2, 7)).getCenter(), 2f, false, Level.ExplosionInteraction.BLOW)) + .thenExecute(pig -> helper.getLevel().explode(null, helper.getLevel().damageSources().generic(), null, helper.absolutePos(new BlockPos(7, 2, 7)).getCenter(), 2f, false, Level.ExplosionInteraction.TNT)) .thenExecute(pig -> helper.assertEntityProperty(pig, p -> pig.getDeltaMovement().x() == 0 && pig.getDeltaMovement().y() != 0 && pig.getDeltaMovement().z() == 0, "Check explosion Knockback")) .thenIdle(10) .thenExecute(helper::killAllEntities) diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java index 786c8527a8..a0b17ec16c 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java @@ -20,6 +20,7 @@ import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.Mob; @@ -32,9 +33,11 @@ import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.portal.DimensionTransition; import net.neoforged.bus.api.EventPriority; import net.neoforged.neoforge.event.StatAwardEvent; import net.neoforged.neoforge.event.entity.living.ArmorHurtEvent; +import net.neoforged.neoforge.event.entity.player.ItemEntityPickupEvent; import net.neoforged.neoforge.event.entity.player.PermissionsChangedEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; @@ -129,11 +132,11 @@ static void entityInteractEvent(final DynamicTest test) { @EmptyTemplate(floor = true) @TestHolder(description = "Tests if the ItemPickupEvent fires") public static void itemPickupEvent(final DynamicTest test) { - test.eventListeners().forge().addListener((final PlayerEvent.ItemPickupEvent event) -> { - if (event.getStack().is(Items.MELON_SEEDS)) { + test.eventListeners().forge().addListener((ItemEntityPickupEvent.Post event) -> { + if (event.getOriginalStack().is(Items.MELON_SEEDS)) { // If the event is fired and detects pickup of melon seeds, the test will be considered pass // and the player will get pumpkin seeds too - event.getEntity().addItem(new ItemStack(Items.PUMPKIN_SEEDS)); + event.getPlayer().addItem(new ItemStack(Items.PUMPKIN_SEEDS)); test.pass(); } }); @@ -267,13 +270,21 @@ static void playerRespawnPositionEvent(final DynamicTest test, final Registratio return; } - event.setRespawnPosition(event.getEntity().position().relative(Direction.SOUTH, 1)); + var oldTransition = event.getDimensionTransition(); + var newTransition = new DimensionTransition(oldTransition.newLevel(), + event.getEntity().position().relative(Direction.SOUTH, 1), + oldTransition.speed(), + oldTransition.xRot(), + oldTransition.yRot(), + oldTransition.missingRespawnBlock(), + oldTransition.postDimensionTransition()); + event.setDimensionTransition(newTransition); }); test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) .thenExecute(player -> player.setCustomName(Component.literal("respawn-position-test"))) .thenExecute(player -> player.setRespawnPosition(player.getRespawnDimension(), helper.absolutePos(new BlockPos(0, 1, 0)), 0, false, true)) - .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false)) + .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false, Entity.RemovalReason.KILLED)) .thenExecute(() -> helper.assertEntityPresent(EntityType.PLAYER, new BlockPos(0, 1, 1))) .thenSucceed()); } @@ -288,7 +299,7 @@ static void playerRespawnEvent(final DynamicTest test, final RegistrationHelper test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) .thenExecute(player -> player.setRespawnPosition(player.getRespawnDimension(), helper.absolutePos(new BlockPos(0, 1, 1)), 0, true, true)) - .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false)) + .thenExecute(player -> Objects.requireNonNull(player.getServer()).getPlayerList().respawn(player, false, Entity.RemovalReason.KILLED)) .thenExecute(() -> helper.assertEntityIsHolding(new BlockPos(0, 1, 1), EntityType.PLAYER, Items.APPLE)) .thenSucceed()); } From 0d257a9d7a5884569ea87404043d7a6a5a2b398a Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Thu, 13 Jun 2024 19:11:56 -0400 Subject: [PATCH 34/41] spotless cleanup --- src/main/java/net/neoforged/neoforge/common/CommonHooks.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 57d2cb277f..4f6e8581ec 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -596,10 +596,6 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) { Item item = itemstack.getItem(); int size = itemstack.getCount(); DataComponentMap components = itemstack.getComponents(); - // Porting 1.20.5 redo this for components? - //CompoundTag nbt = null; - //if (itemstack.getTag() != null) - // nbt = itemstack.getTag().copy(); if (!(itemstack.getItem() instanceof BucketItem)) // if not bucket level.captureBlockSnapshots = true; @@ -1454,7 +1450,6 @@ private static boolean overridesEqualsAndHashCode(Class clazz) { } } - /** * The goal here is to fix the POI memory leak that happens due to * {@link net.minecraft.world.level.chunk.storage.SectionStorage#storage} field never From 1a2bb13b78280e85cec4039227f25faaa136f7a4 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sat, 15 Jun 2024 11:54:05 -0400 Subject: [PATCH 35/41] addressing review - remove DamageSequenceEvent and refactor events to extend LivingEvent only with DamageContainers as applicable - flatten DamageContainer to one class instance --- .../minecraft/world/entity/Entity.java.patch | 9 +- .../world/entity/LivingEntity.java.patch | 6 +- .../neoforge/common/CommonHooks.java | 22 +-- .../common/damagesource/DamageContainer.java | 168 ++++++++++-------- .../damagesource/IReductionFunction.java | 24 +++ .../damagesource/InternalDamageContainer.java | 105 ----------- .../entity/living/DamageSequenceEvent.java | 51 ------ .../entity/living/LivingDamageEvent.java | 100 +++++++++-- .../living/LivingIncomingDamageEvent.java | 17 +- .../entity/living/LivingShieldBlockEvent.java | 12 +- .../neoforge/debug/data/DataMapTests.java | 2 +- 11 files changed, 239 insertions(+), 277 deletions(-) create mode 100644 src/main/java/net/neoforged/neoforge/common/damagesource/IReductionFunction.java delete mode 100644 src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java delete mode 100644 src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java diff --git a/patches/net/minecraft/world/entity/Entity.java.patch b/patches/net/minecraft/world/entity/Entity.java.patch index 6621363756..1fefa3fa93 100644 --- a/patches/net/minecraft/world/entity/Entity.java.patch +++ b/patches/net/minecraft/world/entity/Entity.java.patch @@ -297,13 +297,10 @@ public boolean isInvulnerableTo(DamageSource p_20122_) { - return this.isRemoved() -- || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() -- || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() -- || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); + boolean isVanillaInvulnerable = this.isRemoved() -+ || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() -+ || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() -+ || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); + || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() + || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() + || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); + return net.neoforged.neoforge.common.CommonHooks.onEntityInvulnerablityCheck(this, p_20122_, isVanillaInvulnerable); } diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index 0214284cb0..f58b0f2e16 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -20,7 +20,7 @@ + * the stack before the method's return. + **/ + @Nullable -+ protected java.util.Stack damageContainers = new java.util.Stack<>(); ++ protected java.util.Stack damageContainers = new java.util.Stack<>(); protected LivingEntity(EntityType p_20966_, Level p_20967_) { super(p_20966_, p_20967_); @@ -171,8 +171,8 @@ } else if (p_21016_.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { -+ this.damageContainers.push(new net.neoforged.neoforge.common.damagesource.InternalDamageContainer(p_21016_, p_21017_)); -+ if (!net.neoforged.neoforge.common.CommonHooks.onEntityIncomingDamage(this, this.damageContainers.peek())) return false; ++ this.damageContainers.push(new net.neoforged.neoforge.common.damagesource.DamageContainer(p_21016_, p_21017_)); ++ if (net.neoforged.neoforge.common.CommonHooks.onEntityIncomingDamage(this, this.damageContainers.peek())) return false; if (this.isSleeping() && !this.level().isClientSide) { this.stopSleeping(); } diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 4f6e8581ec..64798c9f60 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -265,23 +265,7 @@ public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource so * @return if the event is cancelled and no damage will be applied to the entity */ public static boolean onEntityIncomingDamage(LivingEntity entity, DamageContainer container) { - return entity instanceof Player || !NeoForge.EVENT_BUS.post(new LivingIncomingDamageEvent(entity, container)).isCanceled(); - } - - /** - * Called after invulnerability checks in {@link Player#hurt(DamageSource, float)}, - * {@link net.minecraft.client.player.LocalPlayer#hurt(DamageSource, float)}, and - * {@link net.minecraft.client.player.RemotePlayer#hurt(DamageSource, float)}, - * this method creates and posts the first event in the LivingEntity damage sequence, - * {@link LivingIncomingDamageEvent}, for player entities. - * - * @param entity the player to receive damage - * @param container the newly instantiated container for damage to be dealt. Most properties of - * the container will be empty at this stage. - * @return if the event is cancelled and no damage will be applied to the entity - */ - public static boolean onPlayerIncomingDamage(LivingEntity entity, DamageContainer container) { - return !NeoForge.EVENT_BUS.post(new LivingIncomingDamageEvent(entity, container)).isCanceled(); + return NeoForge.EVENT_BUS.post(new LivingIncomingDamageEvent(entity, container)).isCanceled(); } public static LivingKnockBackEvent onLivingKnockBack(LivingEntity target, float strength, double ratioX, double ratioZ) { @@ -306,7 +290,7 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS * */ public static float onLivingDamagePre(LivingEntity entity, DamageContainer container) { - return NeoForge.EVENT_BUS.post(new LivingDamageEvent.Pre(entity, container)).getDamageContainer().getNewDamage(); + return NeoForge.EVENT_BUS.post(new LivingDamageEvent.Pre(entity, container)).getContainer().getNewDamage(); } /** @@ -319,7 +303,7 @@ public static float onLivingDamagePre(LivingEntity entity, DamageContainer conta * instance is immutable. */ public static void onLivingDamagePost(LivingEntity entity, DamageContainer container) { - NeoForge.EVENT_BUS.post(new LivingDamageEvent.Post(entity, new DamageContainer.ResultDamageContainer(container))); + NeoForge.EVENT_BUS.post(new LivingDamageEvent.Post(entity, container)); } /** diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index 91ac854153..e1cca9e24c 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -5,41 +5,38 @@ package net.neoforged.neoforge.common.damagesource; -import java.util.AbstractMap; -import java.util.Arrays; +import java.util.ArrayList; import java.util.EnumMap; -import java.util.function.BiFunction; -import java.util.stream.Collectors; +import java.util.List; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import net.neoforged.neoforge.event.entity.EntityInvulnerabilityCheckEvent; import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; +import org.jetbrains.annotations.ApiStatus; /** * DamageContainer encapsulates aspects of the entity damage sequence so that * relevant context related to damage dealt is accessible throughout the entire * sequence. *

        Note: certain values will be defaults until the stage in the sequence when they are set.

        - *

        Damage Sequence and uses

          - *
        1. Entity is hurt by a damage source
        2. - *
        3. {@link EntityInvulnerabilityCheckEvent EntityInvulnerablityCheckEvent} - * fires and determines if the sequence can commence
        4. - *
        5. {@link LivingIncomingDamageEvent EntityPreDamageEvent} fires - * and gives access to this. Modifiers should be added here.
        6. - *
        7. {@link LivingShieldBlockEvent} fires
        8. - *
        9. armor, enchantments, mob effect, and absorption modifiers are applied to the damage
        10. - *
        11. {@link LivingDamageEvent.Pre IncomingDamageEvent} fires and - * provides final values for the preceding modifiers and the last chance to negate the damage but will not - * undo the preceding effects
        12. - *
        13. {@link LivingDamageEvent.Post DamageTakenEvent} fires and provides - * an immutable perspective of what the entire sequence ended with.
        14. + *

          The Damage Sequence

          + *
            + *
          1. {@link LivingEntity#hurt} is invoked on the recipient from the source of + * the attack.
          2. + *
          3. {@link Entity#isInvulnerableTo} is invoked and fires {@link EntityInvulnerabilityCheckEvent}
          4. + *
          5. After determining the entity is vulnerable, the {@link DamageContainer} in instantiated for the entity
          6. + *
          7. {@link LivingIncomingDamageEvent} is fired
          8. + *
          9. {@link LivingShieldBlockEvent} fires and the result determines if shield effects apply
          10. + *
          11. {@link LivingEntity#actuallyHurt} is called.
          12. + *
          13. armor, magic, mob_effect, and absorption reductions are captured in the DamageContainer
          14. + *
          15. {@link LivingDamageEvent.Pre} is fired
          16. + *
          17. if the damage is not zero, entity health is modified and recorded and {@link LivingDamageEvent.Post} is fired
          18. *
          - * - * */ -public interface DamageContainer { +@ApiStatus.Internal +public class DamageContainer { public enum Reduction { /** Damage reduced from the effects of armor */ ARMOR, @@ -51,66 +48,100 @@ public enum Reduction { ABSORPTION } + private final EnumMap> reductionFunctions = new EnumMap<>(Reduction.class); + private final float originalDamage; + private final DamageSource source; + private float newDamage; + private final EnumMap reductions = new EnumMap<>(Reduction.class); + private float blockedDamage = 0f; + private float shieldDamage = 0; + private int invulnerabilityTicksAfterAttack = 20; + + public DamageContainer(DamageSource source, float originalDamage) { + this.source = source; + this.originalDamage = originalDamage; + this.newDamage = originalDamage; + } + /** * @return the value passed into {@link LivingEntity#hurt(DamageSource, float)} before * any modifications are made. */ - float getOriginalDamage(); + public float getOriginalDamage() { + return originalDamage; + } /** - * @return the current amount expected to be applied to the entity or used in subsequent damage calculations. + * @return The damage source for this damage sequence */ - float getNewDamage(); + public DamageSource getSource() { + return source; + } /** - * @return The damage source for this damage sequence + * This sets the current damage value for the entity at the stage of the damage sequence in which it is set. + * Subsequent steps in the damage sequence will use and modify this value accordingly. If this is called in + * the final step of the sequence, this value will be applied against the entity's health. + * + * @param damage the amount to harm this entity at the end of the damage sequence */ - DamageSource getSource(); + public void setNewDamage(float damage) { + this.newDamage = damage; + } + + /** + * @return the current amount expected to be applied to the entity or used in subsequent damage calculations. + */ + public float getNewDamage() { + return newDamage; + } /** * Adds a callback modifier to the vanilla damage reductions. Each function will be performed in sequence - * on the vanilla value at the time the {@link Reduction} type is set by vanilla. + * on the vanilla value at the time the {@link DamageContainer.Reduction} type is set by vanilla. *

          Note: only the {@link LivingIncomingDamageEvent EntityPreDamageEvent} * happens early enough in the sequence for this method to have any effect.

          * - * @param type The reduction type your function will apply to - * @param operation takes the current reduction from vanilla and any preceding functions and returns a new - * value for the reduction. These are always executed in insertion order. if sequence - * matters, use {@link net.neoforged.bus.api.EventPriority} to order your function. + * @param type The reduction type your function will apply to + * @param reductionFunction takes the current reduction from vanilla and any preceding functions and returns a new + * value for the reduction. These are always executed in insertion order. if sequence + * matters, use {@link net.neoforged.bus.api.EventPriority} to order your function. */ - void addModifier(Reduction type, BiFunction operation); - /** - * This sets the current damage value for the entity at the stage of the damage sequence in which it is set. - * Subsequent steps in the damage sequence will use and modify this value accordingly. If this is called in - * the final step of the sequence, this value will be applied against the entity's health. - * - * @param damage the amount to harm this entity at the end of the damage sequence - */ - void setNewDamage(float damage); + public void addModifier(Reduction type, IReductionFunction reductionFunction) { + this.reductionFunctions.computeIfAbsent(type, a -> new ArrayList<>()).add(reductionFunction); + } /** * @return The damage blocked during the {@link LivingShieldBlockEvent} */ - float getBlockedDamage(); + public float getBlockedDamage() { + return blockedDamage; + } /** * @return The durability applied to the applicable shield after {@link LivingShieldBlockEvent} * returned a successful block */ - float getShieldDamage(); + public float getShieldDamage() { + return shieldDamage; + } /** * Explicitly sets the invulnerability ticks after the damage has been applied. * * @param ticks Ticks of invulnerability after this damage sequence */ - void setPostAttackInvulnerabilityTicks(int ticks); + public void setPostAttackInvulnerabilityTicks(int ticks) { + this.invulnerabilityTicksAfterAttack = ticks; + } /** * @return The number of ticks this entity will be invulnerable after damage is applied. */ - int getPostAttackInvulnerabilityTicks(); + public int getPostAttackInvulnerabilityTicks() { + return invulnerabilityTicksAfterAttack; + } /** * This provides a post-reduction value for the reduction and modifiers. This will always return zero @@ -120,42 +151,31 @@ public enum Reduction { * @param type the specific source type of the damage reduction * @return The amount of damage reduced by armor after vanilla armor reductions and added modifiers */ - float getReduction(Reduction type); - - public record ResultDamageContainer( - float getOriginalDamage, - DamageSource getSource, - float getNewDamage, - float getBlockedDamage, - float getShieldDamage, - int getPostAttackInvulnerabilityTicks, - EnumMap reduction - - ) implements DamageContainer { - public ResultDamageContainer(DamageContainer container) { - this(container.getOriginalDamage(), container.getSource(), container.getNewDamage(), - container.getBlockedDamage(), container.getShieldDamage(), container.getPostAttackInvulnerabilityTicks(), - new EnumMap(Arrays.stream(Reduction.values()) - .map(type -> new AbstractMap.SimpleEntry<>(type, container.getReduction(type))) - .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)))); - } + public float getReduction(Reduction type) { + return reductions.getOrDefault(type, 0f); + } - @Override - public void addModifier(Reduction type, BiFunction function) {} + //=============INTERNAL METHODS - DO NOT USE=================== - @Override - public void setNewDamage(float damage) { - throw new IllegalStateException("Attempted to modify damage in an immutable context"); + @ApiStatus.Internal + public void setBlockedDamage(LivingShieldBlockEvent event) { + if (event.getBlocked()) { + this.blockedDamage = event.getBlockedDamage(); + this.shieldDamage = event.shieldDamage(); + this.newDamage -= this.blockedDamage; } + } - @Override - public void setPostAttackInvulnerabilityTicks(int ticks) { - throw new IllegalStateException("Attempted to modify invulnerability ticks in an immutable context"); - } + @ApiStatus.Internal + public void setReduction(Reduction reduction, float amount) { + this.reductions.put(reduction, modifyReduction(Reduction.ABSORPTION, amount)); + this.newDamage -= Math.max(0, amount); + } - @Override - public float getReduction(Reduction type) { - return reduction().getOrDefault(type, 0f); + private float modifyReduction(Reduction type, float reduction) { + for (var func : reductionFunctions.getOrDefault(type, new ArrayList<>())) { + reduction = func.modify(this, reduction); } + return reduction; } } diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/IReductionFunction.java b/src/main/java/net/neoforged/neoforge/common/damagesource/IReductionFunction.java new file mode 100644 index 0000000000..03e16f18a9 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/IReductionFunction.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.common.damagesource; + +/** + * An {@link IReductionFunction} is used by {@link DamageContainer} instances.
          + * This allows sequential modification of damage reduction values to be stored and + * later invoked before actual reductions are applied to the damage sequence. + */ +@FunctionalInterface +public interface IReductionFunction { + /** + * Consumes an existing reduction value and produces a modified value. + * + * @param container the {@link DamageContainer} representing the damage sequence + * values for the reduction being modified + * @param reductionIn the initial or preceding reduction value to this operation + * @return the new reduction value + */ + float modify(DamageContainer container, float reductionIn); +} diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java deleted file mode 100644 index 6156062459..0000000000 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/InternalDamageContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) NeoForged and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.common.damagesource; - -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.function.BiFunction; -import net.minecraft.world.damagesource.DamageSource; -import net.neoforged.neoforge.event.entity.living.LivingShieldBlockEvent; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public class InternalDamageContainer implements DamageContainer { - private final EnumMap>> reductionMap = new EnumMap<>(Reduction.class); - private final float originalDamage; - private final DamageSource source; - private float newDamage; - EnumMap reductions = new EnumMap<>(Reduction.class); - private float blockedDamage = 0f; - private float shieldDamage = 0; - private int invulnerabilityTicksAfterAttack = 20; - - public InternalDamageContainer(DamageSource source, float originalDamage) { - this.source = source; - this.originalDamage = originalDamage; - this.newDamage = originalDamage; - } - - @Override - public float getOriginalDamage() { - return originalDamage; - } - - @Override - public DamageSource getSource() { - return source; - } - - @Override - public void setNewDamage(float damage) { - this.newDamage = damage; - } - - @Override - public float getNewDamage() { - return newDamage; - } - - public void addModifier(Reduction type, BiFunction operation) { - this.reductionMap.computeIfAbsent(type, a -> new ArrayList<>()).add(operation); - } - - @Override - public float getBlockedDamage() { - return blockedDamage; - } - - @Override - public float getShieldDamage() { - return shieldDamage; - } - - @Override - public void setPostAttackInvulnerabilityTicks(int ticks) { - this.invulnerabilityTicksAfterAttack = ticks; - } - - @Override - public int getPostAttackInvulnerabilityTicks() { - return invulnerabilityTicksAfterAttack; - } - - @Override - public float getReduction(Reduction type) { - return reductions.getOrDefault(type, 0f); - } - - //=============INTERNAL METHODS - DO NOT USE=================== - - @ApiStatus.Internal - public void setBlockedDamage(LivingShieldBlockEvent event) { - if (event.getBlocked()) { - this.blockedDamage = event.getBlockedDamage(); - this.shieldDamage = event.shieldDamage(); - this.newDamage -= this.blockedDamage; - } - } - - @ApiStatus.Internal - public void setReduction(Reduction reduction, float amount) { - this.reductions.put(reduction, modifyReduction(Reduction.ABSORPTION, amount)); - this.newDamage -= Math.max(0, amount); - } - - private float modifyReduction(Reduction type, float reduction) { - for (var func : reductionMap.getOrDefault(type, new ArrayList<>())) { - reduction = func.apply(this, reduction); - } - return reduction; - } -} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java deleted file mode 100644 index 6f8f02fa2a..0000000000 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/DamageSequenceEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) NeoForged and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.event.entity.living; - -import net.minecraft.world.entity.LivingEntity; -import net.neoforged.bus.api.ICancellableEvent; -import net.neoforged.neoforge.common.damagesource.DamageContainer; -import net.neoforged.neoforge.event.entity.EntityInvulnerabilityCheckEvent; - -/** - * DamageSequenceEvent provides a DamageContainer to its subclasses. Subscribe to - * the correct subclass of DamageSequenceEvent for your use case. - *
          - * The {@link DamageContainer container} can be accessed to modify or obtain values - * from the damage sequence. Note that depending on where in the damage sequence - * a child event is invoked, modification of a value may have no effect. Read the - * documentation on the child event of your listener for more detail. - *
          - * This event is not {@link ICancellableEvent} by default. Implementation classes - * can implement this interface if their corresponding hooks effectively terminate - * the damage sequence. - *
          - *

          The Damage Sequence

          - *
            - *
          1. {@link LivingEntity#hurt} is invoked on the recipient from the source of - * the attack.
          2. - *
          3. {@link Entity#isInvulnerableTo} is invoked and fires {@link EntityInvulnerabilityCheckEvent}
          4. - *
          5. After determining the entity is vulnerable, the {@link DamageContainer} in instantiated for the entity
          6. - *
          7. {@link LivingIncomingDamageEvent} is fired
          8. - *
          9. {@link LivingShieldBlockEvent} fires and the result determines if shield effects apply
          10. - *
          11. {@link LivingEntity#actuallyHurt} is called.
          12. - *
          13. armor, magic, mob_effect, and absorption reductions are captured in the DamageContainer
          14. - *
          15. {@link LivingDamageEvent.Pre} is fired
          16. - *
          17. if the damage is not zero, entity health is modified and recorded and {@link LivingDamageEvent.Post} is fired
          18. - *
          - */ -public abstract class DamageSequenceEvent extends LivingEvent { - final DamageContainer container; - - public DamageSequenceEvent(LivingEntity entity, DamageContainer container) { - super(entity); - this.container = container; - } - - public DamageContainer getDamageContainer() { - return container; - } -} diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java index e8bfa09271..ca81446c94 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java @@ -5,6 +5,11 @@ package net.neoforged.neoforge.event.entity.living; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.stream.Collectors; +import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import net.neoforged.neoforge.common.CommonHooks; import net.neoforged.neoforge.common.damagesource.DamageContainer; @@ -21,11 +26,11 @@ *
          * For more information on the damage sequence * - * @see DamageSequenceEvent + * @see DamageContainer */ -public abstract class LivingDamageEvent extends DamageSequenceEvent { - private LivingDamageEvent(LivingEntity entity, DamageContainer container) { - super(entity, container); +public abstract class LivingDamageEvent extends LivingEvent { + private LivingDamageEvent(LivingEntity entity) { + super(entity); } /** @@ -42,17 +47,24 @@ private LivingDamageEvent(LivingEntity entity, DamageContainer container) { *
          * For more information on the damage sequence * - * @see DamageSequenceEvent + * @see DamageContainer **/ public static class Pre extends LivingDamageEvent { - public Pre(LivingEntity entity, DamageContainer source) { - super(entity, source); + private final DamageContainer container; + + public Pre(LivingEntity entity, DamageContainer container) { + super(entity); + this.container = container; + } + + public DamageContainer getContainer() { + return container; } } /** * LivingDamageEvent.Post is fired after health is modified on the entity.
          - * the {@link DamageContainer} is immutable and represents a FINAL value of what was applied to the entity. + * The fields in this event represent the FINAL values of what was applied to the entity. *
          * Also note that appropriate resources (like armor durability and absorption extra hearts) have already been consumed.
          * This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)} @@ -61,11 +73,79 @@ public Pre(LivingEntity entity, DamageContainer source) { *
          * For more information on the damage sequence * - * @see DamageSequenceEvent + * @see DamageContainer **/ public static class Post extends LivingDamageEvent { + private final float originalDamage; + private final DamageSource source; + private final float newDamage; + private final float blockedDamage; + private final float shieldDamage; + private final int postAttackInvulnerabilityTicks; + private final EnumMap reductions; + public Post(LivingEntity entity, DamageContainer container) { - super(entity, container); + super(entity); + this.originalDamage = container.getOriginalDamage(); + this.source = container.getSource(); + this.newDamage = container.getNewDamage(); + this.blockedDamage = container.getBlockedDamage(); + this.shieldDamage = container.getShieldDamage(); + this.postAttackInvulnerabilityTicks = container.getPostAttackInvulnerabilityTicks(); + this.reductions = new EnumMap(Arrays.stream(DamageContainer.Reduction.values()) + .map(type -> new AbstractMap.SimpleEntry<>(type, container.getReduction(type))) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue))); + } + + /** + * @return the original damage when {@link LivingEntity#hurt} was invoked + */ + public float getOriginalDamage() { + return originalDamage; + } + + /** + * @return the {@link DamageSource} for this damage sequence + */ + public DamageSource getSource() { + return source; + } + + /** + * @return the amount of health this entity lost during this sequence + */ + public float getNewDamage() { + return newDamage; + } + + /** + * @return the amount of damage reduced by a blocking action + */ + public float getBlockedDamage() { + return blockedDamage; + } + + /** + * @return the amount of shield durability this entity lost if a blocking action was + * captured and the entity was holding a shield + */ + public float getShieldDamage() { + return shieldDamage; + } + + /** + * @return the number of ticks this entity will be invulnerable after this sequence + */ + public int getPostAttackInvulnerabilityTicks() { + return postAttackInvulnerabilityTicks; + } + + /** + * @param reduction the type of reduction to obtain + * @return the amount of damage reduced by this reduction type. + */ + public float getReduction(DamageContainer.Reduction reduction) { + return reductions.getOrDefault(reduction, 0f); } } } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java index c7e8135212..0625a5fb4b 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java @@ -5,12 +5,12 @@ package net.neoforged.neoforge.event.entity.living; -import java.util.function.BiFunction; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import net.neoforged.bus.api.ICancellableEvent; import net.neoforged.neoforge.common.CommonHooks; import net.neoforged.neoforge.common.damagesource.DamageContainer; +import net.neoforged.neoforge.common.damagesource.IReductionFunction; /** * LivingIncomingDamageEvent is fired when a LivingEntity is about to receive damage. @@ -25,11 +25,18 @@ *
          * For more information on the damage sequence * - * @see DamageSequenceEvent + * @see DamageContainer **/ -public class LivingIncomingDamageEvent extends DamageSequenceEvent implements ICancellableEvent { +public class LivingIncomingDamageEvent extends LivingEvent implements ICancellableEvent { + private final DamageContainer container; + public LivingIncomingDamageEvent(LivingEntity entity, DamageContainer container) { - super(entity, container); + super(entity); + this.container = container; + } + + public DamageContainer getContainer() { + return this.container; } public DamageSource getSource() { @@ -58,7 +65,7 @@ public void setAmount(float newDamage) { * @param type the reduction type to be modified * @param reductionFunc the function to apply to the reduction value. */ - public void addReductionModifier(DamageContainer.Reduction type, BiFunction reductionFunc) { + public void addReductionModifier(DamageContainer.Reduction type, IReductionFunction reductionFunc) { this.container.addModifier(type, reductionFunc); } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java index 750e2714ef..fba06256d6 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java @@ -22,22 +22,28 @@ * for players. * For more information on the damage sequence * - * @see DamageSequenceEvent + * @see DamageContainer */ -public class LivingShieldBlockEvent extends DamageSequenceEvent implements ICancellableEvent { +public class LivingShieldBlockEvent extends LivingEvent implements ICancellableEvent { + private final DamageContainer container; private float dmgBlocked; private float shieldDamage = -1; private final boolean originalBlocked; private boolean newBlocked; public LivingShieldBlockEvent(LivingEntity blocker, DamageContainer container, boolean originalBlockedState) { - super(blocker, container); + super(blocker); + this.container = container; this.dmgBlocked = container.getNewDamage(); this.originalBlocked = originalBlockedState; this.newBlocked = originalBlockedState; this.shieldDamage = container.getNewDamage(); } + public DamageContainer getDamageContainer() { + return this.container; + } + /** * @return The damage source. */ diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java index eb1e559dd3..cdcc11f3fa 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java @@ -277,7 +277,7 @@ protected void gather() { }); test.eventListeners().forge().addListener((final LivingDamageEvent.Post event) -> { - final ExperienceGrant grant = event.getDamageContainer().getSource().typeHolder().getData(xpGrant); + final ExperienceGrant grant = event.getSource().typeHolder().getData(xpGrant); if (grant != null && event.getEntity() instanceof Player player) { player.giveExperiencePoints(grant.amount()); } From b02da13880815b42986de29ef6cfc42df8b2850b Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:47:47 -0400 Subject: [PATCH 36/41] fix typo and clean javadocs --- .../net/neoforged/neoforge/common/CommonHooks.java | 13 +++++++------ .../entity/EntityInvulnerabilityCheckEvent.java | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 64798c9f60..695f70861c 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -43,6 +43,7 @@ import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; +import net.minecraft.core.HolderLookup.RegistryLookup; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; @@ -250,7 +251,7 @@ public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, * @param isInvul whether this entity is invulnerable according to preceding/vanilla logic * @return if this entity is invulnerable */ - public static boolean onEntityInvulnerablityCheck(Entity entity, DamageSource source, boolean isInvul) { + public static boolean onEntityInvulnerabilityCheck(Entity entity, DamageSource source, boolean isInvul) { return NeoForge.EVENT_BUS.post(new EntityInvulnerabilityCheckEvent(entity, source, isInvul)).isInvulnerable(); } @@ -299,8 +300,8 @@ public static float onLivingDamagePre(LivingEntity entity, DamageContainer conta * and requires access to the internal field {@link LivingEntity#damageContainers} as a parameter. * * @param entity the entity to receive damage - * @param container the container object holding the truly final values of the damage pipeline. This - * instance is immutable. + * @param container the container object holding the truly final values of the damage pipeline. The values + * of this container and used to instantiate final fields in the event. */ public static void onLivingDamagePost(LivingEntity entity, DamageContainer container) { NeoForge.EVENT_BUS.post(new LivingDamageEvent.Post(entity, container)); @@ -1069,8 +1070,8 @@ public static void onEntityEnterSection(Entity entity, long packedOldPos, long p /** * Creates, posts, and returns a {@link LivingShieldBlockEvent}. This method is invoked in - * {@link LivingEntity#hurt(DamageSource, float)} and requires internal access to the - * protected field {@link LivingEntity#damageContainers} as a parameter. + * {@link LivingEntity#hurt(DamageSource, float)} and requires internal access to the top entry + * in the protected field {@link LivingEntity#damageContainers} as a parameter. * * @param blocker the entity performing the block * @param container the entity's internal damage container for accessing current values @@ -1474,7 +1475,7 @@ public static boolean canMobEffectBeApplied(LivingEntity entity, MobEffectInstan * @return A registry access, if one was available. */ @Nullable - public static HolderLookup.RegistryLookup resolveLookup(ResourceKey> key) { + public static RegistryLookup resolveLookup(ResourceKey> key) { MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); if (server != null) { return server.registryAccess().lookup(key).orElse(null); diff --git a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java index 8d1b800fe3..7f93ef8920 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java @@ -10,7 +10,7 @@ import org.jetbrains.annotations.ApiStatus; /** - * Fired when {@link Entity#hurt(DamageSource, float)} is invoked and determines if + * Fired when {@link Entity#isInvulnerableTo(DamageSource)} is invoked and determines if * downstream hurt logic should apply. This event is fired on both sides in * {@link Entity#isInvulnerableTo(DamageSource)} *
          From c0012caff958115ade1f9230a37d84586aae7862 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:47:52 -0400 Subject: [PATCH 37/41] Fix refactor not applied to patch --- patches/net/minecraft/world/entity/Entity.java.patch | 2 +- .../neoforge/event/entity/EntityInvulnerabilityCheckEvent.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/net/minecraft/world/entity/Entity.java.patch b/patches/net/minecraft/world/entity/Entity.java.patch index 1fefa3fa93..28b4da1aac 100644 --- a/patches/net/minecraft/world/entity/Entity.java.patch +++ b/patches/net/minecraft/world/entity/Entity.java.patch @@ -301,7 +301,7 @@ || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); -+ return net.neoforged.neoforge.common.CommonHooks.onEntityInvulnerablityCheck(this, p_20122_, isVanillaInvulnerable); ++ return net.neoforged.neoforge.common.CommonHooks.onEntityInvulnerabilityCheck(this, p_20122_, isVanillaInvulnerable); } public boolean isInvulnerable() { diff --git a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java index 7f93ef8920..51889eb3a0 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/EntityInvulnerabilityCheckEvent.java @@ -10,7 +10,7 @@ import org.jetbrains.annotations.ApiStatus; /** - * Fired when {@link Entity#isInvulnerableTo(DamageSource)} is invoked and determines if + * Fired when {@link Entity#isInvulnerableTo(DamageSource)} is invoked and determines if * downstream hurt logic should apply. This event is fired on both sides in * {@link Entity#isInvulnerableTo(DamageSource)} *
          From 5917ebe42e47f510231f205c950bee2a78ac9e41 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Wed, 19 Jun 2024 07:34:27 -0400 Subject: [PATCH 38/41] additional code cleanup --- .../common/damagesource/DamageContainer.java | 48 +++++++------------ .../entity/living/LivingDamageEvent.java | 39 ++++----------- .../living/LivingIncomingDamageEvent.java | 10 ++-- .../entity/living/LivingShieldBlockEvent.java | 3 +- .../debug/entity/EntityEventTests.java | 8 +++- 5 files changed, 40 insertions(+), 68 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java index e1cca9e24c..5a912d1d87 100644 --- a/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java +++ b/src/main/java/net/neoforged/neoforge/common/damagesource/DamageContainer.java @@ -20,29 +20,29 @@ * DamageContainer encapsulates aspects of the entity damage sequence so that * relevant context related to damage dealt is accessible throughout the entire * sequence. - *

          Note: certain values will be defaults until the stage in the sequence when they are set.

          + *

          Note: certain values will be defaults until the stage in the sequence when they are set.

          *

          The Damage Sequence

          *
            *
          1. {@link LivingEntity#hurt} is invoked on the recipient from the source of * the attack.
          2. - *
          3. {@link Entity#isInvulnerableTo} is invoked and fires {@link EntityInvulnerabilityCheckEvent}
          4. - *
          5. After determining the entity is vulnerable, the {@link DamageContainer} in instantiated for the entity
          6. - *
          7. {@link LivingIncomingDamageEvent} is fired
          8. - *
          9. {@link LivingShieldBlockEvent} fires and the result determines if shield effects apply
          10. + *
          11. {@link Entity#isInvulnerableTo} is invoked and fires {@link EntityInvulnerabilityCheckEvent}.
          12. + *
          13. After determining the entity is vulnerable, the {@link DamageContainer} in instantiated for the entity.
          14. + *
          15. {@link LivingIncomingDamageEvent} is fired.
          16. + *
          17. {@link LivingShieldBlockEvent} fires and the result determines if shield effects apply.
          18. *
          19. {@link LivingEntity#actuallyHurt} is called.
          20. - *
          21. armor, magic, mob_effect, and absorption reductions are captured in the DamageContainer
          22. - *
          23. {@link LivingDamageEvent.Pre} is fired
          24. - *
          25. if the damage is not zero, entity health is modified and recorded and {@link LivingDamageEvent.Post} is fired
          26. + *
          27. armor, magic, mob_effect, and absorption reductions are captured in the DamageContainer.
          28. + *
          29. {@link LivingDamageEvent.Pre} is fired.
          30. + *
          31. if the damage is not zero, entity health is modified and recorded and {@link LivingDamageEvent.Post} is fired.
          32. *
          */ @ApiStatus.Internal public class DamageContainer { public enum Reduction { - /** Damage reduced from the effects of armor */ + /** Damage reduced from the effects of armor. */ ARMOR, - /** Damage reduced from enchantments on armor */ + /** Damage reduced from enchantments on armor. */ ENCHANTMENTS, - /** Damage reduced from active mob effects */ + /** Damage reduced from active mob effects. */ MOB_EFFECTS, /** Damage absorbed by absorption. */ ABSORPTION @@ -63,17 +63,12 @@ public DamageContainer(DamageSource source, float originalDamage) { this.newDamage = originalDamage; } - /** - * @return the value passed into {@link LivingEntity#hurt(DamageSource, float)} before - * any modifications are made. - */ + /** {@return the value passed into {@link LivingEntity#hurt(DamageSource, float)} before any modifications are made} */ public float getOriginalDamage() { return originalDamage; } - /** - * @return The damage source for this damage sequence - */ + /** {@return the damage source for this damage sequence} */ public DamageSource getSource() { return source; } @@ -89,9 +84,7 @@ public void setNewDamage(float damage) { this.newDamage = damage; } - /** - * @return the current amount expected to be applied to the entity or used in subsequent damage calculations. - */ + /** {@return the current amount expected to be applied to the entity or used in subsequent damage calculations} */ public float getNewDamage() { return newDamage; } @@ -112,17 +105,12 @@ public void addModifier(Reduction type, IReductionFunction reductionFunction) { this.reductionFunctions.computeIfAbsent(type, a -> new ArrayList<>()).add(reductionFunction); } - /** - * @return The damage blocked during the {@link LivingShieldBlockEvent} - */ + /** {@return the damage blocked during the {@link LivingShieldBlockEvent}} */ public float getBlockedDamage() { return blockedDamage; } - /** - * @return The durability applied to the applicable shield after {@link LivingShieldBlockEvent} - * returned a successful block - */ + /** {@return the durability applied to the applicable shield after {@link LivingShieldBlockEvent} returned a successful block} */ public float getShieldDamage() { return shieldDamage; } @@ -136,9 +124,7 @@ public void setPostAttackInvulnerabilityTicks(int ticks) { this.invulnerabilityTicksAfterAttack = ticks; } - /** - * @return The number of ticks this entity will be invulnerable after damage is applied. - */ + /** {@return the number of ticks this entity will be invulnerable after damage is applied} */ public int getPostAttackInvulnerabilityTicks() { return invulnerabilityTicksAfterAttack; } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java index ca81446c94..b406448858 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingDamageEvent.java @@ -23,10 +23,8 @@ *
          * {@link Post} contains an immutable representation of the entire damage sequence * and allows for reference to the values accrued at each step. - *
          - * For more information on the damage sequence * - * @see DamageContainer + * @see DamageContainer for more information on the damage sequence */ public abstract class LivingDamageEvent extends LivingEvent { private LivingDamageEvent(LivingEntity entity) { @@ -44,10 +42,8 @@ private LivingDamageEvent(LivingEntity entity) { * health has been applied. This event expects a mutable {@link DamageContainer}. *
          * This event is fired via the {@link CommonHooks#onLivingDamagePre(LivingEntity, DamageContainer)}. - *
          - * For more information on the damage sequence * - * @see DamageContainer + * @see DamageContainer for more information on the damage sequence **/ public static class Pre extends LivingDamageEvent { private final DamageContainer container; @@ -69,11 +65,9 @@ public DamageContainer getContainer() { * Also note that appropriate resources (like armor durability and absorption extra hearts) have already been consumed.
          * This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)} *
          - * This event is fired via {@link CommonHooks#onLivingDamagePost(LivingEntity, DamageContainer)}.
          - *
          - * For more information on the damage sequence + * This event is fired via {@link CommonHooks#onLivingDamagePost(LivingEntity, DamageContainer)}. * - * @see DamageContainer + * @see DamageContainer for more information on the damage sequence **/ public static class Post extends LivingDamageEvent { private final float originalDamage; @@ -97,45 +91,32 @@ public Post(LivingEntity entity, DamageContainer container) { .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue))); } - /** - * @return the original damage when {@link LivingEntity#hurt} was invoked - */ + /** {@return the original damage when {@link LivingEntity#hurt} was invoked} */ public float getOriginalDamage() { return originalDamage; } - /** - * @return the {@link DamageSource} for this damage sequence - */ + /** {@return the {@link DamageSource} for this damage sequence} */ public DamageSource getSource() { return source; } - /** - * @return the amount of health this entity lost during this sequence - */ + /** {@return the amount of health this entity lost during this sequence} */ public float getNewDamage() { return newDamage; } - /** - * @return the amount of damage reduced by a blocking action - */ + /** {@return the amount of damage reduced by a blocking action} */ public float getBlockedDamage() { return blockedDamage; } - /** - * @return the amount of shield durability this entity lost if a blocking action was - * captured and the entity was holding a shield - */ + /** {@return the amount of shield durability this entity lost if a blocking action was captured and the entity was holding a shield} */ public float getShieldDamage() { return shieldDamage; } - /** - * @return the number of ticks this entity will be invulnerable after this sequence - */ + /** {@return the number of ticks this entity will be invulnerable after this sequence} */ public int getPostAttackInvulnerabilityTicks() { return postAttackInvulnerabilityTicks; } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java index 0625a5fb4b..ae30de4bd4 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingIncomingDamageEvent.java @@ -21,11 +21,9 @@ * For custom posting of this event, the event expects to be fired before any * damage reductions have been calculated. This event expects a mutable {@link DamageContainer}. *
          - * This event is fired via the {@link CommonHooks#onEntityIncomingDamage(LivingEntity, DamageContainer)}.
          - *
          - * For more information on the damage sequence + * This event is fired via the {@link CommonHooks#onEntityIncomingDamage(LivingEntity, DamageContainer)}. * - * @see DamageContainer + * @see DamageContainer for more information on the damage sequence **/ public class LivingIncomingDamageEvent extends LivingEvent implements ICancellableEvent { private final DamageContainer container; @@ -35,18 +33,22 @@ public LivingIncomingDamageEvent(LivingEntity entity, DamageContainer container) this.container = container; } + /** {@return the container for this damage sequence} */ public DamageContainer getContainer() { return this.container; } + /** {@return the {@link DamageSource} for this damage sequence} */ public DamageSource getSource() { return this.container.getSource(); } + /** {@return the current damage to be applied to the entity} */ public float getAmount() { return this.container.getNewDamage(); } + /** {@return the damage value passed into the damage sequence before modifications} */ public float getOriginalAmount() { return this.container.getOriginalDamage(); } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java index fba06256d6..6207535891 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/living/LivingShieldBlockEvent.java @@ -20,9 +20,8 @@ * blocking logic is captured and passed into the event via {@link #getOriginalBlock()}. If this is * true, The shield item stack "should" be available from {@link LivingEntity#getUseItem()} at least * for players. - * For more information on the damage sequence * - * @see DamageContainer + * @see DamageContainer for more information on the damage sequence */ public class LivingShieldBlockEvent extends LivingEvent implements ICancellableEvent { private final DamageContainer container; diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java index 08aa008162..02b100e274 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java @@ -5,9 +5,11 @@ package net.neoforged.neoforge.debug.entity; +import java.util.Objects; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.GameTest; +import net.minecraft.network.chat.Component; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.EntityType; @@ -84,16 +86,18 @@ static void entityAttributeModificationEvent(final DynamicTest test, final Regis @EmptyTemplate @TestHolder(description = "Tests if EntityInvulnerabilityCheckEvent prevents damage when modified.") static void entityInvulnerabilityCheckEvent(final DynamicTest test, final RegistrationHelper reg) { + final Component NAME = Component.literal("invulnerable_entity"); test.eventListeners().forge().addListener((final EntityInvulnerabilityCheckEvent event) -> { - if (event.getEntity() instanceof GameTestPlayer entity) + if (event.getEntity() instanceof GameTestPlayer entity && entity.hasCustomName() && Objects.equals(entity.getCustomName(), NAME)) event.setInvulnerable(false); }); test.onGameTest(helper -> { DamageSource source = new DamageSource(helper.getLevel().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.MOB_ATTACK)); helper.startSequence(() -> helper.makeTickingMockServerPlayerInLevel(GameType.SURVIVAL)) + .thenExecute(player -> player.setCustomName(NAME)) .thenExecute(player -> player.setInvulnerable(true)) - .thenWaitUntil(player -> helper.assertTrue(!player.isInvulnerableTo(source), "Player Invulnerability not bypassed.")) + .thenWaitUntil(player -> helper.assertFalse(player.isInvulnerableTo(source), "Player Invulnerability not bypassed.")) .thenSucceed(); }); } From b3862911b7e5f4975158d2c0a064a0d72f97b54d Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sat, 22 Jun 2024 18:01:07 -0400 Subject: [PATCH 39/41] IDE friendly code replacement --- patches/net/minecraft/world/entity/LivingEntity.java.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index f58b0f2e16..e5fd781754 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -392,7 +392,7 @@ int i = (int)Math.max(1.0F, p_330394_ / 4.0F); + net.neoforged.neoforge.common.CommonHooks.onArmorHurt(p_330843_, p_331314_, p_330394_, this); -+ p_331314_ = new EquipmentSlot[0]; //Neo: invalidates the loop. armor damage happens in common hook ++ if (true) return; //Neo: invalidates the loop. armor damage happens in common hook for (EquipmentSlot equipmentslot : p_331314_) { ItemStack itemstack = this.getItemBySlot(equipmentslot); if (itemstack.getItem() instanceof ArmorItem && itemstack.canBeHurtBy(p_330843_)) { From 8a0168da50369210b63a51ee6b581695e958e610 Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sat, 22 Jun 2024 18:27:32 -0400 Subject: [PATCH 40/41] javadoc tweaks --- src/main/java/net/neoforged/neoforge/common/CommonHooks.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index 695f70861c..d54ad60afe 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -258,7 +258,7 @@ public static boolean onEntityInvulnerabilityCheck(Entity entity, DamageSource s /** * Called after invulnerability checks in {@link LivingEntity#hurt(DamageSource, float)}, * this method creates and posts the first event in the LivingEntity damage sequence, - * {@link LivingIncomingDamageEvent}, FOR NON-PLAYER entities. + * {@link LivingIncomingDamageEvent}. * * @param entity the entity to receive damage * @param container the newly instantiated container for damage to be dealt. Most properties of @@ -285,8 +285,7 @@ public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageS * and requires access to the internal field {@link LivingEntity#damageContainers} as a parameter. * * @param entity the entity to receive damage - * @param container the container object holding the final values of the damage pipeline while they are - * still mutable + * @param container the container object holding the final values of the damage pipeline while they are still mutable * @return the current damage value to be applied to the entity's health * */ From 59aceae207f03042917f521fb9032cad6ce0ee3c Mon Sep 17 00:00:00 2001 From: Caltinor <62700786+Caltinor@users.noreply.github.com> Date: Sat, 22 Jun 2024 18:31:41 -0400 Subject: [PATCH 41/41] rename invul check in CommonHooks --- patches/net/minecraft/world/entity/Entity.java.patch | 2 +- src/main/java/net/neoforged/neoforge/common/CommonHooks.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/net/minecraft/world/entity/Entity.java.patch b/patches/net/minecraft/world/entity/Entity.java.patch index 28b4da1aac..f8cf8c0824 100644 --- a/patches/net/minecraft/world/entity/Entity.java.patch +++ b/patches/net/minecraft/world/entity/Entity.java.patch @@ -301,7 +301,7 @@ || this.invulnerable && !p_20122_.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !p_20122_.isCreativePlayer() || p_20122_.is(DamageTypeTags.IS_FIRE) && this.fireImmune() || p_20122_.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); -+ return net.neoforged.neoforge.common.CommonHooks.onEntityInvulnerabilityCheck(this, p_20122_, isVanillaInvulnerable); ++ return net.neoforged.neoforge.common.CommonHooks.isEntityInvulnerableTo(this, p_20122_, isVanillaInvulnerable); } public boolean isInvulnerable() { diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index d54ad60afe..730bdc1cbe 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -251,7 +251,7 @@ public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, * @param isInvul whether this entity is invulnerable according to preceding/vanilla logic * @return if this entity is invulnerable */ - public static boolean onEntityInvulnerabilityCheck(Entity entity, DamageSource source, boolean isInvul) { + public static boolean isEntityInvulnerableTo(Entity entity, DamageSource source, boolean isInvul) { return NeoForge.EVENT_BUS.post(new EntityInvulnerabilityCheckEvent(entity, source, isInvul)).isInvulnerable(); }