Mod Patch Schemas¶
This folder contains the v0.1 JSON Schemas for Pagonia Land patch-style mods. These schemas are the public contract — anything that consumes Pagonia Land mod manifests (the patcher, pagonia-manager, a future GUI on top of Manager.Core, IDE plugins, EE's own tooling, web validators) reads against them.
The schemas are intentionally small and conservative. They support:
- editor validation for
mod.yamland patch files - the
pagonia-patchercommand line tool - mod managers (
pagonia-managerdoes this today; future GUIs do the same) that validate archives before installation - automated checks in CI
Reference Implementation And Drift Protection¶
pagonia-patcher schema-validate is the reference implementation of this contract. It embeds the schemas in this folder into the patcher binary and validates mod.yaml, patch files, collections, and lockfiles against them.
Two safeguards keep the schemas, the patcher's C# code, and the sandbox examples in sync:
scripts/preflight.ps1runsschema-validateagainst every sandbox example before any commit. If a schema change breaks an example, preflight catches it locally..github/workflows/tools.ymlruns the same preflight on every push and PR. Schemas, code, and examples cannot drift past CI undetected.
When you add a new field to a model in tools/pagonia-patcher/src/PagoniaLand.Patcher.Core/Models/, add the matching property to the schema here in the same PR. The CI's schema-validate step will fail loudly on the first sandbox example that uses the new field if the schema doesn't know it yet — that's how we caught the missing pak: block when schema-validate first ran. See CONTRIBUTING.md → When You Touch Tools Or Schemas for the rule.
Format Versions¶
Each file carries a MAJOR.MINOR format version (patchFormatVersion, collectionFormatVersion, collectionLockVersion, indexFormatVersion, catalogFormatVersion), currently 0.1. The version field accepts any same-major value (the schema constrains it to major 0); the tools layer a tiered reader on top that the schema can't express: a same-major newer minor still reads (newer optional fields ignored, with a recommend-update note), while a newer or retired major is refused with an actionable "download a newer tool" message. Bump the minor for an additive, backward-compatible field; bump the major only for a breaking shape change. Prefer the string form ("0.1") on disk. The full contract — semantics, the tier table, and read-old/write-new migration — is documented in the Mod Distribution → Format compatibility guide.
Files¶
| Schema | Purpose |
|---|---|
| mod.schema.json | Validates the root mod.yaml manifest |
| patch-file.schema.json | Validates YAML files listed under patches or patchSets[].patches |
| collection.schema.json | Validates curated collection manifests |
| collection-lock.schema.json | Validates resolved collection lockfiles |
| repo-index.schema.json | Validates a Git-distribution repo's top-level index.yaml catalog (mods + collections offered by the repo) |
| catalog.schema.json | Validates a catalog.yaml — a curated list of mod-distribution repos plus optional federated references to other catalogs. The manager aggregates across every catalog the user is subscribed to. |
JSON Schema can validate YAML after the YAML file has been parsed into normal JSON-like data.
Current Scope¶
The first version focuses on data shape:
- required mod identity fields
- exact
gameDatabaseVersion - required and optional package declarations
- patch file paths
- optional patch sets
- basic mod manager metadata
- patch operations and target fields
- curated collection manifests
- resolved collection lockfiles
It does not prove that a target exists in the XML. That belongs in the patcher itself, which already resolves targets, applies clean plans, and reports conflicts.
Example Manifest¶
patchFormatVersion: 0.1
id: pagonia-land.example.cheaper-sawmill
name: Cheaper Sawmill
version: 0.1.0
author: Pagonia Land
gameDatabaseVersion: "1.4.0-12032+195221"
description: Lowers one Sawmill construction cost for local testing.
requiredPackages:
- core
optionalPackages: []
requiresNewGame: false
safeToRemove: unknown
multiplayerSafe: unknown
campaignSafe: unknown
loadAfter: []
loadBefore: []
incompatibleWith: []
patches:
- patches/buildings.yaml
Example Patch File¶
operations:
- id: cheaper-sawmill-softwood
operation: replaceValue
risk: low
reason: Lower early Sawmill construction cost for testing.
target:
file: core/gdb/buildings.gd.xml
entityGuid: c732cb26-7487-4a7b-b1ba-b65e094f9bac
entityName: Sawmill
component: AspectBuildup
path: Costs/Item[Content/Resource='c22b4997-5563-44ab-8aa0-04a7b2c826be']/Content/Amount
expectedOldValue: "4"
value: "3"
Notes For Tool Authors¶
A patcher should validate in layers:
- Parse YAML.
- Validate against these schemas.
- Check local package folders.
- Check
gameDatabaseVersion. - Resolve targets in XML.
- Check expected old values.
- Build a combined patch plan.
- Detect conflicts across all enabled mods.
- Apply only after a clean dry run.
The schema is not a replacement for the patcher. It is the first gate.
For collection design, see Mod Collections.
For small example manifests, see Collection Examples.