mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-27 00:48:32 +02:00
feat(mod-api): add imported dataset views
This commit is contained in:
@@ -200,6 +200,42 @@ the adapter's own coverage table:
|
||||
python3 tools/modkit.py gen2check mods/my_mod
|
||||
```
|
||||
|
||||
## Imported version datasets
|
||||
|
||||
A mod can inspect semantic content from another game the player has already
|
||||
imported without switching the active game or reaching into engine cache
|
||||
internals:
|
||||
|
||||
```lua
|
||||
local gold, reason = mod.datasets:open("gold")
|
||||
if not gold then
|
||||
-- reason is "unknown_version" or "not_imported"
|
||||
return
|
||||
end
|
||||
|
||||
local chikorita = gold.content.pokemon:get("CHIKORITA")
|
||||
local normalVsGhost = gold.content.type_chart:get("NORMAL>GHOST")
|
||||
local spritePath = gold.assets:path(chikorita.spriteFront)
|
||||
|
||||
for id, record in gold.content.pokemon:each() do
|
||||
-- ids are returned in deterministic lexical order
|
||||
end
|
||||
```
|
||||
|
||||
`view.version` and `view.generation` identify the selected dataset.
|
||||
`view.content` exposes the same registry names and generation-specific record
|
||||
shapes as `mod.content`, but only `get`, `has`, and `each`; returned
|
||||
records are detached copies and cannot mutate either dataset. Each open call
|
||||
receives an independent facade, so one mod cannot replace another mod view method. Engine-provided
|
||||
semantic records, such as `NORMAL>GHOST` type matchups, are included.
|
||||
|
||||
Only a cache carrying the current engine completion marker is opened. Missing
|
||||
and stale imports both return `nil, "not_imported"`; no raw ROM bytes or
|
||||
generated Lua modules are exposed. `view.assets:path(relative)` and
|
||||
`view.assets:info(relative)` accept only `assets/generated/...` paths and
|
||||
keep them under the selected version cache prefix. The API never changes
|
||||
`mod.game`, the active `Data` table, `GameVersion`, or cache mount state.
|
||||
|
||||
## Editing maps in Tiled
|
||||
|
||||
Maps are data, not assets, so they can be authored in a real map editor and
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# RFC 0012: Read-only imported dataset views
|
||||
|
||||
## Status
|
||||
|
||||
Proposed.
|
||||
|
||||
## Motivation
|
||||
|
||||
A cross-version content mod can read only the active merged dataset through
|
||||
`mod.content`. Even when the player has already imported another supported
|
||||
game, a mod cannot inspect that version's semantic species, moves, items, type
|
||||
chart, or generated asset namespace. The available alternatives are private:
|
||||
mutating `CacheFs.prefix`, mounting another cache over the active one, loading
|
||||
generated Lua directly, or asking for a second raw-ROM import. They compose
|
||||
poorly with the active game, expose unstable import layout, and make safe
|
||||
read-only use impossible from the sandbox.
|
||||
|
||||
The immediate example is an optional content pack derived from an already
|
||||
verified Gold import while Red, Blue, or Yellow remains active. The capability
|
||||
is generic and useful to randomizers, compatibility inspectors, dex tools, and
|
||||
other cross-version content mods.
|
||||
|
||||
## Decision and plan extended
|
||||
|
||||
This implements **D-AT-004: optional Kanto+ content consumes an
|
||||
active-independent semantic dataset view**. The consuming design is tracked in
|
||||
the Adaptive Trainers implementation plan,
|
||||
[`docs/superpowers/plans/2026-08-14-adaptive-trainers.md`](https://github.com/MaxTomahawk/gen1recomp-adaptive-trainers/blob/main/docs/superpowers/plans/2026-08-14-adaptive-trainers.md),
|
||||
Task 8. The delta is a generic, additive public API and contains no trainer
|
||||
pools, scaling, boss identities, version-mixing rules, or Adaptive Trainers
|
||||
policy.
|
||||
|
||||
## Exact API delta
|
||||
|
||||
Every sandboxed mod receives:
|
||||
|
||||
```lua
|
||||
local view, reason = mod.datasets:open("gold")
|
||||
```
|
||||
|
||||
A known version with the current completed import marker returns a read-only view:
|
||||
|
||||
```lua
|
||||
view = {
|
||||
version = "gold",
|
||||
generation = 2,
|
||||
content = {
|
||||
pokemon = {
|
||||
get = function(self, id) end,
|
||||
has = function(self, id) end,
|
||||
each = function(self) end,
|
||||
},
|
||||
-- every public registry name and alias
|
||||
},
|
||||
assets = {
|
||||
path = function(self, generatedPath) end,
|
||||
info = function(self, generatedPath) end,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`get` returns a detached copy or nil. `has` reports semantic presence.
|
||||
`each` returns ids in lexical order and detached values. The registries use
|
||||
the selected version's generation routing and the engine's existing
|
||||
`Schemas`, `Registry`, and `Builtins` normalization, so structured sources
|
||||
such as type matchups retain the same public ids used by the active
|
||||
`mod.content` facade. No register, patch, override, or remove verb is exposed. Each call returns an
|
||||
independent facade over the cached internal dataset, so facade mutation cannot cross
|
||||
mod boundaries.
|
||||
|
||||
`assets:path` returns the selected cache-prefixed virtual path.
|
||||
`assets:info` returns sanitized `type` and optional `size` metadata. Both
|
||||
accept only relative paths below `assets/generated/`, reject control
|
||||
characters, absolute paths, backslashes, and traversal, and expose no byte
|
||||
reader.
|
||||
|
||||
An unknown version returns `nil, "unknown_version"`. A missing or stale
|
||||
completion marker returns `nil, "not_imported"`. Generated tables are parsed
|
||||
under an empty environment and cached per version; the API never exposes raw
|
||||
ROM bytes, generated source, host paths, or a cache mount.
|
||||
|
||||
## Migration and compatibility
|
||||
|
||||
Existing mods change nothing. `mod.datasets` is additive and requires no
|
||||
permission. The service is allocated lazily on the first explicit
|
||||
`mod.datasets:open` call. A boot with no mods, or with mods that do not call
|
||||
it, performs no cross-version cache reads.
|
||||
|
||||
Opening a view does not change `GameVersion`, `CacheFs.prefix`, the active
|
||||
`Data` table, PhysFS mounts, save state, or the selected game's behavior.
|
||||
Red, Blue, Yellow, Gold, and Silver keep their existing active data paths.
|
||||
|
||||
The completion-marker format moves to the pure `CacheFormat` helper shared by
|
||||
the importer and dataset service. The literal marker and import readiness
|
||||
behavior are unchanged.
|
||||
|
||||
## Verification
|
||||
|
||||
- `tests/modkit/cases/dataset_views.lua` loads a sandboxed fixture mod through
|
||||
the public API and covers Red, Blue, Yellow, and Gold independently.
|
||||
- The test proves semantic registry normalization, deterministic iteration,
|
||||
detached records, read-only facades, cross-mod facade isolation,
|
||||
version-prefixed generated assets,
|
||||
traversal rejection, stable failure reasons, and stale-marker rejection.
|
||||
- The same test proves that cross-version reads do not change the active data,
|
||||
active game, or cache prefix, and that a no-mod boot performs zero
|
||||
cross-version cache reads.
|
||||
- The existing importer and engine/modkit suites prove unchanged marker
|
||||
readiness and no-mod behavior.
|
||||
|
||||
## Deprecation etiquette
|
||||
|
||||
Nothing is removed, renamed, superseded, or deprecated.
|
||||
Reference in New Issue
Block a user