Explanation: JSON vs Hardcoded Content

Library of Exile supports two ways to define registry entries. Choosing between them is a deliberate design decision, not just a stylistic preference.


Hardcoded entries

A hardcoded entry is defined in Java and registered during FMLCommonSetupEvent. It exists for the lifetime of the JVM and cannot be changed by a /reload.

When to use hardcoded: - The entry has complex logic that cannot be expressed in JSON (a League with a custom isInSide predicate, a MapDataBlock with custom generation code). - The entry is a structural requirement — things like "empty" fallback entries that must always exist before any JSON is parsed. - The entry is internal to your mod and you deliberately do not want server admins to override it.

How to write:

Use ExileKey.ofId inside an ExileKeyHolder:

public ExileKey<MobList, KeyInfo> CAVE = ExileKey.ofId(
    this, "my_mod:cave",
    x -> new MobList(x.GUID(), 1000, entries, MobListTags.MAP)
);

Or use ExileRegistryEventClass for a batch:

public void init(ExileRegistryEvent e) {
    e.add(new MyCaveMobList(), ExileRegistrationInfo.of("my_mod"));
}

JSON entries

A JSON entry lives in a datapack file under data/<namespace>/<type_id>/. It is parsed on every /reload and fully replaces its previous version.

When to use JSON: - The entry is pure data — weights, stat ranges, effect ids, item ids. - You want server admins or modpack authors to be able to tune values without recompiling. - The entry should participate in the Library of Exile datapack ecosystem (other mods can override it with "loader": "REPLACE_FIELDS").

How to write:

Implement JsonExileRegistry<T> and IAutoGson<T> on your content class. Place JSON files in the correct datapack folder. The library's BaseDataPackLoader handles everything else.


Mixed: addSeriazable

A third option exists: register an entry hardcoded but mark it as serializable. Use e.addSeriazable(entry, info) instead of e.add(entry, info).

This means: - The entry is guaranteed to exist (registered in Java at startup). - A JSON file with the same GUID can partially or fully override it at runtime.

This is ideal for default values that most servers keep as-is, but that modpack authors occasionally need to adjust. For example, the built-in relic rarities (Common through Mythic) are registered this way — they have sensible defaults but can be overridden by a datapack without the mod author needing to change the code.

Overriding a addSeriazable entry from JSON:

{
  "id": "library_of_exile:mythic",
  "loader": "REPLACE_FIELDS",
  "affixes": 4
}

Only affixes changes; all other fields keep their hardcoded values.


Client sync implications

Hardcoded entries are not included in ON_LOGIN sync packets. Only isFromDatapack() == true entries (JSON entries and addSeriazable entries that were overridden by JSON) travel to the client.

This means: - If you want a hardcoded entry to be visible to clients, you must also register it client-side — the client mod init code runs EXILE_REGISTRY_GATHER the same way the server does. - If a JSON entry should be client-visible, use an ON_LOGIN type and it syncs automatically.

For most use cases, JSON entries for display data (relic stats, affix names) and hardcoded entries for logic-heavy types (leagues, custom map data blocks) is the natural split.


Summary

Property Hardcoded JSON addSeriazable
Defined in Java Datapack file Java (overridable by JSON)
Hot-reloadable No Yes Partially (JSON overlay only)
Overridable by server admin No Yes Yes (via JSON)
Included in ON_LOGIN sync No Yes Yes (if overridden)
Supports complex logic Yes No No
Load order guaranteed Yes After FMLCommonSetup Yes (base); JSON part on reload