Skip to content

Entity Modification Event

liopyu edited this page Aug 14, 2025 · 12 revisions

Modifying and Overriding Methods in Minecraft Entities🔄

In this guide, we'll explore how to modify and override methods of Minecraft entities using EntityJS. It's important to understand the limitations and scopes of these modifications, particularly when dealing with entities that have overridden methods in their subclasses.

Understanding Method Overrides💡

Minecraft entities have various methods controlling their behavior, sounds, and interactions. Many of these can be overridden using the `EntityJSEvents.modifyEntity` event, but in some cases, subclass implementations may prevent certain methods from being modified.
Example: You can generally modify the `.setHurtSound()` method for most entities, but for entities like zombies, you cannot override the `getHurtSound()` method because it is already overridden in their subclass.

Example Script

//Startup Event
EntityJSEvents.modifyEntity(event => {
    event.modify("minecraft:zombie", modifyBuilder => {
        // Since zombies extend the PathfinderMob class, a ModifyPathfinderMobBuilder will be provided
        modifyBuilder.onRemovedFromWorld(entity => {
            // Code to execute when the zombie is removed from the world
        })
        // Example on how to write synced entity data
        modifyBuilder.defineSyncedData(entity => {
            entity.addSyncedData("string", "NbtTagName", "StartValue")
        })
    });
});
This example demonstrates how to modify the behavior of a Minecraft zombie using the `EntityJSEvents.modifyEntity` event. In this case, a custom action is triggered when the zombie is removed from the world.

Key Takeaways

- You can modify most entity methods using `EntityJSEvents.modifyEntity`, but some methods in subclasses, like `getHurtSound()` in zombies, cannot be overridden.
- Focus on modifying methods that are not already overridden in the subclass for entities like zombies.
Full Code Example 1.19-1.20
EntityJSEvents.modifyEntity(event => {
	event.modify("minecraft:zombie", modifyBuilder => {
		modifyBuilder
			/**
			 * Entity Overrides for entities that are non-living
			 */
			.controlledByFirstPassenger(true)
			.myRidingOffset(entity => 5)
			.canCollideWith(context => true)
			.isFreezing(entity => true)
			.setBlockJumpFactor(entity => 10)
			.isPushable(false)
			.positionRider(context => {
				const { entity, passenger, moveFunction } = context
			})
			.canAddPassenger(context => true)
			.setSwimSound("minecraft:entity.generic.swim")
			.setSwimSplashSound("minecraft:entity.generic.splash")
			.blockSpeedFactor(entity => 1)
			.isFlapping(entity => false)
			.onAddedToWorld(entity => {})
			.repositionEntityAfterLoad(true)
			.onSprint(entity => {})
			.onStopRiding(entity => {})
			.rideTick(entity => {})
			.canFreeze(entity => true)
			.isCurrentlyGlowing(entity => true)
			.setMaxFallDistance(entity => 3)
			.onClientRemoval(entity => {})
			.lavaHurt(entity => {})
			.onFlap(entity => {})
			.dampensVibrations(entity => {})
			.showVehicleHealth(entity => true)
			.thunderHit(context => {})
			.isInvulnerableTo(context => false)
			.canChangeDimensions(entity => false)
			.mayInteract(context => false)
			.canTrample(context => false)
			.onRemovedFromWorld(entity => {})
			.onFall(context => {})
			.lerpTo(context => {})
			.shouldRenderAtSqrDistance(context => true)
			.isAttackable(true)
			.playerTouch(context => {})
			.move(context => {})
			.tick(entity => {})
			.onInteract(context => {
				if (context.player.isShiftKeyDown()) return;
				context.player.startRiding(context.entity);
			})

			/**
			 * LivingEntity Overrides available for living entities
			 */
			.setWaterSlowDown(0.6)
			.setSoundVolume(0.5)
			.shouldDropLoot(entity => false)
			.aiStep(entity => {})
			.isAffectedByFluids(entity => false)
			.isImmobile(entity => false)
			.isAlwaysExperienceDropper(true)
			.calculateFallDamage(context => 1)
			.setDeathSound("minecraft:entity.generic.death")
			.doAutoAttackOnTouch(context => {})
			.setStandingEyeHeight(context => 1)
			.onDecreaseAirSupply(entity => {})
			.onBlockedByShield(context => {})
			.nextStep(entity => 1)
			.onIncreaseAirSupply(entity => {})
			.setHurtSound(context => {
				const { entity, damageSource } = context;
				switch (damageSource.getType()) {
					case "fire":
						return "minecraft:entity.generic.explode";
					case "fall":
						return "minecraft:entity.generic.hurt";
					case "drown":
						return "minecraft:entity.generic.hurt";
					case "explosion":
						return "minecraft:entity.generic.explode";
					default:
						return "minecraft:entity.generic.explode";
				}
			})
			.canAttackType(context => false)
			.scale(entity => 1)
			.shouldDropExperience(entity => false)
			.experienceReward(killedEntity => 10)
			.onEquipItem(context => {})
			.visibilityPercent(context => 1)
			.canAttack(context => false)
			.canBeAffected(context => false)
			.invertedHealAndHarm(entity => true)
			.onEffectAdded(context => {})
			.onLivingHeal(context => {})
			.onEffectRemoved(context => {})
			.onHurt(context => {})
			.onDeath(context => {})
			.dropCustomDeathLoot(context => {})
			.fallSounds("minecraft:entity.generic.small_fall", "minecraft:entity.generic.large_fall")
			.eatingSound("minecraft:entity.zombie.ambient")
			.onClimbable(entity => false)
			.canBreatheUnderwater(true)
			.onLivingFall(context => {})
			.jumpBoostPower(entity => 1)
			.canStandOnFluid(context => true)
			.isSensitiveToWater(entity => true)
			.onItemPickup(context => {})
			.hasLineOfSight(context => false)
			.onEnterCombat(entity => {})
			.onLeaveCombat(entity => {})
			.isAffectedByPotions(entity => false)
			.isAttackableFunction(entity => true)
			.canTakeItem(context => true)
			.isSleeping(entity => false)
			.onStartSleeping(context => {})
			.onStopSleeping(entity => {})
			.eat(context => {})
			.shouldRiderFaceForward(context => true)
			.canDisableShield(entity => true)
			.isPickable(entity => {
				return true;
			})
			.lerpTo(context => {
				const { x, y, z, yaw, pitch, posRotationIncrements, teleport, entity } = context;
				entity.setPositionAndRotation(x, y, z, yaw, pitch);
			})
			.isAlliedTo(context => {
				const { entity, target } = context;
				return target.type == 'minecraft:blaze';
			})
			.onHurtTarget(context => {
				const { entity, targetEntity } = context;
				//Execute code when the target is hurt
			})
			.tickDeath(entity => {})
			.travel(context => {
				const { entity, vec3 } = context;
				// Use the vec3 and entity to determine the travel logic of the entity
			})
			.mobType('undead')
			.positionRider(context => {
				const { entity, passenger, moveFunction } = context;
			})
			/**
			* Mob Overrides for entities extending from Mob class
			*/
			.mobInteract(context => {
				if (context.player.isShiftKeyDown()) return;
				context.player.startRiding(context.entity);
			})
			.createNavigation(context => {
				const { entity, level } = context;
				return EntityJSUtils.createWallClimberNavigation(entity, level);
			})
			.canBeLeashed(context => true)
			.removeWhenFarAway(context => {})
			.ambientSoundInterval(100)
			.onTargetChanged(context => {})
			.ate(entity => {})
			.setAmbientSound("minecraft:entity.zombie.ambient")
			.canHoldItem(context => true)
			.shouldDespawnInPeaceful(true)
			.canPickUpLoot(entity => true)
			.isPersistenceRequired(true)
			.meleeAttackRangeSqr(entity => 2)
			.tickLeash(context => {})
			 /**
			 * PathfinderMob Overrides for mobs extending the PathfinderMob class
			 */
			.shouldStayCloseToLeashHolder(entity => true)
			.followLeashSpeed(1.5)
			.walkTargetValue(context => 10);
	})
});
Full Code Example 1.21
EntityJSEvents.modifyEntity(event => {
	event.modify("minecraft:zombie", modifyBuilder => {
		modifyBuilder
			/**
			 * Entity Overrides for entities that are non-living
			 */
			.controlledByFirstPassenger(true)
			.canCollideWith(context => true)
			.isFreezing(entity => true)
			.setBlockJumpFactor(entity => 10)
			.isPushable(false)
			.positionRider(context => {
				const { entity, passenger, moveFunction } = context
			})
			.canAddPassenger(context => true)
			.setSwimSound("minecraft:entity.generic.swim")
			.setSwimSplashSound("minecraft:entity.generic.splash")
			.blockSpeedFactor(entity => 1)
			.isFlapping(entity => false)
			.onAddedToWorld(entity => { })
			.repositionEntityAfterLoad(true)
			.onSprint(entity => { })
			.onStopRiding(entity => { })
			.rideTick(entity => { })
			.canFreeze(entity => true)
			.isCurrentlyGlowing(entity => true)
			.setMaxFallDistance(entity => 3)
			.onClientRemoval(entity => { })
			.lavaHurt(entity => { })
			.onFlap(entity => { })
			.dampensVibrations(entity => { })
			.showVehicleHealth(entity => true)
			.thunderHit(context => { })
			.isInvulnerableTo(context => false)
			.canChangeDimensions(ctx => false)
			.mayInteract(context => false)
			.canTrample(context => false)
			.onRemovedFromWorld(entity => { })
			.onFall(context => { })
			.lerpTo(context => { })
			.shouldRenderAtSqrDistance(context => true)
			.isAttackable(true)
			.playerTouch(context => { })
			.move(context => { })
			.tick(entity => { })
			.onInteract(context => {
				if (context.player.isShiftKeyDown()) return;
				context.player.startRiding(context.entity);
			})
			/**
			 * LivingEntity Overrides available for living entities
			 */
			.setWaterSlowDown(0.6)
			.setSoundVolume(0.5)
			.shouldDropLoot(entity => false)
			.aiStep(entity => { })
			.isAffectedByFluids(entity => false)
			.isImmobile(entity => false)
			.isAlwaysExperienceDropper(true)
			.calculateFallDamage(context => 1)
			.setDeathSound("minecraft:entity.generic.death")
			.doAutoAttackOnTouch(context => { })
			.onDecreaseAirSupply(entity => { })
			.onBlockedByShield(context => { })
			.nextStep(entity => 1)
			.onIncreaseAirSupply(entity => { })
			.setHurtSound(context => {
				const { entity, damageSource } = context;
				switch (damageSource.getType()) {
					case "fire":
						return "minecraft:entity.generic.explode";
					case "fall":
						return "minecraft:entity.generic.hurt";
					case "drown":
						return "minecraft:entity.generic.hurt";
					case "explosion":
						return "minecraft:entity.generic.explode";
					default:
						return "minecraft:entity.generic.explode";
				}
			})
			.canAttackType(context => false)
			.scale(entity => 1)
			.shouldDropExperience(entity => false)
			.experienceReward(killedEntity => 10)
			.onEquipItem(context => { })
			.visibilityPercent(context => 1)
			.canAttack(context => false)
			.canBeAffected(context => false)
			.invertedHealAndHarm(entity => true)
			.onEffectAdded(context => { })
			.onLivingHeal(context => { })
			.onEffectRemoved(context => { })
			.onHurt(context => { })
			.onDeath(context => { })
			.dropCustomDeathLoot(context => { })
			.fallSounds("minecraft:entity.generic.small_fall", "minecraft:entity.generic.large_fall")
			.eatingSound("minecraft:entity.zombie.ambient")
			.onClimbable(entity => false)
			.canBreatheUnderwater(true)
			.onLivingFall(context => { })
			.jumpBoostPower(entity => 1)
			.canStandOnFluid(context => true)
			.isSensitiveToWater(entity => true)
			.onItemPickup(context => { })
			.hasLineOfSight(context => false)
			.onEnterCombat(entity => { })
			.onLeaveCombat(entity => { })
			.isAffectedByPotions(entity => false)
			.isAttackableFunction(entity => true)
			.canTakeItem(context => true)
			.isSleeping(entity => false)
			.onStartSleeping(context => { })
			.onStopSleeping(entity => { })
			.eat(context => { })
			.shouldRiderFaceForward(context => true)
			.canDisableShield(entity => true)
			.isPickable(entity => {
				return true;
			})
			.lerpTo(context => {
				const { x, y, z, yaw, pitch, posRotationIncrements, teleport, entity } = context;
				entity.setPositionAndRotation(x, y, z, yaw, pitch);
			})
			.isAlliedTo(context => {
				const { entity, target } = context;
				return target.type == 'minecraft:blaze';
			})
			.onHurtTarget(context => {
				const { entity, targetEntity } = context;
				//Execute code when the target is hurt
			})
			.tickDeath(entity => { })
			.travel(context => {
				const { entity, vec3 } = context;
				// Use the vec3 and entity to determine the travel logic of the entity
			})
			.positionRider(context => {
				const { entity, passenger, moveFunction } = context;
			})
			/**
			 * Mob Overrides for entities extending from Mob class
			 */
			.mobInteract(context => {
				if (context.player.isShiftKeyDown()) return;
				context.player.startRiding(context.entity);
			})
			.createNavigation(context => {
				const { entity, level } = context;
				return EntityJSUtils.createWallClimberNavigation(entity, level);
			})
			.canBeLeashed(context => true)
			.removeWhenFarAway(context => { })
			.ambientSoundInterval(100)
			.onTargetChanged(context => { })
			.ate(entity => { })
			.setAmbientSound("minecraft:entity.zombie.ambient")
			.canHoldItem(context => true)
			.shouldDespawnInPeaceful(true)
			.canPickUpLoot(entity => true)
			.isPersistenceRequired(true)
			.meleeAttackRangeSqr(entity => 2)
			/**
			 * PathfinderMob Overrides for mobs extending the PathfinderMob class
			 */
			.shouldStayCloseToLeashHolder(entity => true)
			.followLeashSpeed(1.5)
			.walkTargetValue(context => 10);
	})
});

Builder Type Dependency

The type of builder provided during entity modification depends on the subtype of the entity being modified. This is determined at runtime by the `modifyEntity` method, which checks the entity's type and provides the appropriate builder.

Available Builders

ModifyPathfinderMobBuilder Used for entities that extend PathfinderMob.
ModifyMobBuilder Used for entities that extend Mob.
ModifyLivingEntityBuilder Used for entities that extend LivingEntity.
ModifyEntityBuilder Used for entities that extend Entity.
Each builder includes methods specific to the features and behaviors of the entity type it supports, ensuring effective and appropriate modifications.

Methods by Builder Type

ModifyEntityBuilder Methods

- `onInteract`
- `controlledByFirstPassenger`
- `myRidingOffset`
- `isPickable`
- `canCollideWith`
- `isFreezing`
- `setBlockJumpFactor`
- `isPushable`
- `positionRider`
- `canAddPassenger`
- `setSwimSound`
- `setSwimSplashSound`
- `blockSpeedFactor`
- `isFlapping`
- `onAddedToWorld`
- `repositionEntityAfterLoad`
- `onSprint`
- `onStopRiding`
- `rideTick`
- `canFreeze`
- `isCurrentlyGlowing`
- `setMaxFallDistance`
- `onClientRemoval`
- `lavaHurt`
- `onFlap`
- `dampensVibrations`
- `showVehicleHealth`
- `thunderHit`
- `isInvulnerableTo`
- `canChangeDimensions`
- `mayInteract`
- `canTrample`
- `onRemovedFromWorld`
- `onFall`
- `lerpTo`
- `shouldRenderAtSqrDistance`
- `isAttackable`
- `playerTouch`
- `move`
- `tick`

ModifyLivingEntityBuilder Methods

- `setWaterSlowDown`
- `setSoundVolume`
- `shouldDropLoot`
- `aiStep`
- `isPushable`
- `isAffectedByFluids`
- `isImmobile`
- `isAlwaysExperienceDropper`
- `calculateFallDamage`
- `setDeathSound`
- `doAutoAttackOnTouch`
- `setStandingEyeHeight`
- `onDecreaseAirSupply`
- `onBlockedByShield`
- `repositionEntityAfterLoad`
- `nextStep`
- `onIncreaseAirSupply`
- `setHurtSound`
- `canAttackType`
- `scale`
- `shouldDropExperience`
- `experienceReward`
- `onEquipItem`
- `visibilityPercent`
- `canAttack`
- `canBeAffected`
- `invertedHealAndHarm`
- `onEffectAdded`
- `onLivingHeal`
- `onEffectRemoved`
- `onHurt`
- `onDeath`
- `dropCustomDeathLoot`
- `fallSounds`
- `eatingSound`
- `onClimbable`
- `canBreatheUnderwater`
- `onLivingFall`
- `jumpBoostPower`
- `canStandOnFluid`
- `isSensitiveToWater`
- `onItemPickup`
- `hasLineOfSight`
- `onEnterCombat`
- `onLeaveCombat`
- `isAffectedByPotions`
- `isAttackableFunction`
- `canTakeItem`
- `isSleeping`
- `onStartSleeping`
- `onStopSleeping`
- `eat`
- `shouldRiderFaceForward`

ModifyMobBuilder Methods

- `canDisableShield`
- `mobInteract`
- `lerpTo`
- `isAlliedTo`
- `onHurtTarget`
- `tickDeath`
- `travel`
- `mobType`
- `positionRider`
- `createNavigation`
- `canBeLeashed`
- `removeWhenFarAway`
- `ambientSoundInterval`
- `onTargetChanged`
- `ate`
- `setAmbientSound`
- `canHoldItem`
- `shouldDespawnInPeaceful`
- `canPickUpLoot`
- `isPersistenceRequired`
- `meleeAttackRangeSqr`
- `tickLeash`

ModifyPathfinderMobBuilder Methods

- `shouldStayCloseToLeashHolder`
- `followLeashSpeed`
- `walkTargetValue`

Methods Exclusive to Forge

- `shouldStayCloseToLeashHolder`
- `shouldRiderFaceForward`
- `canTrample`
Clone this wiki locally