From 6500187ca1d9804f5d701b116f730f16a1a04759 Mon Sep 17 00:00:00 2001 From: Kam Date: Sun, 1 Mar 2026 20:57:17 -0500 Subject: [PATCH 1/2] Fix Anchor Launch Point --- .../type/energy/AbilityEnergyProjectile.java | 1 + .../npcs/entity/EntityEnergyProjectile.java | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyProjectile.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyProjectile.java index 91cf185b2..80dfb8a9b 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyProjectile.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyProjectile.java @@ -210,6 +210,7 @@ public abstract class AbilityEnergyProjectile Vec3 spawnPos = getSpawnPosition(caster, index); EnergyDisplayData resolved = projectiles[index].resolveDisplay(displayData); E entity = createEntity(caster, target, spawnPos, resolved, index); + entity.setAnchorData(projectiles[index].anchor); entity.setEffects(this.effects); entity.setSourceAbility(this); return entity; diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java index 59dd346e4..ab5303f28 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java @@ -966,6 +966,10 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { /** * Set the effects list from the ability's configured effects. */ + public void setAnchorData(EnergyAnchorData anchor) { + this.anchorData = anchor != null ? anchor.copy() : new EnergyAnchorData(AnchorPoint.FRONT); + } + public void setEffects(List effects) { if (effects == null || effects.isEmpty()) { this.effects = new ArrayList<>(); @@ -1490,8 +1494,13 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { /** * Set motion along owner look vector or apply explicit fallback values. + * When {@code launchFromAnchor} is true, ray-casts from the owner's eye to find the + * crosshair target point and aims from the projectile's anchor position toward it. */ protected void setMotionAlongLookVectorOrFallback(float speed, double fallbackX, double fallbackY, double fallbackZ) { + if (anchorData.launchFromAnchor && setMotionTowardLookTarget(speed)) { + return; + } if (!setMotionAlongLookVector(speed)) { motionX = fallbackX; motionY = fallbackY; @@ -1499,6 +1508,55 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { } } + /** + * Ray-cast from the owner's eye along the look vector to find the crosshair target point, + * then set motion from the projectile's current position toward that point. + * Used when {@code launchFromAnchor} is true so projectiles fired from offset anchor + * positions converge to the crosshair rather than flying parallel to the look direction. + */ + protected boolean setMotionTowardLookTarget(float speed) { + Entity owner = getOwnerEntity(); + if (!(owner instanceof EntityLivingBase)) return false; + Vec3 look = getOwnerLookVector(); + if (look == null) return false; + + EntityLivingBase livingOwner = (EntityLivingBase) owner; + double eyeX = livingOwner.posX; + double eyeY = livingOwner.posY + livingOwner.getEyeHeight(); + double eyeZ = livingOwner.posZ; + + double maxDist = 200.0; + Vec3 start = Vec3.createVectorHelper(eyeX, eyeY, eyeZ); + Vec3 end = Vec3.createVectorHelper( + eyeX + look.xCoord * maxDist, + eyeY + look.yCoord * maxDist, + eyeZ + look.zCoord * maxDist + ); + + double targetX, targetY, targetZ; + MovingObjectPosition hit = worldObj.rayTraceBlocks(start, end); + if (hit != null && hit.hitVec != null) { + targetX = hit.hitVec.xCoord; + targetY = hit.hitVec.yCoord; + targetZ = hit.hitVec.zCoord; + } else { + targetX = eyeX + look.xCoord * maxDist; + targetY = eyeY + look.yCoord * maxDist; + targetZ = eyeZ + look.zCoord * maxDist; + } + + double dx = targetX - posX; + double dy = targetY - posY; + double dz = targetZ - posZ; + double len = Math.sqrt(dx * dx + dy * dy + dz * dz); + if (len <= 0.0001) return false; + + motionX = (dx / len) * speed; + motionY = (dy / len) * speed; + motionZ = (dz / len) * speed; + return true; + } + /** * Set projectile motion toward a target from a given source point. * From 2448655fc489fa3e6331e5cdc203b0a42acf0383 Mon Sep 17 00:00:00 2001 From: Kam Date: Sun, 1 Mar 2026 21:07:52 -0500 Subject: [PATCH 2/2] 1.11 Beta 12 --- build.gradle | 2 +- src/main/java/noppes/npcs/CustomNpcs.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c4783606b..c6006229c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { id 'idea' } -version = "1.11-beta11" +version = "1.11-beta12" group= "kamkeel.customnpc-plus" archivesBaseName = "CustomNPC-Plus" diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index 32ac9b796..475416f08 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -124,7 +124,7 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; -@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11-beta11") +@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11-beta12") public class CustomNpcs { @SidedProxy(clientSide = "noppes.npcs.client.ClientProxy", serverSide = "noppes.npcs.CommonProxy")