From 41c2a23b5eaa644120cb87477ca69db6bfcc5c7d Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Sat, 4 Apr 2026 04:21:01 -0400 Subject: [PATCH 1/3] Add handling for incorrect entity lookdirs --- .../actions/queryentity/OpEntityLook.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt index 23e47e9076..b2011479d0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt @@ -5,6 +5,11 @@ import at.petrak.hexcasting.api.casting.castables.ConstMediaAction import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.getEntity import at.petrak.hexcasting.api.casting.iota.Iota +import net.minecraft.world.entity.monster.Phantom +import net.minecraft.world.entity.projectile.AbstractHurtingProjectile +import net.minecraft.world.entity.projectile.Projectile +import net.minecraft.world.entity.projectile.ShulkerBullet +import net.minecraft.world.phys.Vec3 object OpEntityLook : ConstMediaAction { override val argc = 1 @@ -12,6 +17,17 @@ object OpEntityLook : ConstMediaAction { override fun execute(args: List, env: CastingEnvironment): List { val e = args.getEntity(0, argc) env.assertEntityInRange(e) - return e.lookAngle.asActionResult + + var lookDir = e.lookAngle + if (e is Projectile) { // https://bugs.mojang.com/browse/MC/issues/MC-112474 + if (e is AbstractHurtingProjectile || e is ShulkerBullet) + lookDir = Vec3(-1 * lookDir.x, lookDir.y, -1 * lookDir.z) + else + lookDir = Vec3(-1 * lookDir.x, -1 * lookDir.y, lookDir.z) + } else if (e is Phantom) { // https://bugs.mojang.com/browse/MC/issues/MC-134707 + lookDir = Vec3(lookDir.x, -1 * lookDir.y, lookDir.z) + } + + return lookDir.asActionResult } } From 51acbefc0666e9b19df32c410a308d47f2b2e5b1 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:21:54 -0400 Subject: [PATCH 2/3] Move handling code to HexAPI, use for OpBlink --- .../java/at/petrak/hexcasting/api/HexAPI.java | 7 +++++++ .../actions/queryentity/OpEntityLook.kt | 17 ++--------------- .../common/casting/actions/spells/OpBlink.kt | 5 +++-- .../hexcasting/common/impl/HexAPIImpl.java | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java b/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java index 8ddde5669b..45af9fee79 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/HexAPI.java @@ -83,6 +83,13 @@ default Component getRawHookI18n(ResourceLocation name) { return Component.translatable(getRawHookI18nKey(name)).withStyle(ChatFormatting.LIGHT_PURPLE); } + /** + * If the entity has a special getter return that, otherwise return its normal look angle + */ + default Vec3 getEntityLookDirSpecial(Entity entity) { + return entity.getLookAngle(); + } + /** * Register an entity with the given ID to have its velocity as perceived by OpEntityVelocity be different * than it's "normal" velocity diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt index b2011479d0..81ad7d3a1f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/queryentity/OpEntityLook.kt @@ -5,11 +5,7 @@ import at.petrak.hexcasting.api.casting.castables.ConstMediaAction import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.getEntity import at.petrak.hexcasting.api.casting.iota.Iota -import net.minecraft.world.entity.monster.Phantom -import net.minecraft.world.entity.projectile.AbstractHurtingProjectile -import net.minecraft.world.entity.projectile.Projectile -import net.minecraft.world.entity.projectile.ShulkerBullet -import net.minecraft.world.phys.Vec3 +import at.petrak.hexcasting.api.HexAPI object OpEntityLook : ConstMediaAction { override val argc = 1 @@ -18,16 +14,7 @@ object OpEntityLook : ConstMediaAction { val e = args.getEntity(0, argc) env.assertEntityInRange(e) - var lookDir = e.lookAngle - if (e is Projectile) { // https://bugs.mojang.com/browse/MC/issues/MC-112474 - if (e is AbstractHurtingProjectile || e is ShulkerBullet) - lookDir = Vec3(-1 * lookDir.x, lookDir.y, -1 * lookDir.z) - else - lookDir = Vec3(-1 * lookDir.x, -1 * lookDir.y, lookDir.z) - } else if (e is Phantom) { // https://bugs.mojang.com/browse/MC/issues/MC-134707 - lookDir = Vec3(lookDir.x, -1 * lookDir.y, lookDir.z) - } - + val lookDir = HexAPI.instance().getEntityLookDirSpecial(e) return lookDir.asActionResult } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt index e13b7b3eb8..08e1865d1e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt @@ -1,5 +1,6 @@ package at.petrak.hexcasting.common.casting.actions.spells +import at.petrak.hexcasting.api.HexAPI import at.petrak.hexcasting.api.casting.ParticleSpray import at.petrak.hexcasting.api.casting.RenderedSpell import at.petrak.hexcasting.api.casting.castables.SpellAction @@ -36,7 +37,7 @@ object OpBlink : SpellAction { throw MishapImmuneEntity(immunePassengers.get(0)) } - val dvec = target.lookAngle.scale(delta) + val dvec = HexAPI.instance().getEntityLookDirSpecial(target).scale(delta) val endPos = target.position().add(dvec) if (!HexConfig.server().canTeleportInThisDimension(env.world.dimension())) @@ -65,7 +66,7 @@ object OpBlink : SpellAction { if (!HexConfig.server().canTeleportInThisDimension(env.world.dimension())) return - val delta = target.lookAngle.scale(delta) + val delta = HexAPI.instance().getEntityLookDirSpecial(target).scale(delta) OpTeleport.teleportRespectSticky(target, delta, env.world) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java b/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java index 0ff996b907..f5479ac888 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/impl/HexAPIImpl.java @@ -12,7 +12,11 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.monster.Phantom; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.entity.projectile.ShulkerBullet; import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.ArmorMaterial; import net.minecraft.world.item.ItemStack; @@ -31,6 +35,21 @@ public class HexAPIImpl implements HexAPI { private static final ConcurrentMap, Consumer> SPECIAL_BRAINSWEEPS = new ConcurrentHashMap<>(); + @Override public Vec3 getEntityLookDirSpecial(Entity entity) { + var lookDir = entity.getLookAngle(); + if (entity instanceof AbstractHurtingProjectile || entity instanceof ShulkerBullet) { + // couldn't find a report but these are bugged differently than other projectiles + lookDir = new Vec3(-1 * lookDir.x, lookDir.y, -1 * lookDir.z); + } else if (entity instanceof Projectile) { + // https://bugs.mojang.com/browse/MC/issues/MC-112474 + lookDir = new Vec3(-1 * lookDir.x, -1 * lookDir.y, lookDir.z); + } else if (entity instanceof Phantom) { + // https://bugs.mojang.com/browse/MC/issues/MC-134707 + lookDir = new Vec3(lookDir.x, -1 * lookDir.y, lookDir.z); + } + return lookDir; + } + public void registerSpecialVelocityGetter(EntityType key, EntityVelocityGetter getter) { if (SPECIAL_VELOCITIES.containsKey(key)) { From 47f5e93bd1c7cd7caac67a924dd825206eb70c58 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:27:49 -0400 Subject: [PATCH 3/3] Slightly streamline OpBlink --- .../hexcasting/common/casting/actions/spells/OpBlink.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt index 08e1865d1e..2882984ebd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBlink.kt @@ -15,6 +15,7 @@ import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexTags import at.petrak.hexcasting.common.casting.actions.spells.great.OpTeleport import net.minecraft.world.entity.Entity +import net.minecraft.world.phys.Vec3 import kotlin.math.absoluteValue import kotlin.math.roundToLong @@ -52,7 +53,7 @@ object OpBlink : SpellAction { val targetMiddlePos = target.position().add(0.0, target.eyeHeight / 2.0, 0.0) return SpellAction.Result( - Spell(target, delta), + Spell(target, dvec), (MediaConstants.SHARD_UNIT * delta.absoluteValue * 0.5).roundToLong(), listOf( ParticleSpray.cloud(targetMiddlePos, 2.0, 50), @@ -61,13 +62,12 @@ object OpBlink : SpellAction { ) } - private data class Spell(val target: Entity, val delta: Double) : RenderedSpell { + private data class Spell(val target: Entity, val dvec: Vec3) : RenderedSpell { override fun cast(env: CastingEnvironment) { if (!HexConfig.server().canTeleportInThisDimension(env.world.dimension())) return - val delta = HexAPI.instance().getEntityLookDirSpecial(target).scale(delta) - OpTeleport.teleportRespectSticky(target, delta, env.world) + OpTeleport.teleportRespectSticky(target, dvec, env.world) } } }