Explanation: Architecture Overview

Library of Exile is a foundation mod. It does not add weapons, dungeons, or gameplay by itself. Instead it provides the infrastructure that other mods in the Mine and Slash ecosystem build on top of. Understanding its shape makes it easier to know where to look when adding features or debugging.


The registry layer

The most important abstraction is ExileRegistryType. Think of it as a typed channel — a named slot in a global map. Each content category (mob affixes, relic types, mob lists, etc.) has one ExileRegistryType instance. All entries of that category go into the corresponding ExileRegistryContainer stored in Database.

This is separate from Forge's own registry system. Forge registries handle Item, Block, EntityType, etc. — Minecraft's built-in object types. The ExileRegistryType system handles game design data: the stat definitions, spawn weights, map generation rules, and similar content that is meant to be datapack-editable and often needs to be synced to clients.

The two systems coexist: a RelicType entry (in the exile registry) holds the string id of a Forge-registered Item, bridging the two worlds.


Content lifecycle

Content enters the system in one of two ways: hardcoded Java registration or JSON datapack loading. In both cases the result ends up in the same ExileRegistryContainer.

Hardcoded entries are registered during FMLCommonSetupEvent when the library fires ExileEvents.EXILE_REGISTRY_GATHER for each type. Mods listen to this event and call e.add(entry, info) to register their entries. The ExileKeyHolder + ExileKey pattern automates this wiring.

JSON entries are loaded by BaseDataPackLoader, which is registered as a Forge reload listener. On every /reload and on world load, the loader reads all JSON files from the correct datapack folder for each type and calls e.add(parsed_entry, info).

After both sources have contributed, Database.checkGuidValidity() validates all entries and unregisterInvalidEntries() removes bad ones. Then each ExileRegistryContainer caches its ON_LOGIN sync packet bytes.


The sync model

Clients need some registry data (relic stats, affix names, rarity info) to display things correctly. They do not need server-authoritative data like mob spawn lists or map generation rules.

The SyncTime enum controls this split at the type level: - ON_LOGIN — the library automatically sends all JSON-originated entries to every connecting client. - NEVER — entries stay on the server.

This means the division between client and server knowledge is declared once, at type registration time, and is then fully automatic. Mods do not need to write packet handlers for registry data.


The event layer

Library of Exile exposes game hooks through ExileEvents. These are thin wrappers around internal logic (mixins, Forge events) that give dependent mods a stable surface to attach to.

For example, the GRAB_MOB_AFFIXES event is fired by a tick listener (registered in MobAffixEvents.init()). Any number of mods can register listeners on that single event to contribute affixes for any entity. The library collects all responses and applies them.

This pattern — one library event, many mod listeners — keeps mods decoupled from each other. Two mods that both add affixes to Zombies never need to know about each other.


The mixin layer

Some hooks require bytecode injection into vanilla classes. The library handles all of these in its own mixin package, exposing the results through ExileEvents or through the capability system. Dependent mods should never need to write their own mixins for features the library already covers.

Active mixin targets: - LootTable — chest loot generation, block drop hooks. - LivingEntity — damage pipeline hook. - Mob — spawn finalization, for storing spawn reason. - PlayerList — player login hook. - ServerPlayer, Entity, ItemStack — various small hooks. - Level, Commands — dimension and command hooks.


The capability system

Player, entity, chunk, and map data that must persist across sessions is stored using Forge capabilities. Library of Exile defines: - PlayerDataCapability / PlayerCapabilities — player-level persistent data. - LibMapCap / LibChunkCap — map and chunk data. - EntityInfoComponent / EntityDmgStatsData — per-entity stats and damage tracking.

Dependent mods can read these capabilities to share data. The capability instances are registered in Capabilities.reg(), called from commonSetupEvent.


OrderedModConstructor as the integration contract

The primary integration point for a dependent mod is OrderedModConstructor. Subclassing it and calling register() from your @Mod constructor guarantees that your Forge deferred registers, your exile registry databases, and your content entries all initialize in the right order relative to the library and to each other.

The six abstract methods form a checklist that covers every initialization phase: 1. Register Forge DeferredRegister instances with the event bus. 2. Register items/blocks into those registers. 3. Declare new ExileRegistryType containers (if any). 4. Register hardcoded entries into those containers. 5. Declare ExileRegistryEventClass handlers for batch content registration. 6. Declare ExileKeyHolder instances for individual named entries.