📡 Network Synchronization & Payloads (Minecraft 26.2)
📌 Repository Source Disclaimer: The documentation in this Wiki reflects the current source code state in the repository, which may include recent unreleased commits or developmental features ahead of public release builds on CurseForge and Modrinth.
1. Official Infobox
| Parameter | Technical Details |
|---|---|
| Subsystem Name | Network Synchronization Protocol |
| Payload Class | PotionLimitSyncPayload.java |
| Payload Identifier | potion-stacker:sync_limit |
| Protocol Phase | Play (clientbound S2C) |
| Codec Implementation | StreamCodec<RegistryFriendlyByteBuf, PotionLimitSyncPayload> |
| Client Receiver | PotionStackerFabricClient.java |
| Server Dispatch Events | ServerPlayConnectionEvents.JOIN, DynamicGameRuleManager listener |
| Menu Synchronization | broadcastFullState() on containerMenu and inventoryMenu |
2. Step-by-Step Player Workflow & Synchronization Lifecycle
Initial Player Connection (Handshake): When a player connects to the dedicated server,
ServerPlayConnectionEvents.JOINtriggers. The server queries current active limits fromPotionStackerManagerand sends aPotionLimitSyncPayloadto the connecting client.Client-Side State Storage: Upon packet receipt on the client,
PotionStackerFabricClientqueues a task on the Minecraft client render thread (context.client().execute(...)) to updatePotionStackerManager.setClientLimit(potionLimit, stewLimit). This ensures client-side slot preview rendering reflects true server limits.In-Game Administrator Mutation: An administrator executes
/gamerule potion-stacker-addon:potion_limit 32.DynamicGameRuleManagerdetects the value change and invokesPotionStackerManager.setLimits(...).Full Multi-Client Broadcast & Menu Refresh: The server loops through all online players (
server.getPlayerList().getPlayers()), dispatchesPotionLimitSyncPayload, and invokesbroadcastFullState()on every player's open container and inventory menus, instantly forcing the client to re-render slot contents without ghost items.
3. Mathematical Formulas & Network Bandwidth
Payload Byte Size Calculation ($B$)
Both potionLimit and stewLimit are serialized via ByteBufCodecs.VAR_INT. A Minecraft VarInt encodes 7 bits of data per byte with the 8th bit reserved as continuation flag: $$\text{VarIntBytes}(v) = \begin{cases} 1 & 0 \le v \le 127 \ 2 & 128 \le v \le 16{,}383 \ 3 & 16{,}384 \le v \le 2{,}097{,}151 \ 4 & 2{,}097{,}152 \le v \le 268{,}435{,}455 \ 5 & 268{,}435{,}456 \le v \le 2{,}147{,}483{,}647 \end{cases}$$
The total packet payload size $B$ in bytes is: $$B = \text{VarIntBytes}(P_{\text{limit}}) + \text{VarIntBytes}(S_{\text{limit}})$$
For default settings ($P = 16, S = 16$): $$B = 1 + 1 = 2\text{ bytes}$$
Even at the maximum safe limit ($39{,}768{,}215$): $$B = 4 + 4 = 8\text{ bytes}$$
Network overhead is effectively $O(1)$ and negligible across all network configurations.
4. Visual ASCII Diagrams & Packet Lifecycle
Player Join Handshake Protocol
[ Client ] [ Dedicated Server ]
| |
|----------------- C2S Login / Handshake -------------------->|
| |
| ServerPlayConnectionEvents.JOIN
| |
| Query PotionStackerManager
| pLimit=16, sLimit=16
| |
|<--- S2C PotionLimitSyncPayload(16, 16) ---------------------|
|
Receive Packet
context.client().execute()
PotionStackerManager.setClientLimit(16, 16)
|
Client GUI & Tooltips SynchronizedLive Dynamic GameRule Update & State Refresh
[ Server Admin: /gamerule potion-stacker-addon:potion_limit 64 ]
|
v
PotionStackerManager.setLimits(64, 16, server)
|
+---------------+---------------+
| |
v v
Send PotionLimitSyncPayload For every ServerPlayer:
to all connected players containerMenu.broadcastFullState()
inventoryMenu.broadcastFullState()
|
v
Eliminates Ghost Items & Resets Caches5. Packet Buffer Layout & Codec Schema
Binary Packet Byte Stream Layout:
+------------------------------------+------------------------------------+
| Field 1: potionLimit (VarInt) | Field 2: stewLimit (VarInt) |
| Range: 1 .. 2,147,483,647 (1-5 B) | Range: 1 .. 2,147,483,647 (1-5 B) |
+------------------------------------+------------------------------------+Codec Definition (PotionLimitSyncPayload.java):
public static final StreamCodec<RegistryFriendlyByteBuf, PotionLimitSyncPayload> CODEC = StreamCodec.composite(
ByteBufCodecs.VAR_INT,
PotionLimitSyncPayload::potionLimit,
ByteBufCodecs.VAR_INT,
PotionLimitSyncPayload::stewLimit,
PotionLimitSyncPayload::new
);6. Exhaustive Reference Matrix
| Attribute | Value | Description |
|---|---|---|
| Payload Identifier | potion-stacker:sync_limit | CustomPacketPayload.Type identifier |
| Network Channel | clientboundPlay | Registered via PayloadTypeRegistry |
| Field 0 | potionLimit (int) | Maximum stack limit for potions |
| Field 1 | stewLimit (int) | Maximum stack limit for stews/soups |
| Execution Thread | Main Client Render Thread | Dispatched via context.client().execute() |
| Trigger 1 | Player Join | ServerPlayConnectionEvents.JOIN |
| Trigger 2 | GameRule Mutation | PotionStackerManager.setLimits |
| Menu Sync Hook | broadcastFullState() | Forces client inventory slot cache refresh |
7. Developer & Network Hooks
Payload Registration (PotionStackerFabric.java):
PayloadTypeRegistry.clientboundPlay().register(
PotionLimitSyncPayload.TYPE,
PotionLimitSyncPayload.CODEC
);Client Receiver Registration (PotionStackerFabricClient.java):
ClientPlayNetworking.registerGlobalReceiver(PotionLimitSyncPayload.TYPE, (payload, context) -> {
context.client().execute(() -> {
PotionStackerManager.setClientLimit(payload.potionLimit(), payload.stewLimit());
});
});