From e982eae1c38530ef06735c4074e5d43ea279e7ac Mon Sep 17 00:00:00 2001 From: like4schnitzel Date: Thu, 13 Aug 2026 01:32:58 +0200 Subject: [PATCH 1/2] feat: add entity explosion resistance option --- .../petrak/hexcasting/api/mod/HexConfig.java | 3 +++ .../casting/actions/spells/OpExplode.kt | 23 +++++++++++++++++++ .../hexcasting/fabric/FabricHexConfig.java | 7 ++++++ .../hexcasting/forge/ForgeHexConfig.java | 12 ++++++++++ 4 files changed, 45 insertions(+) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java index 31bbf5379b..11a0ea1af8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java @@ -27,6 +27,8 @@ public interface CommonConfigAccess { int artifactCooldown(); + int entityExplosionResistance(); + long DEFAULT_DUST_MEDIA_AMOUNT = MediaConstants.DUST_UNIT; long DEFAULT_SHARD_MEDIA_AMOUNT = MediaConstants.SHARD_UNIT; long DEFAULT_CHARGED_MEDIA_AMOUNT = MediaConstants.CRYSTAL_UNIT; @@ -36,6 +38,7 @@ public interface CommonConfigAccess { int DEFAULT_TRINKET_COOLDOWN = 5; int DEFAULT_ARTIFACT_COOLDOWN = 3; + int DEFAULT_ENTITY_EXPLOSION_RESISTANCE = 0; } public interface ClientConfigAccess { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt index 0bed07989c..6ff652726c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt @@ -8,9 +8,13 @@ import at.petrak.hexcasting.api.casting.getPositiveDoubleUnderInclusive import at.petrak.hexcasting.api.casting.getVec3 import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.misc.MediaConstants +import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.common.casting.actions.selectors.OpGetEntitiesBy import net.minecraft.core.BlockPos import net.minecraft.util.Mth +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffects +import net.minecraft.world.entity.LivingEntity import net.minecraft.world.level.Level import net.minecraft.world.phys.AABB import net.minecraft.world.phys.Vec3 @@ -53,6 +57,25 @@ class OpExplode(val fire: Boolean) : SpellAction { if (!env.canEditBlockAt(BlockPos.containing(pos))) return + val resistanceLevel = HexConfig.common().entityExplosionResistance() + + if (resistanceLevel > 0) { + val radius = strength * 4 / 3; // approximation + val aabb = AABB(pos.add(Vec3(-radius, -radius, -radius)), pos.add(Vec3(radius, radius, radius))) + val entitiesGot = env.world.getEntities(null, aabb) + .filter { entity -> entity is LivingEntity && entity != env.castingEntity } + .map { entity -> entity as LivingEntity } + entitiesGot.forEach { entity -> + entity.addEffect( + MobEffectInstance( + MobEffects.DAMAGE_RESISTANCE, + 1, // 1 tick only, we want this to exclusively block the explosion + resistanceLevel - 1 + ) + ) + } + } + env.world.explode( env.castingEntity, pos.x, diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java index 8fc4d8465d..c4a96f08ff 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java @@ -80,6 +80,8 @@ public static final class Common implements HexConfig.CommonConfigAccess, Config @ConfigEntry.Gui.Tooltip private int artifactCooldown = DEFAULT_ARTIFACT_COOLDOWN; + @ConfigEntry.Gui.Tooltip + private int entityExplosionResistance = DEFAULT_ENTITY_EXPLOSION_RESISTANCE; @Override public void validatePostLoad() throws ValidationException { @@ -123,6 +125,11 @@ public int trinketCooldown() { public int artifactCooldown() { return artifactCooldown; } + + @Override + public int entityExplosionResistance() { + return entityExplosionResistance; + } } @Config(name = "client") diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java index 510e7eb8b7..fd4b9986cd 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java @@ -23,6 +23,8 @@ public class ForgeHexConfig implements HexConfig.CommonConfigAccess { private static ForgeConfigSpec.IntValue trinketCooldown; private static ForgeConfigSpec.IntValue artifactCooldown; + private static ForgeConfigSpec.IntValue entityExplosionResistance; + public ForgeHexConfig(ForgeConfigSpec.Builder builder) { builder.push("Media Amounts"); dustMediaAmount = builder.comment("How much media a single Amethyst Dust item is worth") @@ -43,6 +45,11 @@ public ForgeHexConfig(ForgeConfigSpec.Builder builder) { artifactCooldown = builder.comment("Cooldown in ticks of a artifact") .defineInRange("artifactCooldown", DEFAULT_ARTIFACT_COOLDOWN, 0, Integer.MAX_VALUE); builder.pop(); + + builder.push("Misc"); + entityExplosionResistance = builder.comment("How much entities should resist explosion damage, where the reduction is Value times 20%") + .defineInRange("entityExplosionResistance", DEFAULT_ENTITY_EXPLOSION_RESISTANCE, 0, 5); + builder.pop(); } @Override @@ -80,6 +87,11 @@ public int artifactCooldown() { return artifactCooldown.get(); } + @Override + public int entityExplosionResistance() { + return entityExplosionResistance.get(); + } + public static class Client implements HexConfig.ClientConfigAccess { private static ForgeConfigSpec.BooleanValue ctrlTogglesOffStrokeOrder; private static ForgeConfigSpec.BooleanValue disableInworldScrolling; From ebbc85ab83e6ed7c2fa898196cc0e30efa4e1345 Mon Sep 17 00:00:00 2001 From: like4schnitzel Date: Thu, 13 Aug 2026 16:00:27 +0200 Subject: [PATCH 2/2] rewrite to use explosion mixin --- .../petrak/hexcasting/api/mod/HexConfig.java | 4 +- .../casting/actions/spells/OpExplode.kt | 45 ++++++------------- .../helper/ExplosionSourceTracker.java | 13 ++++++ .../hexcasting/mixin/MixinExplosion.java | 19 ++++++++ .../hexcasting/lang/en_us.flatten.json5 | 4 ++ Common/src/main/resources/hexplat.mixins.json | 1 + .../hexcasting/fabric/FabricHexConfig.java | 7 +-- .../hexcasting/forge/ForgeHexConfig.java | 10 ++--- 8 files changed, 62 insertions(+), 41 deletions(-) create mode 100644 Common/src/main/java/at/petrak/hexcasting/helper/ExplosionSourceTracker.java create mode 100644 Common/src/main/java/at/petrak/hexcasting/mixin/MixinExplosion.java diff --git a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java index 11a0ea1af8..61c8671edd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexConfig.java @@ -27,7 +27,7 @@ public interface CommonConfigAccess { int artifactCooldown(); - int entityExplosionResistance(); + int explosionScaling(); long DEFAULT_DUST_MEDIA_AMOUNT = MediaConstants.DUST_UNIT; long DEFAULT_SHARD_MEDIA_AMOUNT = MediaConstants.SHARD_UNIT; @@ -38,7 +38,7 @@ public interface CommonConfigAccess { int DEFAULT_TRINKET_COOLDOWN = 5; int DEFAULT_ARTIFACT_COOLDOWN = 3; - int DEFAULT_ENTITY_EXPLOSION_RESISTANCE = 0; + int DEFAULT_EXPLOSION_SCALING = 100; } public interface ClientConfigAccess { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt index 6ff652726c..8ae185013f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpExplode.kt @@ -8,13 +8,10 @@ import at.petrak.hexcasting.api.casting.getPositiveDoubleUnderInclusive import at.petrak.hexcasting.api.casting.getVec3 import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.misc.MediaConstants -import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.common.casting.actions.selectors.OpGetEntitiesBy +import at.petrak.hexcasting.helper.ExplosionSourceTracker import net.minecraft.core.BlockPos import net.minecraft.util.Mth -import net.minecraft.world.effect.MobEffectInstance -import net.minecraft.world.effect.MobEffects -import net.minecraft.world.entity.LivingEntity import net.minecraft.world.level.Level import net.minecraft.world.phys.AABB import net.minecraft.world.phys.Vec3 @@ -57,34 +54,20 @@ class OpExplode(val fire: Boolean) : SpellAction { if (!env.canEditBlockAt(BlockPos.containing(pos))) return - val resistanceLevel = HexConfig.common().entityExplosionResistance() - - if (resistanceLevel > 0) { - val radius = strength * 4 / 3; // approximation - val aabb = AABB(pos.add(Vec3(-radius, -radius, -radius)), pos.add(Vec3(radius, radius, radius))) - val entitiesGot = env.world.getEntities(null, aabb) - .filter { entity -> entity is LivingEntity && entity != env.castingEntity } - .map { entity -> entity as LivingEntity } - entitiesGot.forEach { entity -> - entity.addEffect( - MobEffectInstance( - MobEffects.DAMAGE_RESISTANCE, - 1, // 1 tick only, we want this to exclusively block the explosion - resistanceLevel - 1 - ) - ) - } + ExplosionSourceTracker.setSpellSource(true) + try { + env.world.explode( + env.castingEntity, + pos.x, + pos.y, + pos.z, + strength.toFloat(), + this.fire, + Level.ExplosionInteraction.TNT + ) + } finally { + ExplosionSourceTracker.setSpellSource(false) } - - env.world.explode( - env.castingEntity, - pos.x, - pos.y, - pos.z, - strength.toFloat(), - this.fire, - Level.ExplosionInteraction.TNT - ) } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/helper/ExplosionSourceTracker.java b/Common/src/main/java/at/petrak/hexcasting/helper/ExplosionSourceTracker.java new file mode 100644 index 0000000000..a5bbd422a4 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/helper/ExplosionSourceTracker.java @@ -0,0 +1,13 @@ +package at.petrak.hexcasting.helper; + +public final class ExplosionSourceTracker { + private static final ThreadLocal IS_SPELL_SOURCE = ThreadLocal.withInitial(() -> false); + + public static boolean isSpellSource() { + return IS_SPELL_SOURCE.get(); + } + + public static void setSpellSource(boolean spellSource) { + IS_SPELL_SOURCE.set(spellSource); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/MixinExplosion.java b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinExplosion.java new file mode 100644 index 0000000000..9b43864e13 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/MixinExplosion.java @@ -0,0 +1,19 @@ +package at.petrak.hexcasting.mixin; + +import at.petrak.hexcasting.api.mod.HexConfig; +import at.petrak.hexcasting.helper.ExplosionSourceTracker; +import net.minecraft.world.level.Explosion; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +@Mixin(Explosion.class) +public abstract class MixinExplosion { + @ModifyArgs(method = "explode", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z")) + private void scaleEntityExplosionDamage(Args args) { + if (ExplosionSourceTracker.isSpellSource()) { + args.set(1, (Float) args.get(1) * HexConfig.common().explosionScaling() / 100f); + } + } +} diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index c361c595e5..5c9b007014 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -337,6 +337,10 @@ "": "Artifact Cooldown", "@Tooltip": "Cooldown of an artifact in ticks", }, + explosionScaling: { + "": "Explosion Scaling", + "@Tooltip": "Scaling for entity damage caused by explosion spells in %", + }, }, client: { diff --git a/Common/src/main/resources/hexplat.mixins.json b/Common/src/main/resources/hexplat.mixins.json index a70b99261b..9683c3dc83 100644 --- a/Common/src/main/resources/hexplat.mixins.json +++ b/Common/src/main/resources/hexplat.mixins.json @@ -11,6 +11,7 @@ "MixinVillager", "MixinWanderingTrader", "MixinWitch", + "MixinExplosion", "accessor.AccessorAbstractArrow", "accessor.AccessorEntity", "accessor.AccessorLivingEntity", diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java index c4a96f08ff..996bea3c5a 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/FabricHexConfig.java @@ -81,7 +81,7 @@ public static final class Common implements HexConfig.CommonConfigAccess, Config private int artifactCooldown = DEFAULT_ARTIFACT_COOLDOWN; @ConfigEntry.Gui.Tooltip - private int entityExplosionResistance = DEFAULT_ENTITY_EXPLOSION_RESISTANCE; + private int explosionScaling = DEFAULT_EXPLOSION_SCALING; @Override public void validatePostLoad() throws ValidationException { @@ -127,9 +127,10 @@ public int artifactCooldown() { } @Override - public int entityExplosionResistance() { - return entityExplosionResistance; + public int explosionScaling() { + return explosionScaling; } + } @Config(name = "client") diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java index fd4b9986cd..027a305c05 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java @@ -23,7 +23,7 @@ public class ForgeHexConfig implements HexConfig.CommonConfigAccess { private static ForgeConfigSpec.IntValue trinketCooldown; private static ForgeConfigSpec.IntValue artifactCooldown; - private static ForgeConfigSpec.IntValue entityExplosionResistance; + private static ForgeConfigSpec.IntValue explosionScaling; public ForgeHexConfig(ForgeConfigSpec.Builder builder) { builder.push("Media Amounts"); @@ -47,8 +47,8 @@ public ForgeHexConfig(ForgeConfigSpec.Builder builder) { builder.pop(); builder.push("Misc"); - entityExplosionResistance = builder.comment("How much entities should resist explosion damage, where the reduction is Value times 20%") - .defineInRange("entityExplosionResistance", DEFAULT_ENTITY_EXPLOSION_RESISTANCE, 0, 5); + explosionScaling = builder.comment("Scaling for entity damage caused by explosion spells in %") + .defineInRange("explosionScaling", DEFAULT_EXPLOSION_SCALING, 0, Integer.MAX_VALUE); builder.pop(); } @@ -88,8 +88,8 @@ public int artifactCooldown() { } @Override - public int entityExplosionResistance() { - return entityExplosionResistance.get(); + public int explosionScaling() { + return explosionScaling.get(); } public static class Client implements HexConfig.ClientConfigAccess {