Skip to content

Concepts Compatibility

bryanthaboi edited this page Jul 19, 2026 · 1 revision

Compatibility

Four separate compatibility questions, four separate answers: which mod API a mod speaks, which engine it needs, which other mods it can sit beside, and whether two linked games agree.

API level

api in the manifest picks the contract. Absent means 1, which is what every mod written before v2 says by omission. A v1 mod gets the whole v2 mod object — the surface only ever grew — and differs in strictness: a value that violates a registry schema is a load error for api = 2 and an attributed warning for api = 1, as is an unknown profile or permission. Declaring api: 2 is how you ask for the errors.

api higher than the engine provides is refused outright. The engine's number lives in src/core/Version.lua and moves only on a breaking change to the mod surface.

Engine version

game_version is a semver range against the engine release, checked before the entry chunk runs — a mod that needs a newer engine is refused with needs game version <range>, engine is <version> instead of loading and breaking in the middle. Leave it out if you have no reason to pin.

Other mods

dependencies, optional_dependencies and conflicts are enforced, and each entry may carry a version range ("colorlib@^1.2"). Failure is per-mod: whatever cannot be satisfied is refused with a reason the manager shows, and everything else still loads. See the manifest reference for resolution rules and the range grammar.

Reaching another mod's code goes through mod.exports and mod.find:

return function(mod)
  -- hard dependency: guaranteed loaded before this mod runs
  local color = mod.find("colorlib").exports

  -- optional dependency: declare it for the ordering, then branch
  local radio = mod.find("radio")
  if radio then radio.exports.addStation("NIGHT_FM") end

  mod.exports = { hour = function() return 12 end }
end

find returns { id, version, exports }, or nil when the other mod is absent, disabled or failed. Treat another mod's exports as a versioned public API: range-check handle.version (src/mods/Semver.lua is a supported require) before relying on its shape.

Link play

Two connected games compare a fingerprint: a digest over the link-relevant merged surface — pokemon, moves, the type chart, statuses, move_effects, link-relevant constants, and any registered link_fields — plus the id and version of every mod that declares it affects link (src/link/Fingerprint.lua). The handshake verdict (src/link/Handshake.lua):

Verdict Meaning Battle Trade
full identical link surfaces yes yes
vanilla_peer old build on the far side, this side unmodified yes yes
subset both v2, surfaces differ no negotiated strict-vanilla subset
refused an old build we would corrupt, or an engine mismatch no no

Manifest affects_link feeds this: it defaults to true for overhaul and total_conversion profiles and false for content. A mod that declares affects_link = false while writing into a link-relevant registry gets an attributed warning at load. Never desync silently is the rule; see Link Compatibility for keeping a content mod link-safe.

Your mod's own ledger

The base game keeps three parity ledgers, and docs/known-differences.md reads "None currently." — mods must not invalidate that. A mod's divergences are the mod's, documented by the mod: ship a DIFFERENCES.md enumerating what you change from vanilla (mirroring docs/known-differences.md's format), and let the manifest profile (content / overhaul / total_conversion) be the machine-readable summary of how far you depart. The engine's promise stays auditable precisely because disabling your mod restores vanilla exactly.

Deprecation

A name that is superseded keeps working for the life of the mod API major and logs one attributed warning the first time a given mod touches it — scripts and ui are the current examples, renamed to map_scripts and screens, and the v1 audio registry is superseded by the granular audio registries. Nothing a v1 mod does stops working inside API 2, and pokemon.before_give fires forever.

Clone this wiki locally