Explanation: The Sync Model

Library of Exile automatically synchronizes registry data from the server to clients. This page explains the design rationale and what it means in practice.


Why sync registry data?

Minecraft's client/server architecture means the client and server run separate JVMs. Registry data that the client needs to display — relic stat names, affix descriptions, rarity colors — must be explicitly sent over the network. Without a sync mechanism, every mod would need to write its own packet handlers for its own content.

Library of Exile solves this once, at the registry-type level. When you declare a type with SyncTime.ON_LOGIN, the library handles serialization, packet construction, delivery, and client-side deserialization automatically.


The two sync categories

SyncTime.ON_LOGIN — "clients need this."

These types are synced whenever a player connects or /reload is run. Typical examples: stat definitions, affix names, rarity tables. The client uses these to render item tooltips and UI elements correctly.

SyncTime.NEVER — "this is server business."

These types are authoritative server data that clients should never directly access. Mob spawn lists control which mobs appear in a dimension — the client has no say in that. Map data blocks define generation logic — the client does not generate maps. Leagues contain positional logic — the server evaluates them.


Caching for performance

The most expensive part of syncing is serializing every entry to bytes. If this happened on every login, a server with 50 concurrent players would repeat that work 50 times.

The library avoids this by caching the serialized bytes in ExileRegistryContainer.cachedBuf after each datapack reload. On login, the pre-cached bytes are sent directly, with no re-serialization.

The trade-off: the cache can only be updated at reload time. If you add an entry at runtime (outside of the normal datapack loading flow), it will not appear in the sync packet until the next /reload.


What clients receive

Clients receive only JSON-originated entries from ON_LOGIN types. Hardcoded entries (those registered purely in Java via e.add(...), not e.addSeriazable(...)) are not included.

This is intentional: hardcoded entries are part of the mod code. When the client mod is installed, it runs the same FMLCommonSetupEvent initialization that the server does, populating its Database with the same hardcoded entries. The server does not need to transmit them.

Entries added via e.addSeriazable(...) that were subsequently overridden by a JSON file are included in the sync packet, because those overrides may differ between server deployments.


What this means for your mod

If you add a JSON entry to an ON_LOGIN type: Nothing extra is required. Clients that connect after the last /reload will receive it.

If you add a hardcoded entry to an ON_LOGIN type: You must ensure the same entry is registered client-side. Since both sides run FMLCommonSetupEvent, an ExileKeyHolder or ExileRegistryEventClass that is present in both the client and server mod jar handles this automatically.

If you add a new ExileRegistryType with ON_LOGIN: The sync mechanism picks it up automatically. The client's RegistryPackets handler will deserialize it because it uses the type's registered serializer prototype. Ensure your content class implements IAutoGson<T>.


Debugging sync issues

If a client does not have expected entries:

  1. Check that the type is ON_LOGIN, not NEVER.
  2. Check that the entry was loaded from a JSON file (or was registered with addSeriazable and then overridden). Purely hardcoded entries are not in the sync packet.
  3. Run /reload and reconnect to force a fresh sync.
  4. Check the server log for [LibraryOfExile] warnings about invalid GUIDs or failed round-trip checks — invalid entries are dropped before sync.
  5. Check the client log for deserialization errors during the login packet handler.