-
Notifications
You must be signed in to change notification settings - Fork 2
Concepts Lifecycle
How a mod moves through the engine's boot sequence, and what it may legally do in each phase.
boot -> import -> discover -> load -> merge -> play -> save
-
Boot.
conf.luasets the window; the engine version and mod API number come fromsrc/core/Version.lua, the single home of every compatibility-relevant number (engine semver, mod API major, link protocol, save format, cache generation). -
Import.
Game:loadruns the ROM importer's cached data throughData:load(). Mods never participate in extraction; they see the world only after it exists. -
Discover. The loader scans the virtual
mods/root (source tree and save directory fused) and validates eachmanifest.json. A bad manifest skips that mod with a logged reason; boot continues. The engine then registers its own vanilla records into the behavioral registries under the ownerengine(src/mods/Builtins.lua) — before any mod runs, so a mod'sregisteron a vanilla id collides and must sayoverride. -
Load. Manifest enforcement runs first: engine
game_versionranges, hard dependencies (present, enabled, in range), conflict declarations, and dependency cycles, each failing only the mods involved. Entry chunks then run in dependency order (dependencies first, thenpriorityascending, ties by id). Each chunk runs under a rollback journal: if it errors, every registration it made and every subscription it took are undone, so a broken mod leaves zero residue. -
Merge. Registered content folds over the imported base data, one
registry at a time (
Loader:load, merge loop). A cross-reference pass then resolves id-typed fields against the merged world and reports dangling references. After the merge the content registries freeze:register/override/patch/removeraise from then on, including from inside amods.loadedlistener. Register content at entry-chunk time. Asset transforms run here too, and the merged mod set becomes the asset search path. -
Play.
game.readyfires with{ game = Game }once every service is up: readingev.gameis the sanctioned way to reach the liveGameobject. From here the game runs; mods observe it through events and hooks. - Save. Saving and loading pass through the save model: meta stamping, per-mod namespaces, migrations, and the validation/quarantine pass.
The event and hook buses are never sealed. A mod may subscribe during its
entry chunk, inside a mods.loaded or game.ready listener, or at any
point later — from inside a battle callback if it wants. Only content
freezes at the merge boundary; behavior stays open for the life of the
process.
Every listener and hook link runs under pcall. A callback that raises is
logged against the mod that subscribed it and skipped; the engine path that
emitted the event or called the hook always completes, and a failing hook
link degrades to "not installed for this call"
(Events and Hooks).
| Event | Fires | Payload |
|---|---|---|
mods.loaded |
end of the merge phase | { loader, data } |
game.ready |
after services init, before the first screen | { game } |
Both fire exactly once per boot, with or without mods installed. Under
POKEPORT_DEV=1, a hot reload re-emits game.ready after re-merging
(src/dev/HotReload.lua).
| You want to | Do it |
|---|---|
| Register/override/patch/remove content | entry chunk only |
| Subscribe to events, wrap hooks | any time |
Reach the live Game
|
game.ready payload |
Touch the overworld (mod.world) |
after game.ready
|
| Read another mod's exports |
mod.find(id) — after that mod loaded |
Engine 1.0.0 · mod API 2 · repository · Discord
This project ships no ROM data. All game content is decoded on the player's machine from their own verified Pokemon Red ROM; mods ship recipes and original assets, never extracted content.
Start here
Concepts
Tutorials
- The ladder
- 01 Sprite and Text Tweak
- 02 Balance Patch
- 03 New Species
- 04 New Item and Ball
- 05 New Move
- 06 NPC and Dialogue
- 07 New Map
- 08 Quest
- 09 Custom Music
- 10 New Mechanic
- 11 Custom UI Screen
- 12 Mini Total Conversion
Reference
Guides
Playing