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:
- Check that the type is
ON_LOGIN, notNEVER. - Check that the entry was loaded from a JSON file (or was registered with
addSeriazableand then overridden). Purely hardcoded entries are not in the sync packet. - Run
/reloadand reconnect to force a fresh sync. - Check the server log for
[LibraryOfExile]warnings about invalid GUIDs or failed round-trip checks — invalid entries are dropped before sync. - Check the client log for deserialization errors during the login packet handler.