From edd5837b016f4cf934b90a7d16d976f6d5fd364e Mon Sep 17 00:00:00 2001 From: chaitu0461 Date: Sat, 4 Oct 2025 15:38:56 +0530 Subject: [PATCH 1/2] preserve entity state after lightining strike --- .../LightningTransformsMobsModule.java | 21 +++- .../util/EntityStatePreserverUtil.java | 115 ++++++++++++++++++ 2 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/purpurmc/purpurextras/util/EntityStatePreserverUtil.java diff --git a/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java b/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java index db1af72..297de25 100644 --- a/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java +++ b/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java @@ -18,6 +18,8 @@ import java.util.Locale; import java.util.Map; +import static org.purpurmc.purpurextras.util.EntityStatePreserverUtil.preserveEntityState; + /** * If enabled, entities with type on the left will be transformed into entity of type on the right. * This overrides vanilla transformations. Vanilla mob ids are used to identify mobs. @@ -85,12 +87,15 @@ public void onLightningStrike(EntityDamageByEntityEvent event) { spawnEntity(targetEntity, location); } - private void spawnEntity(Object entity, Location location) { + private Entity spawnEntity(Object entity, Location location) { + Entity spawnedEntity = null; if (entity instanceof EntityType entityType) { - location.getWorld().spawnEntity(location, entityType, CreatureSpawnEvent.SpawnReason.LIGHTNING); + spawnedEntity = location.getWorld().spawnEntity(location, entityType, CreatureSpawnEvent.SpawnReason.LIGHTNING); } else if (entity instanceof Entiddy entiddy) { - entiddy.entiddy().spawn(location, CreatureSpawnEvent.SpawnReason.LIGHTNING); + spawnedEntity = entiddy.entiddy().spawn(location, CreatureSpawnEvent.SpawnReason.LIGHTNING); } + + return spawnedEntity; } private void getEntityTypeOrSpecial(String key, String value) { @@ -136,7 +141,10 @@ public void onLightningStrike(EntityZapEvent event) { entity.remove(); String specialEntityKey = specialEntity.entiddy().toString().toLowerCase(Locale.ROOT); Object targetEntity = entities.get(specialEntityKey); - spawnEntity(targetEntity, location); + Entity spawnedEntity = spawnEntity(targetEntity, location); + if(spawnedEntity instanceof LivingEntity newEntity) { + preserveEntityState((LivingEntity) entity, newEntity); + } return; } Object targetEntity = entities.get(entity.getType().getKey().getKey()); @@ -146,7 +154,10 @@ public void onLightningStrike(EntityZapEvent event) { return; } entity.remove(); - spawnEntity(targetEntity, location); + Entity spawnedEntity = spawnEntity(targetEntity, location); + if(spawnedEntity instanceof LivingEntity newEntity) { + preserveEntityState((LivingEntity) entity, newEntity); + } event.setCancelled(true); } diff --git a/src/main/java/org/purpurmc/purpurextras/util/EntityStatePreserverUtil.java b/src/main/java/org/purpurmc/purpurextras/util/EntityStatePreserverUtil.java new file mode 100644 index 0000000..824f9c5 --- /dev/null +++ b/src/main/java/org/purpurmc/purpurextras/util/EntityStatePreserverUtil.java @@ -0,0 +1,115 @@ +package org.purpurmc.purpurextras.util; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.potion.PotionEffect; + + +public class EntityStatePreserverUtil { + + private EntityStatePreserverUtil() { + + } + + /** + * Copy persistent state from one LivingEntity to another. + */ + public static void preserveEntityState(LivingEntity oldEntity, LivingEntity transformedEntity) { + if (oldEntity == null || transformedEntity == null) return; + preserveGeneralProperties(oldEntity, transformedEntity); + + } + + + private static void preserveGeneralProperties(LivingEntity oldEntity, LivingEntity transformedEntity) { + preserveEquipment(oldEntity.getEquipment(), transformedEntity); + preserveHealth(oldEntity, transformedEntity); + preserveSurvivalState(oldEntity, transformedEntity); + preservePotionEffect(oldEntity, transformedEntity); + preserveFlags(oldEntity, transformedEntity); + preserveFireAndFreeze(oldEntity, transformedEntity); + preservePoseAndRotation(oldEntity, transformedEntity); + preserveExtraStates(oldEntity, transformedEntity); + + + } + + private static void preserveExtraStates(LivingEntity oldEntity, LivingEntity transformedEntity) { + preserveVelocity(oldEntity, transformedEntity); + transformedEntity.setPortalCooldown(oldEntity.getPortalCooldown()); + transformedEntity.setAI(oldEntity.hasAI()); + transformedEntity.setGliding(oldEntity.isGliding()); + transformedEntity.setSneaking(oldEntity.isSneaking()); + } + + private static void preserveSurvivalState(LivingEntity oldEntity, LivingEntity transformedEntity) { + transformedEntity.setAbsorptionAmount(oldEntity.getAbsorptionAmount()); + transformedEntity.setMaximumAir(oldEntity.getMaximumAir()); + transformedEntity.setRemainingAir(oldEntity.getRemainingAir()); + transformedEntity.setNoDamageTicks(oldEntity.getNoDamageTicks()); + } + + private static void preserveVelocity(LivingEntity oldEntity, LivingEntity transformedEntity) { + // Velocity (only if same entity type family, else may cause issues) + if (oldEntity.getType() == transformedEntity.getType()) { + transformedEntity.setVelocity(oldEntity.getVelocity()); + } + } + + private static void preservePoseAndRotation(LivingEntity oldEntity, LivingEntity transformedEntity) { + transformedEntity.setPose(oldEntity.getPose()); + transformedEntity.setRotation(oldEntity.getLocation().getYaw(), oldEntity.getLocation().getPitch()); + } + + private static void preserveFireAndFreeze(LivingEntity oldEntity, LivingEntity transformedEntity) { + transformedEntity.setFireTicks(oldEntity.getFireTicks()); + transformedEntity.setFreezeTicks(oldEntity.getFreezeTicks()); + } + + private static void preserveFlags(LivingEntity oldEntity, LivingEntity transformedEntity) { + transformedEntity.setCustomNameVisible(oldEntity.isCustomNameVisible()); + transformedEntity.setGlowing(oldEntity.isGlowing()); + transformedEntity.setGravity(oldEntity.hasGravity()); + transformedEntity.setCollidable(oldEntity.isCollidable()); + transformedEntity.setSilent(oldEntity.isSilent()); + transformedEntity.setInvisible(oldEntity.isInvisible()); + transformedEntity.setInvulnerable(oldEntity.isInvulnerable()); + transformedEntity.setPersistent(oldEntity.isPersistent()); + } + + private static void preservePotionEffect(LivingEntity oldEntity, LivingEntity transformedEntity) { + transformedEntity.getActivePotionEffects().forEach(pe -> transformedEntity.removePotionEffect(pe.getType())); + for (PotionEffect effect : oldEntity.getActivePotionEffects()) { + transformedEntity.addPotionEffect(effect); + } + } + + private static void preserveHealth(LivingEntity oldEntity, LivingEntity transformedEntity) { + transformedEntity.setHealth(oldEntity.getHealth()); + } + + private static void preserveEquipment(EntityEquipment oldEquipment, Entity spawnedEntity) { + if (spawnedEntity instanceof LivingEntity newEntity && oldEquipment != null) { + EntityEquipment newEquipment = newEntity.getEquipment(); + if (newEquipment != null) { + // Copy armor items + newEquipment.setArmorContents(oldEquipment.getArmorContents()); + + // Copy armor drop chances + newEquipment.setHelmetDropChance(oldEquipment.getHelmetDropChance()); + newEquipment.setChestplateDropChance(oldEquipment.getChestplateDropChance()); + newEquipment.setLeggingsDropChance(oldEquipment.getLeggingsDropChance()); + newEquipment.setBootsDropChance(oldEquipment.getBootsDropChance()); + + // Copy hand items and their drop chances + newEquipment.setItemInMainHand(oldEquipment.getItemInMainHand()); + newEquipment.setItemInMainHandDropChance(oldEquipment.getItemInMainHandDropChance()); + newEquipment.setItemInOffHand(oldEquipment.getItemInOffHand()); + newEquipment.setItemInOffHandDropChance(oldEquipment.getItemInOffHandDropChance()); + } + } + } + + +} From cab23794d4cf38a169c2ab044029608345465eff Mon Sep 17 00:00:00 2001 From: chaitu0461 Date: Sun, 5 Oct 2025 17:26:35 +0530 Subject: [PATCH 2/2] add a boolean flag before preserving mob state --- .../purpurextras/modules/LightningTransformsMobsModule.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java b/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java index 297de25..2d2abc1 100644 --- a/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java +++ b/src/main/java/org/purpurmc/purpurextras/modules/LightningTransformsMobsModule.java @@ -33,12 +33,14 @@ public class LightningTransformsMobsModule implements PurpurExtrasModule, Listener { private final HashMap entities = new HashMap<>(); + private final boolean preserveMobStateOnLightningTransformation; protected LightningTransformsMobsModule() { Map defaults = new HashMap<>(); defaults.put("villager", "witch"); defaults.put("pig", "zombified_piglin"); ConfigurationSection section = PurpurExtras.getPurpurConfig().getConfigSection("settings.lightning-transforms-entities.entities", defaults); + this.preserveMobStateOnLightningTransformation = PurpurExtras.getPurpurConfig().getBoolean("settings.lightning-transforms-entities.preserve-entity-state", false); HashMap lightningTransformEntities = new HashMap<>(); for (String key : section.getKeys(false)) { String value = section.getString(key); @@ -142,7 +144,7 @@ public void onLightningStrike(EntityZapEvent event) { String specialEntityKey = specialEntity.entiddy().toString().toLowerCase(Locale.ROOT); Object targetEntity = entities.get(specialEntityKey); Entity spawnedEntity = spawnEntity(targetEntity, location); - if(spawnedEntity instanceof LivingEntity newEntity) { + if(preserveMobStateOnLightningTransformation && spawnedEntity instanceof LivingEntity newEntity) { preserveEntityState((LivingEntity) entity, newEntity); } return; @@ -155,7 +157,7 @@ public void onLightningStrike(EntityZapEvent event) { } entity.remove(); Entity spawnedEntity = spawnEntity(targetEntity, location); - if(spawnedEntity instanceof LivingEntity newEntity) { + if(preserveMobStateOnLightningTransformation && spawnedEntity instanceof LivingEntity newEntity) { preserveEntityState((LivingEntity) entity, newEntity); } event.setCancelled(true);