Config migrations
The plugin runs JSON config migrations at mod start, before any manual config (ZoneLevelConfig, InstanceLevelConfig, LevelRewardsConfig) is loaded. If a config file’sVersion is strictly less than a migration’s MigrateVersionInferiorTo, the migration steps are applied and the file is saved. A backup of the pre-migration content is written to <filename>.pre-migration (e.g. RPGLevelingConfig.json.pre-migration) so it is not overwritten by Hytale’s Config save (which uses .bak).
When migrations run
- When: During plugin startup, after
ConfigManageris created and beforeZoneLevelConfig.initialize(),InstanceLevelConfig.initialize(), andLevelRewardsConfig.initialize(). - Which files: Config files resolved via
ConfigManager.getConfigFile(fileName). Config file names must match exactly (e.g.RPGLevelingConfig.json,InstanceLevelConfig.json,ZoneLevelConfig.json,LevelRewardsConfig.json).
Folder layout
- Index:
src/main/resources/migrations/index.json— lists version folders and their migration filenames. - Per-version:
src/main/resources/migrations/<version>/— e.g.migrations/0.2.9/. Inside each version folder, place one JSON file per config migration (e.g.InstanceLevelConfigMigration.json). - Discovery: The runner loads the index, then for each version and each filename loads
migrations/<version>/<filename>from the classpath. You must add each new migration file to the index.
Index format
Per-migration file format
Each file undermigrations/<version>/<name>.json has:
| Field | Description |
|---|---|
ConfigFileName | Exact config file name (e.g. InstanceLevelConfig.json). Must match a name used with ConfigManager.getConfigFile(fileName). |
MigrateVersionInferiorTo | Semantic version (e.g. 0.2.9). The migration runs when the config file’s Version is strictly less than this. Should match the folder name for clarity. |
Steps | Array of step objects (see below). Applied in order. |
Step operations
Paths use dot-separated segments. Each segment is either a key (object member) or a numeric index (array element). This allows arbitrary depth (e.g.Rewards.2.Items.0.ItemId).
set
Sets a value at the given path. Creates parent objects if missing; for arrays the index must already exist.
"op": "set""path": "Version"— top-level key"value": "0.2.9"— string, number, or boolean
"path": "Version", "value": "0.2.9""path": "Instances.0.LevelMin", "value": 5"path": "Rewards.2.Items.0.Quantity", "value": 10
remove
Removes a key or an array element at the given path.
"op": "remove""path": "SomeKey"— remove top-level key"path": "Instances.0"— remove first element ofInstances"path": "Rewards.1.Items.2"— remove nested array element
removeArrayElements
Removes all elements in the array at path that match every key-value in arrayMatch. The path can point to an array at any depth.
"op": "removeArrayElements""path": "Instances"— array to filter"arrayMatch": { "Id": "Default" }— object; each array element that has all these keys with these values is removed
"path": "Rewards.0.Items", "arrayMatch": { "ItemId": "OldItem" }
appendToCommaSeparated
Appends values to a comma-separated string at the given path without overwriting. Reads the current string, splits by comma, adds any values from value that are not already present, then writes back (joined with comma, no spaces). If the key is missing, treats current as empty and adds all values.
"op": "appendToCommaSeparated""path": "BlacklistedEntityRoles"— path to the string"value": ["Pet_Follower", "Pet_Follower_Large", "Pet_Follower_Large_Combat"]— string or array of strings to add
"Citizen_" becomes "Citizen_,Pet_Follower,Pet_Follower_Large,Pet_Follower_Large_Combat"; existing "Citizen_,MyRole" becomes "Citizen_,MyRole,Pet_Follower,Pet_Follower_Large,Pet_Follower_Large_Combat".
Version format
Versions are compared as semantic versions (e.g.0.2.9, 1.0). Comparison is strictly less than: the migration runs only when config Version < MigrateVersionInferiorTo. After applying a migration, the config’s Version is set to that migration’s MigrateVersionInferiorTo so it is not applied again.
Config file names
Use the exact names fromConfigManager:
RPGLevelingConfig.jsonInstanceLevelConfig.jsonZoneLevelConfig.jsonLevelRewardsConfig.jsonMessagesLanguageMapping.json
Example: remove Default instance
- Config:
InstanceLevelConfig.json - File:
migrations/0.2.9/InstanceLevelConfigMigration.json - Index:
"0.2.9": ["InstanceLevelConfigMigration.json"]inmigrations/index.json - Condition: Migrate when
Version<0.2.9 - Step: Remove from
Instancesany element with"Id": "Default":
Version is set to 0.2.9.