-
Notifications
You must be signed in to change notification settings - Fork 7
Legacy Data Migration
Before 3.0, EverNifeCore stored each player in a YAML file under
plugins/EverNifeCore/PlayerData/<uuid>.yml. The new storage layer keeps data in the backend the admin
configures (see Storage Backends). EverNifeCore migrates the old files for you,
once, on the first boot after the upgrade - no manual conversion. It also offers a runtime command to
move a single section between backends later on.
Trigger. On boot EverNifeCore looks for plugins/EverNifeCore/PlayerData/*.yml. If any exist and the
migration is not yet recorded as finished, the one-time import runs on the first server tick - after
every plugin has registered its sections and their legacy adapters - and only then are player logins
released.
How a file is split. Each legacy per-player file is broken into independent entities:
- The base block becomes the new
PlayerDataentity. - Every top-level (root) key claimed by a registered legacy adapter is routed by that adapter into its own section's collection and backend.
A plugin opts a section into the import by declaring a legacy adapter on its PDSection configuration:
PDSectionConfiguration.builder(ecPluginData, JobsSection.class)
// convert the old '<rootKey>:' subtree of the per-player file into the new POJO
.legacyYaml("Jobs", section -> {
JobsSection jobs = new JobsSection();
jobs.level = section.getInt("level", 0);
jobs.job = section.getString("job", "none");
return jobs;
})
.build();Sections without a legacy adapter are simply not migrated.
- Idempotent - an entity whose UUID is already present in the target collection is skipped, so a re-run never overwrites more recent data.
-
Leaving the folder means completion - a file moves out only once every root key holding data
has been migrated. Whatever remains in
PlayerData/is, literally, the to-do list. -
Never edits or deletes a YAML file - a broken one is copied to
PlayerData-Failed/for diagnosis while the original stays behind as pending. - A broken file never aborts the run - it is reported and the rest still imports.
Progress is tracked in playerdata-storage-migration-metadata.yml, rewritten each run with every root
key it saw (including ones no adapter claims yet - those are what bring the import back on a later boot,
once the owning plugin is installed).
On the boot that finally drains the folder, a one-time tidy-up gathers every artifact the migration produced into a single archive, leaving the plugin folder clean and the whole migration documented in one place:
plugins/EverNifeCore/__LegacyData_V2/
PlayerData/ (the archived original .yml files - was PlayerData-Imported)
PlayerData-Failed/ (only if any broken files were ever copied for diagnosis)
playerdata-storage-migration-metadata.yml (the progress file, moved out of the plugin root)
migration-result.log (a human-readable summary of the whole migration)
The archived originals are renamed back to PlayerData/ on purpose: rollback is a single move. An
older EverNifeCore reads only a PlayerData/ folder, so to downgrade you move
__LegacyData_V2/PlayerData/ back to the plugin folder before downgrading - otherwise every player is
greeted as brand new.
A later re-migration does not mix into an existing archive: it gets its own untouched sibling
(__LegacyData_V2_2, _3, …).
To force a re-migration: delete the generated artifacts (the progress file and the __LegacyData_V2
archive) and restore the PlayerData/*.yml files. The import runs again and skips whatever already
reached the backend.
⚠️ The import runs on the main thread on the first tick, and logins are held on a gate that is subject toplayerdata.login-timeout-seconds(default 5 s). On a server with thousands of legacy files the first migration can take much longer than that, during which connecting players may be kicked ("storage unavailable") and retry until it finishes. Run the first post-upgrade boot in a maintenance window, and consider raising the server's watchdog timeout for that boot.
📌 A root key whose owning plugin is not installed keeps its file in
PlayerData/(no adapter = not fully migrated), so the import re-scans on every boot. To finish, install the plugin that owns that data, or move the remaining.ymlfiles out ofPlayerData/by hand.
You can move a single PDSection's collection to another backend at runtime, without editing files by hand:
/ecstorage transfer section <plugin:section> <backend>
Permission node evernifecore.command.storage.transfer. It is a subcommand of [[Command
Framework|Command-Framework]]'s /ecstorage, alongside the read-only /ecstorage status (see
Storage Backends).
-
<plugin:section>identifies the section by itsPluginName:SectionSimpleNameid. -
<backend>is a backend declared and enabled instorage.yml.
What it does: freezes the section's writes, copies the collection through EveryDatabase's
StorageTransfer (keeping
the source collection as a backup), cuts over to the new backend, and persists the choice into
storage.yml so the new binding survives a restart. It runs asynchronously and reports the entity
count and duration when done; on failure the binding stays unchanged and each error is listed.
📌 A maintenance window is recommended for a transfer - the source is kept as a backup, but a cutover under live writes is best done quietly.
-
Storage Backends -
storage.yml, backends and routing. -
PlayerData & PDSections - the section model the import targets, and
legacyYaml(...). -
EveryDatabase: Moving Data Between Backends
- the transfer engine underneath.
EverNifeCore · Home · made by Petrus Pradella
Getting Started
Commands & Text
Player Data & Storage
- PlayerData & PDSections
- Accounts
- Storage Backends
- Inline Backends for Plugins
- Legacy Data Migration
- Cooldowns
Config & Minecraft Systems
- Configuration
- Scheduler & Threading
- Items & NBT
- GUI Framework
- Integrations
- Economy
- Version Compatibility
Architecture & Reference