From c121d0c4e21dd5afeafad0fc1c4760a525e35e9f Mon Sep 17 00:00:00 2001 From: somehussar <148253652+somehussar@users.noreply.github.com> Date: Sat, 21 Feb 2026 00:03:48 +0100 Subject: [PATCH] Fix missing spawndata. --- .../kamkeel/npcs/network/PacketHandler.java | 20 +-- .../npcs/network/enums/EnumDataPacket.java | 1 + .../packets/data/RequestProperSpawnData.java | 119 ++++++++++++++++++ .../noppes/npcs/client/ClientTickHandler.java | 4 + .../npcs/entity/EntityNPCInterface.java | 11 ++ 5 files changed, 137 insertions(+), 18 deletions(-) create mode 100644 src/main/java/kamkeel/npcs/network/packets/data/RequestProperSpawnData.java diff --git a/src/main/java/kamkeel/npcs/network/PacketHandler.java b/src/main/java/kamkeel/npcs/network/PacketHandler.java index 766210559..8e784b5b8 100644 --- a/src/main/java/kamkeel/npcs/network/PacketHandler.java +++ b/src/main/java/kamkeel/npcs/network/PacketHandler.java @@ -8,24 +8,7 @@ import cpw.mods.fml.common.network.internal.FMLProxyPacket; import cpw.mods.fml.relauncher.Side; import io.netty.buffer.ByteBuf; import kamkeel.npcs.network.enums.EnumChannelType; -import kamkeel.npcs.network.packets.data.AchievementPacket; -import kamkeel.npcs.network.packets.data.ChatAlertPacket; -import kamkeel.npcs.network.packets.data.ChatBubblePacket; -import kamkeel.npcs.network.packets.data.ClonerPacket; -import kamkeel.npcs.network.packets.data.ConfigCommandPacket; -import kamkeel.npcs.network.packets.data.DisableMouseInputPacket; -import kamkeel.npcs.network.packets.data.LoginPacket; -import kamkeel.npcs.network.packets.data.MarkDataPacket; -import kamkeel.npcs.network.packets.data.OverlayQuestTrackingPacket; -import kamkeel.npcs.network.packets.data.ParticlePacket; -import kamkeel.npcs.network.packets.data.PlayerDataInfoPacket; -import kamkeel.npcs.network.packets.data.PlayerUpdateSkinOverlaysPacket; -import kamkeel.npcs.network.packets.data.QuestCompletionPacket; -import kamkeel.npcs.network.packets.data.ScrollSelectedPacket; -import kamkeel.npcs.network.packets.data.SoundManagementPacket; -import kamkeel.npcs.network.packets.data.SwingPlayerArmPacket; -import kamkeel.npcs.network.packets.data.UpdateAnimationsPacket; -import kamkeel.npcs.network.packets.data.VillagerListPacket; +import kamkeel.npcs.network.packets.data.*; import kamkeel.npcs.network.packets.data.ability.AbilityCooldownSyncPacket; import kamkeel.npcs.network.packets.data.ability.AbilityHotbarSyncPacket; import kamkeel.npcs.network.packets.data.ability.PlayerAbilityStatePacket; @@ -583,6 +566,7 @@ public class PacketHandler { DATA_PACKET.registerPacket(new DialogPacket()); DATA_PACKET.registerPacket(new RolePacket()); DATA_PACKET.registerPacket(new WeaponNpcPacket()); + DATA_PACKET.registerPacket(new RequestProperSpawnData()); // Data | Script Packets DATA_PACKET.registerPacket(new ScriptedParticlePacket()); diff --git a/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java b/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java index bc6d7d1f9..ec351a2c9 100644 --- a/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java +++ b/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java @@ -23,6 +23,7 @@ public enum EnumDataPacket { DELETE_NPC, CLONE_NPC, WEAPON_NPC, + REQUEST_SPAWN_DATA, // Data SCROLL_LIST, diff --git a/src/main/java/kamkeel/npcs/network/packets/data/RequestProperSpawnData.java b/src/main/java/kamkeel/npcs/network/packets/data/RequestProperSpawnData.java new file mode 100644 index 000000000..afd013a74 --- /dev/null +++ b/src/main/java/kamkeel/npcs/network/packets/data/RequestProperSpawnData.java @@ -0,0 +1,119 @@ +package kamkeel.npcs.network.packets.data; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import kamkeel.npcs.network.AbstractPacket; +import kamkeel.npcs.network.PacketChannel; +import kamkeel.npcs.network.PacketClient; +import kamkeel.npcs.network.PacketHandler; +import kamkeel.npcs.network.enums.EnumDataPacket; +import kamkeel.npcs.network.packets.data.npc.UpdateNpcPacket; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.LogWriter; +import noppes.npcs.entity.EntityNPCInterface; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class RequestProperSpawnData extends AbstractPacket { + public static final String packetName = "Data|SpawnData"; + private static final int BATCH_LIMIT = 5; + + @SideOnly(Side.CLIENT) + private static final Set entitiesToFix = new HashSet<>(); + @SideOnly(Side.CLIENT) + private static long lastBatchAttemptMillis = 0; + + private int entityId; + + public RequestProperSpawnData() {} + + @SideOnly(Side.CLIENT) + public RequestProperSpawnData(int entityId) { + this.entityId = entityId; + } + + public static void clear() { + entitiesToFix.clear(); + } + + @Override + public Enum getType() { + return EnumDataPacket.REQUEST_SPAWN_DATA; + } + + @Override + public PacketChannel getChannel() { + return PacketHandler.DATA_PACKET; + } + + @Override + @SideOnly(Side.CLIENT) + public void sendData(ByteBuf out) throws IOException { + out.writeInt(this.entityId); + } + + @Override + public void receiveData(ByteBuf in, EntityPlayer player) throws IOException { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) + return; + + int entityId = in.readInt(); + Entity entity = Minecraft.getMinecraft().theWorld.getEntityByID(entityId); + if (entity instanceof EntityNPCInterface) { + EntityNPCInterface npc = (EntityNPCInterface) entity; + NBTTagCompound compound = npc.writeSpawnData(); + compound.setInteger("EntityId", npc.getEntityId()); + PacketHandler.Instance.sendToPlayer(new UpdateNpcPacket(compound), (EntityPlayerMP) player); + } + } + + @SideOnly(Side.CLIENT) + public static void reportMissingData(EntityNPCInterface npc) { + int entityID = npc.getEntityId(); + + if (npc.immediateSpawnDataFixAttempts++ < 3) { + PacketClient.sendClient(new RequestProperSpawnData(entityID)); + } else { + entitiesToFix.add(entityID); + } + } + + @SideOnly(Side.CLIENT) + public static boolean canDoBatchUpdate() { + return System.currentTimeMillis() - lastBatchAttemptMillis >= 5000; + } + + @SideOnly(Side.CLIENT) + public static void handleBacklog() { + Minecraft mc = Minecraft.getMinecraft(); + if (mc == null || mc.theWorld == null || mc.thePlayer == null) + return; + + if (entitiesToFix.isEmpty()) + return; + // Remove entity checks if they're no longer loaded + entitiesToFix.removeIf( value -> !(Minecraft.getMinecraft().theWorld.getEntityByID(value) instanceof EntityNPCInterface) ); + + Iterator it = entitiesToFix.iterator(); + int count = 0; + + while (it.hasNext() && count < BATCH_LIMIT) { + PacketClient.sendClient(new RequestProperSpawnData(it.next())); + it.remove(); + count++; + } + + if (count != 0) { + lastBatchAttemptMillis = System.currentTimeMillis(); + } + } +} diff --git a/src/main/java/noppes/npcs/client/ClientTickHandler.java b/src/main/java/noppes/npcs/client/ClientTickHandler.java index 1c16de390..a23a9195c 100644 --- a/src/main/java/noppes/npcs/client/ClientTickHandler.java +++ b/src/main/java/noppes/npcs/client/ClientTickHandler.java @@ -9,6 +9,7 @@ import kamkeel.npcs.client.renderer.lightning.LightningBolt; import kamkeel.npcs.controllers.AbilityController; import kamkeel.npcs.controllers.data.telegraph.TelegraphManager; import kamkeel.npcs.network.PacketClient; +import kamkeel.npcs.network.packets.data.RequestProperSpawnData; import kamkeel.npcs.network.packets.player.CheckPlayerValue; import kamkeel.npcs.network.packets.player.InputDevicePacket; import kamkeel.npcs.network.packets.player.ScreenSizePacket; @@ -59,6 +60,7 @@ public class ClientTickHandler { if (mc.theWorld == null) { ClientCacheHandler.clearCache(); ClientAbilityState.reset(); + RequestProperSpawnData.clear(); } this.prevWorld = mc.theWorld; } @@ -199,6 +201,8 @@ public class ClientTickHandler { return; if (mc.theWorld.getTotalWorldTime() % 20 == 0) { // Update every second + if (RequestProperSpawnData.canDoBatchUpdate()) + RequestProperSpawnData.handleBacklog(); updateCompassMarks(); } } diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index 187ce583d..6cfb59553 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -68,6 +68,7 @@ import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.event.ServerChatEvent; import noppes.npcs.CustomItems; @@ -229,6 +230,9 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti public FlyingMoveHelper flyMoveHelper = new FlyingMoveHelper(this); public PathNavigate flyNavigator = new PathNavigateFlying(this, worldObj); + @SideOnly(Side.CLIENT) + public int immediateSpawnDataFixAttempts = 0; + public EntityNPCInterface(World world) { super(world); try { @@ -1829,10 +1833,17 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti try { readSpawnData(ByteBufUtils.readNBT(buf)); } catch (IOException e) { + RequestProperSpawnData.reportMissingData(this); } } public void readSpawnData(NBTTagCompound compound) { + if ((compound.hasNoTags() || !compound.hasKey("MaxHealth", Constants.NBT.TAG_DOUBLE))) { + RequestProperSpawnData.reportMissingData(this); + return; + } + + immediateSpawnDataFixAttempts = 0; stats.maxHealth = compound.getDouble("MaxHealth"); ais.setWalkingSpeed(compound.getInteger("Speed")); stats.hideKilledBody = compound.getBoolean("DeadBody");