diff --git a/src/main/java/kamkeel/npcs/controllers/SyncController.java b/src/main/java/kamkeel/npcs/controllers/SyncController.java index b4119ec8d..eed423ea1 100644 --- a/src/main/java/kamkeel/npcs/controllers/SyncController.java +++ b/src/main/java/kamkeel/npcs/controllers/SyncController.java @@ -4,8 +4,6 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import kamkeel.npcdbc.network.DBCPacketHandler; -import kamkeel.npcdbc.network.packets.get.DBCInfoSyncPacket; import kamkeel.npcs.addon.DBCAddon; import kamkeel.npcs.controllers.sync.SyncHandler; import kamkeel.npcs.controllers.sync.SyncRegistry; @@ -26,7 +24,6 @@ import noppes.npcs.LogWriter; import noppes.npcs.client.ClientCacheHandler; import noppes.npcs.controllers.data.PlayerData; -import java.io.IOException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -146,7 +143,7 @@ public class SyncController { * revision state. Used after the login handshake and by server-side callers * that need to refresh a player's global cached sync families. */ - public static void syncPlayer(EntityPlayerMP player) { + public static void dispatchSyncForAllTypes(EntityPlayerMP player) { PlayerSyncState state = playerSyncState.computeIfAbsent(player.getUniqueID(), PlayerSyncState::new); // Registry-driven login iteration: iterate only cached types @@ -194,7 +191,7 @@ public class SyncController { else // The client and server agree on identity, so seed the stored state from the report. state.applyHandshake(clientRevisions); - syncPlayer(player); + dispatchSyncForAllTypes(player); } @@ -217,21 +214,42 @@ public class SyncController { // ═══════════════════════════════════════════════════════════════════════ // Server-side dispatchers — registry-driven // ═══════════════════════════════════════════════════════════════════════ + public static void syncUpdate(SyncType type, NBTTagCompound compound) { + Map revisions = invalidateCaches(type); + int revision = getRequestedInvalidationRevision(type, revisions); + PacketHandler.Instance.sendToAll(new SyncPacket(type, EnumSyncAction.UPDATE, -1, null, revision, compound)); + updateAllPlayerRevisions(revisions); + } - public static void syncRemove(SyncType syncType, int id) { - Map revisions = invalidateCaches(syncType); - int revision = getRequestedInvalidationRevision(syncType, revisions); - PacketHandler.Instance.sendToAll(new SyncPacket(syncType, EnumSyncAction.REMOVE, id, revision, new NBTTagCompound())); + public static void syncUpdate(SyncType type, String key, NBTTagCompound compound) { + Map revisions = invalidateCaches(type); + int revision = getRequestedInvalidationRevision(type, revisions); + PacketHandler.Instance.sendToAll(new SyncPacket(type, EnumSyncAction.UPDATE, -1, key, revision, compound)); updateAllPlayerRevisions(revisions); } public static void syncUpdate(SyncType type, int cat, NBTTagCompound compound) { Map revisions = invalidateCaches(type); int revision = getRequestedInvalidationRevision(type, revisions); - PacketHandler.Instance.sendToAll(new SyncPacket(type, EnumSyncAction.UPDATE, cat, revision, compound)); + PacketHandler.Instance.sendToAll(new SyncPacket(type, EnumSyncAction.UPDATE, cat, null, revision, compound)); updateAllPlayerRevisions(revisions); } + public static void syncRemove(SyncType syncType, String key) { + Map revisions = invalidateCaches(syncType); + int revision = getRequestedInvalidationRevision(syncType, revisions); + PacketHandler.Instance.sendToAll(new SyncPacket(syncType, EnumSyncAction.REMOVE, -1, key, revision, null)); + updateAllPlayerRevisions(revisions); + } + + public static void syncRemove(SyncType syncType, int id) { + Map revisions = invalidateCaches(syncType); + int revision = getRequestedInvalidationRevision(syncType, revisions); + PacketHandler.Instance.sendToAll(new SyncPacket(syncType, EnumSyncAction.REMOVE, id, null, revision, null)); + updateAllPlayerRevisions(revisions); + } + + // ═══════════════════════════════════════════════════════════════════════ // Client-side handlers — registry-driven handler delegation // ═══════════════════════════════════════════════════════════════════════ @@ -250,11 +268,12 @@ public class SyncController { } @SideOnly(Side.CLIENT) - public static void clientHandleUpdate(SyncType syncType, int category_id, int revision, NBTTagCompound compound) { + public static void clientHandleUpdate(SyncType syncType, int id, String key, int revision, NBTTagCompound compound) { SyncHandler handler = SyncRegistry.getHandler(syncType); if (handler == null) return; try { - handler.clientHandleUpdate(compound, category_id); + handler.clientHandleUpdate(compound, id); + handler.clientHandleUpdate(compound, key); } catch (Exception e) { LogWriter.error("[SyncController] Failed to handle UPDATE for sync type " + syncType, e); } @@ -263,12 +282,12 @@ public class SyncController { } @SideOnly(Side.CLIENT) - public static void clientHandleRemove(SyncType syncType, int id, int revision, NBTTagCompound compound) { + public static void clientHandleRemove(SyncType syncType, int id, String key, int revision) { SyncHandler handler = SyncRegistry.getHandler(syncType); if (handler == null) return; try { handler.clientHandleRemove(id); - handler.clientHandleRemove(compound); + handler.clientHandleRemove(key); } catch (Exception e) { LogWriter.error("[SyncController] Failed to handle REMOVE for sync type " + syncType, e); } diff --git a/src/main/java/kamkeel/npcs/controllers/sync/SyncHandler.java b/src/main/java/kamkeel/npcs/controllers/sync/SyncHandler.java index 5cfe5e7a6..ef0ce0bda 100644 --- a/src/main/java/kamkeel/npcs/controllers/sync/SyncHandler.java +++ b/src/main/java/kamkeel/npcs/controllers/sync/SyncHandler.java @@ -52,8 +52,26 @@ public interface SyncHandler { * @param fullCompound the full serialized dataset from {@link #serializeAll()} */ @SideOnly(Side.CLIENT) - void clientHandleReload(NBTTagCompound fullCompound); + default void clientHandleReload(NBTTagCompound fullCompound){ + // No-op: type does not support individual updates + } + /** + * Handle an UPDATE action on the client. + * Deserialize a single object and insert/replace it in the client-side data. + * + *

Default: no-op. Types that don't support individual updates + * use {@code syncAll()} for full reload instead.

+ * + * @param compound the serialized single object + * @param categoryKey the parent category key (null if not applicable) + */ + @SideOnly(Side.CLIENT) + default void clientHandleUpdate(NBTTagCompound compound, String categoryKey) { + // No-op: type does not support individual updates + } + + /** * Handle an UPDATE action on the client. Deserialize a single * entity and insert/replace it in the client-side data. @@ -75,7 +93,7 @@ public interface SyncHandler { * Int-keyed handlers should override {@link #clientHandleRemove(int)} instead. */ @SideOnly(Side.CLIENT) - default void clientHandleRemove(NBTTagCompound compound) { + default void clientHandleRemove(String key) { } /** diff --git a/src/main/java/kamkeel/npcs/network/packets/data/large/SyncPacket.java b/src/main/java/kamkeel/npcs/network/packets/data/large/SyncPacket.java index 3ebe78712..8ef77a69a 100644 --- a/src/main/java/kamkeel/npcs/network/packets/data/large/SyncPacket.java +++ b/src/main/java/kamkeel/npcs/network/packets/data/large/SyncPacket.java @@ -28,6 +28,7 @@ public final class SyncPacket extends LargeAbstractPacket { private EnumSyncAction enumSyncAction; private NBTTagCompound syncData; private int operationID; + private String operationKey; private int revision = -1; private byte[] cachedPayload; private byte[][] cachedChunks; @@ -36,14 +37,15 @@ public final class SyncPacket extends LargeAbstractPacket { } public SyncPacket(SyncType syncType, EnumSyncAction enumSyncAction, int catId, NBTTagCompound syncData) { - this(syncType, enumSyncAction, catId, -1, syncData); + this(syncType, enumSyncAction, catId, null, -1, syncData); } - public SyncPacket(SyncType syncType, EnumSyncAction enumSyncAction, int catId, int revision, NBTTagCompound syncData) { + public SyncPacket(SyncType syncType, EnumSyncAction enumSyncAction, int operationId, String operationKey, int revision, NBTTagCompound syncData) { this.syncType = syncType; this.enumSyncAction = enumSyncAction; this.syncData = syncData; - this.operationID = catId; + this.operationID = operationId; + this.operationKey = operationKey; this.revision = revision; } @@ -72,13 +74,19 @@ public final class SyncPacket extends LargeAbstractPacket { return cachedPayload; } + boolean hasKey = operationKey != null; + boolean hasNbt = syncData != null; + ByteBuf buffer = Unpooled.buffer(); try { buffer.writeInt(syncType.ordinal()); buffer.writeInt(enumSyncAction.ordinal()); buffer.writeInt(operationID); + buffer.writeBoolean(hasKey); + if (hasKey) ByteBufUtils.writeString(buffer, operationKey); buffer.writeInt(revision); - ByteBufUtils.writeBigNBT(buffer, syncData); + buffer.writeBoolean(hasNbt); + if (hasNbt) ByteBufUtils.writeBigNBT(buffer, syncData); byte[] bytes = new byte[buffer.readableBytes()]; buffer.readBytes(bytes); @@ -126,39 +134,32 @@ public final class SyncPacket extends LargeAbstractPacket { int syncTypeOrdinal = data.readInt(); int syncActionOrdinal = data.readInt(); - int categoryID = data.readInt(); - int incomingRevision = data.readInt(); + operationID = data.readInt(); + if (data.readBoolean()) operationKey = ByteBufUtils.readString(data); + revision = data.readInt(); + if (data.readBoolean()) syncData = ByteBufUtils.readBigNBT(data); - SyncType type = SyncType.byOrdinal(syncTypeOrdinal); - if (type == null) { + + syncType = SyncType.byOrdinal(syncTypeOrdinal); + if (syncType == null) { LogWriter.error("[SyncPacket] Unknown sync type ordinal: " + syncTypeOrdinal + "; skipping"); return; } + EnumSyncAction action = EnumSyncAction.values()[syncActionOrdinal]; - try { - NBTTagCompound tag = ByteBufUtils.readBigNBT(data); - handleSyncPacketClient(type, action, categoryID, incomingRevision, tag); - } catch (RuntimeException e) { - LogWriter.error(String.format("Attempted to Sync %s but it was too big", type.toString())); - } + handleSync(syncType, action, operationID, operationKey, revision, syncData); } - private void handleSyncPacketClient( - SyncType syncType, - EnumSyncAction enumSyncAction, - int id, - int incomingRevision, - NBTTagCompound data - ) { - switch (enumSyncAction) { + private void handleSync(SyncType type, EnumSyncAction action, int id, String key, int revision, NBTTagCompound data) { + switch (action) { case RELOAD: - SyncController.clientHandleAll(syncType, incomingRevision, data); + SyncController.clientHandleAll(type, revision, data); break; case UPDATE: - SyncController.clientHandleUpdate(syncType, id, incomingRevision, data); + SyncController.clientHandleUpdate(type, id, key, revision, data); break; case REMOVE: - SyncController.clientHandleRemove(syncType, id, incomingRevision, data); + SyncController.clientHandleRemove(type, id, key, revision); break; } } diff --git a/src/main/java/noppes/npcs/NoppesUtilServer.java b/src/main/java/noppes/npcs/NoppesUtilServer.java index 53dbfb239..dba0c27c1 100644 --- a/src/main/java/noppes/npcs/NoppesUtilServer.java +++ b/src/main/java/noppes/npcs/NoppesUtilServer.java @@ -640,7 +640,7 @@ public class NoppesUtilServer { playerdata.save(); } if (pl != null) { - SyncController.syncPlayer((EntityPlayerMP) pl); + SyncController.dispatchSyncForAllTypes((EntityPlayerMP) pl); } sendPlayerData(type, player, name); } @@ -1229,7 +1229,7 @@ public class NoppesUtilServer { playerdata.save(); if (pl != null) { - SyncController.syncPlayer((EntityPlayerMP) pl); + SyncController.dispatchSyncForAllTypes((EntityPlayerMP) pl); } } @@ -1261,7 +1261,7 @@ public class NoppesUtilServer { playerdata.save(); if (pl != null) { - SyncController.syncPlayer((EntityPlayerMP) pl); + SyncController.dispatchSyncForAllTypes((EntityPlayerMP) pl); } } } diff --git a/src/main/java/noppes/npcs/ServerEventsHandler.java b/src/main/java/noppes/npcs/ServerEventsHandler.java index 9664933be..d36c95eb5 100644 --- a/src/main/java/noppes/npcs/ServerEventsHandler.java +++ b/src/main/java/noppes/npcs/ServerEventsHandler.java @@ -260,6 +260,7 @@ public class ServerEventsHandler { SyncType.WORKBENCH_RECIPES, EnumSyncAction.RELOAD, -1, + null, SyncController.getCurrentServerRevision(SyncType.WORKBENCH_RECIPES), WorkbenchRecipeSyncHandler.getInstance().serializeAll() ), (EntityPlayerMP) player); @@ -269,6 +270,7 @@ public class ServerEventsHandler { SyncType.CARPENTRY_RECIPES, EnumSyncAction.RELOAD, -1, + null, SyncController.getCurrentServerRevision(SyncType.CARPENTRY_RECIPES), CarpentryRecipeSyncHandler.getInstance().serializeAll() ), (EntityPlayerMP) player);