mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 04:17:36 +00:00
Reflection Barrier Fixes
This commit is contained in:
1 parent
92cfbbcc9d
commit
47ebc2889f
8 files changed
+288
-1
No files matched your search
+16
@@ -18,6 +18,7 @@ import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import kamkeel.npcs.network.packets.data.energycharge.EnergyChargeRemovePacket;
|
||||
import kamkeel.npcs.network.packets.data.energycharge.EnergyChargeSpawnPacket;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
@@ -341,6 +342,21 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
spawnedCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific entity from this ability's tracking.
|
||||
* Used when a projectile is reflected — it no longer belongs to this ability,
|
||||
* so the ability should stop waiting for it and free the caster.
|
||||
*/
|
||||
public void detachEntity(Entity entity) {
|
||||
if (entities == null || entity == null) return;
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
if (entities[i] == entity) {
|
||||
entities[i] = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadyForBurstCompletion(int activeTick) {
|
||||
return fireDelay <= 0 || activeTick >= fireDelay * (projectileCount - 1);
|
||||
|
||||
@@ -637,6 +637,50 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
return trailFadeTime;
|
||||
}
|
||||
|
||||
// ==================== REFLECTION ====================
|
||||
|
||||
@Override
|
||||
protected boolean reflectFromBarrier(EntityAbilityBarrier barrier, float reflectStrengthPct) {
|
||||
boolean reflected = super.reflectFromBarrier(barrier, reflectStrengthPct);
|
||||
if (reflected) {
|
||||
// Switch to FREE_TRAIL: detach from caster (tail-less), trail fades out.
|
||||
setBeamMode(BeamMode.FREE_TRAIL);
|
||||
|
||||
// Reset origin to the reflection point (current head position).
|
||||
startX = posX;
|
||||
startY = posY;
|
||||
startZ = posZ;
|
||||
resetHeadOffsets();
|
||||
resetTrailStorage();
|
||||
|
||||
// Disable homing — reflected beams fly straight.
|
||||
homingData.setHoming(false);
|
||||
setTargetEntityId(-1);
|
||||
}
|
||||
return reflected;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeProjectileReflectionData(NBTTagCompound nbt) {
|
||||
nbt.setByte("BeamMode", (byte) beamMode.ordinal());
|
||||
nbt.setDouble("StartX", startX);
|
||||
nbt.setDouble("StartY", startY);
|
||||
nbt.setDouble("StartZ", startZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyProjectileReflectionData(NBTTagCompound nbt) {
|
||||
int mode = nbt.getByte("BeamMode");
|
||||
setBeamMode(mode >= 0 && mode < BeamMode.values().length ? BeamMode.values()[mode] : BeamMode.FREE_TRAIL);
|
||||
startX = nbt.getDouble("StartX");
|
||||
startY = nbt.getDouble("StartY");
|
||||
startZ = nbt.getDouble("StartZ");
|
||||
resetHeadOffsets();
|
||||
resetTrailStorage();
|
||||
homingData.setHoming(false);
|
||||
setTargetEntityId(-1);
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
|
||||
@@ -395,6 +395,32 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
return lastTravelYaw;
|
||||
}
|
||||
|
||||
// ==================== REFLECTION ====================
|
||||
|
||||
@Override
|
||||
protected boolean reflectFromBarrier(EntityAbilityBarrier barrier, float reflectStrengthPct) {
|
||||
boolean reflected = super.reflectFromBarrier(barrier, reflectStrengthPct);
|
||||
if (reflected) {
|
||||
// Disable boomerang on reflected discs — the original owner is no longer
|
||||
// relevant and the return-to-owner logic causes erratic flight paths.
|
||||
this.boomerang = false;
|
||||
this.returning = false;
|
||||
}
|
||||
return reflected;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeProjectileReflectionData(NBTTagCompound nbt) {
|
||||
nbt.setBoolean("Boomerang", boomerang);
|
||||
nbt.setBoolean("Returning", returning);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyProjectileReflectionData(NBTTagCompound nbt) {
|
||||
boomerang = nbt.getBoolean("Boomerang");
|
||||
returning = nbt.getBoolean("Returning");
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
|
||||
@@ -134,9 +134,10 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
// After reflection, hold trajectory briefly so the rebound is visible.
|
||||
// Once reflected, never resume owner-tracking — the laser flies in a fixed direction.
|
||||
if (reflectedLockTicks > 0) {
|
||||
reflectedLockTicks--;
|
||||
} else {
|
||||
} else if (!reflected) {
|
||||
// Track owner's anchor position and rotation each tick
|
||||
// so the laser follows the NPC's facing direction
|
||||
updateLaserOriginAndDirection();
|
||||
@@ -717,6 +718,41 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.endZ = posZ;
|
||||
}
|
||||
|
||||
// ==================== REFLECTION SYNC ====================
|
||||
|
||||
@Override
|
||||
protected void writeProjectileReflectionData(NBTTagCompound nbt) {
|
||||
nbt.setDouble("DirX", dirX);
|
||||
nbt.setDouble("DirY", dirY);
|
||||
nbt.setDouble("DirZ", dirZ);
|
||||
nbt.setDouble("StartX", startX);
|
||||
nbt.setDouble("StartY", startY);
|
||||
nbt.setDouble("StartZ", startZ);
|
||||
nbt.setFloat("CurrentLength", currentLength);
|
||||
nbt.setDouble("EndX", endX);
|
||||
nbt.setDouble("EndY", endY);
|
||||
nbt.setDouble("EndZ", endZ);
|
||||
nbt.setInteger("ReflectedLockTicks", reflectedLockTicks);
|
||||
nbt.setBoolean("FullyExtended", fullyExtended);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyProjectileReflectionData(NBTTagCompound nbt) {
|
||||
dirX = nbt.getDouble("DirX");
|
||||
dirY = nbt.getDouble("DirY");
|
||||
dirZ = nbt.getDouble("DirZ");
|
||||
startX = nbt.getDouble("StartX");
|
||||
startY = nbt.getDouble("StartY");
|
||||
startZ = nbt.getDouble("StartZ");
|
||||
currentLength = nbt.getFloat("CurrentLength");
|
||||
endX = nbt.getDouble("EndX");
|
||||
endY = nbt.getDouble("EndY");
|
||||
endZ = nbt.getDouble("EndZ");
|
||||
reflectedLockTicks = nbt.getInteger("ReflectedLockTicks");
|
||||
fullyExtended = nbt.getBoolean("FullyExtended");
|
||||
ticksSinceFullExtension = 0;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package kamkeel.npcs.entity;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityEnergyProjectile;
|
||||
import kamkeel.npcs.controllers.data.ability.data.effect.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.enums.AnchorPoint;
|
||||
import kamkeel.npcs.controllers.data.ability.enums.HitType;
|
||||
@@ -12,6 +13,7 @@ import kamkeel.npcs.controllers.data.ability.data.energy.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLightningData;
|
||||
import kamkeel.npcs.network.packets.data.energy.ProjectileReflectPacket;
|
||||
import kamkeel.npcs.network.packets.data.energyexplosion.EnergyExplosionSpawnPacket;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.block.Block;
|
||||
@@ -120,6 +122,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
protected int targetEntityId = -1;
|
||||
|
||||
// ==================== STATE ====================
|
||||
protected boolean reflected = false; // Set after barrier reflection; prevents owner-tracking on reflected projectiles
|
||||
protected boolean hasHit = false;
|
||||
protected int hitCount = 0;
|
||||
protected final Set<Integer> hitOnceEntities = new HashSet<Integer>();
|
||||
@@ -427,6 +430,8 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
if (hitOutcome.shouldReflect()) {
|
||||
if (!reflectFromBarrier(barrier, hitOutcome.reflectStrengthPct)) {
|
||||
beginBarrierImpactPause(true, barrier);
|
||||
} else {
|
||||
sendReflectionSync();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -498,6 +503,14 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
barrierImpactPauseTicks = 0;
|
||||
barrierImpactDestroyOnResume = false;
|
||||
|
||||
// Detach from source ability BEFORE changing ownership.
|
||||
// This lets the ability see the projectile as gone and free the caster
|
||||
// (e.g., release movement/rotation locks on the player).
|
||||
if (sourceAbility instanceof AbilityEnergyProjectile) {
|
||||
((AbilityEnergyProjectile<?>) sourceAbility).detachEntity(this);
|
||||
}
|
||||
sourceAbility = null;
|
||||
|
||||
Entity barrierOwner = barrier.getOwnerEntity();
|
||||
if (barrierOwner != null) {
|
||||
setOwnerEntityId(barrierOwner.getEntityId());
|
||||
@@ -517,9 +530,75 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
hitOnceEntities.clear();
|
||||
lastHitTickByEntity.clear();
|
||||
hitCount = 0;
|
||||
reflected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== REFLECTION SYNC ====================
|
||||
|
||||
/**
|
||||
* Write reflection state for client sync.
|
||||
* Subclasses should override writeProjectileReflectionData for type-specific fields.
|
||||
*/
|
||||
public NBTTagCompound writeReflectionData() {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setInteger("OwnerId", ownerEntityId);
|
||||
nbt.setDouble("PosX", posX);
|
||||
nbt.setDouble("PosY", posY);
|
||||
nbt.setDouble("PosZ", posZ);
|
||||
nbt.setDouble("MotionX", motionX);
|
||||
nbt.setDouble("MotionY", motionY);
|
||||
nbt.setDouble("MotionZ", motionZ);
|
||||
nbt.setInteger("InnerColor", getInnerColor());
|
||||
nbt.setInteger("OuterColor", getOuterColor());
|
||||
nbt.setBoolean("Reflected", reflected);
|
||||
writeProjectileReflectionData(nbt);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply reflection state from server sync.
|
||||
* Subclasses should override applyProjectileReflectionData for type-specific fields.
|
||||
*/
|
||||
public void applyReflectionData(NBTTagCompound nbt) {
|
||||
ownerEntityId = nbt.getInteger("OwnerId");
|
||||
double px = nbt.getDouble("PosX");
|
||||
double py = nbt.getDouble("PosY");
|
||||
double pz = nbt.getDouble("PosZ");
|
||||
setPosition(px, py, pz);
|
||||
motionX = nbt.getDouble("MotionX");
|
||||
motionY = nbt.getDouble("MotionY");
|
||||
motionZ = nbt.getDouble("MotionZ");
|
||||
setInnerColor(nbt.getInteger("InnerColor"));
|
||||
setOuterColor(nbt.getInteger("OuterColor"));
|
||||
reflected = nbt.getBoolean("Reflected");
|
||||
syncPositionStateToCurrent(true);
|
||||
hitOnceEntities.clear();
|
||||
lastHitTickByEntity.clear();
|
||||
hitCount = 0;
|
||||
applyProjectileReflectionData(nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass hook: write type-specific reflection data.
|
||||
*/
|
||||
protected void writeProjectileReflectionData(NBTTagCompound nbt) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass hook: apply type-specific reflection data on client.
|
||||
*/
|
||||
protected void applyProjectileReflectionData(NBTTagCompound nbt) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send reflection state to all tracking clients.
|
||||
*/
|
||||
protected void sendReflectionSync() {
|
||||
if (worldObj == null || worldObj.isRemote) return;
|
||||
ProjectileReflectPacket.sendToTracking(this, writeReflectionData());
|
||||
}
|
||||
|
||||
protected double[] getBarrierImpactNormal(EntityAbilityBarrier barrier, double velocityX, double velocityY, double velocityZ) {
|
||||
if (barrier instanceof EntityAbilityDome) {
|
||||
EntityAbilityDome dome = (EntityAbilityDome) barrier;
|
||||
@@ -2187,6 +2266,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
this.startZ = nbt.getDouble("StartZ");
|
||||
|
||||
this.targetEntityId = nbt.getInteger("TargetId");
|
||||
this.reflected = nbt.getBoolean("Reflected");
|
||||
|
||||
this.motionX = nbt.getDouble("MotionX");
|
||||
this.motionY = nbt.getDouble("MotionY");
|
||||
@@ -2243,6 +2323,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
nbt.setDouble("StartZ", startZ);
|
||||
|
||||
nbt.setInteger("TargetId", targetEntityId);
|
||||
nbt.setBoolean("Reflected", reflected);
|
||||
|
||||
nbt.setDouble("MotionX", motionX);
|
||||
nbt.setDouble("MotionY", motionY);
|
||||
|
||||
@@ -39,6 +39,7 @@ import kamkeel.npcs.network.packets.data.script.ScriptedParticlePacket;
|
||||
import kamkeel.npcs.network.packets.data.energycharge.EnergyChargeRemovePacket;
|
||||
import kamkeel.npcs.network.packets.data.energycharge.EnergyChargeSpawnPacket;
|
||||
import kamkeel.npcs.network.packets.data.energyexplosion.EnergyExplosionSpawnPacket;
|
||||
import kamkeel.npcs.network.packets.data.energy.ProjectileReflectPacket;
|
||||
import kamkeel.npcs.network.packets.data.telegraph.TelegraphRemovePacket;
|
||||
import kamkeel.npcs.network.packets.data.telegraph.TelegraphSpawnPacket;
|
||||
import kamkeel.npcs.network.packets.player.AuctionActionPacket;
|
||||
@@ -592,6 +593,7 @@ public class PacketHandler {
|
||||
DATA_PACKET.registerPacket(new EnergyChargeSpawnPacket());
|
||||
DATA_PACKET.registerPacket(new EnergyChargeRemovePacket());
|
||||
DATA_PACKET.registerPacket(new EnergyExplosionSpawnPacket());
|
||||
DATA_PACKET.registerPacket(new ProjectileReflectPacket());
|
||||
DATA_PACKET.registerPacket(new PlayerAbilitySyncPacket());
|
||||
DATA_PACKET.registerPacket(new PlayerAbilityStatePacket());
|
||||
DATA_PACKET.registerPacket(new AbilityHotbarSyncPacket());
|
||||
|
||||
@@ -76,4 +76,7 @@ public enum EnumDataPacket {
|
||||
|
||||
// Energy Explosion Preview
|
||||
ENERGY_EXPLOSION_SPAWN,
|
||||
|
||||
// Energy Projectile Reflection Sync
|
||||
PROJECTILE_REFLECT,
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package kamkeel.npcs.network.packets.data.energy;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.enums.EnumDataPacket;
|
||||
import kamkeel.npcs.util.ByteBufUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Syncs projectile reflection state to all tracking clients.
|
||||
* Sent server→client after a successful barrier reflection so the client
|
||||
* can update ownerEntityId, position, motion, colors, and type-specific
|
||||
* reflection data (beam mode, laser direction, disc boomerang, etc.).
|
||||
*/
|
||||
public final class ProjectileReflectPacket extends AbstractPacket {
|
||||
public static final String packetName = "Data|ProjectileReflect";
|
||||
|
||||
private int entityId;
|
||||
private NBTTagCompound reflectData;
|
||||
|
||||
public ProjectileReflectPacket() {
|
||||
}
|
||||
|
||||
public ProjectileReflectPacket(int entityId, NBTTagCompound reflectData) {
|
||||
this.entityId = entityId;
|
||||
this.reflectData = reflectData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum getType() {
|
||||
return EnumDataPacket.PROJECTILE_REFLECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.DATA_PACKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
out.writeInt(entityId);
|
||||
ByteBufUtils.writeNBT(out, reflectData);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
|
||||
int id = in.readInt();
|
||||
NBTTagCompound nbt = ByteBufUtils.readNBT(in);
|
||||
if (nbt == null) return;
|
||||
|
||||
World world = Minecraft.getMinecraft().theWorld;
|
||||
if (world == null) return;
|
||||
|
||||
Entity entity = world.getEntityByID(id);
|
||||
if (entity instanceof EntityEnergyProjectile) {
|
||||
((EntityEnergyProjectile) entity).applyReflectionData(nbt);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendToTracking(EntityEnergyProjectile projectile, NBTTagCompound reflectData) {
|
||||
if (projectile == null || reflectData == null) return;
|
||||
PacketHandler.Instance.sendTracking(
|
||||
new ProjectileReflectPacket(projectile.getEntityId(), reflectData),
|
||||
projectile
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user