Mega Tree API

Persistence

Where levels are stored, and why uninstalling your mod does not destroy the player's progress.

You do not have to do anything

Saving is handled for you. Levels are written the moment something is bought or sold, into a file of Mega Tree's own, per save slot. Your mod never opens a file and never touches the game's save.

path
BepInEx/config/MegaTree/slot0.dat
Why not inside the game save

Megastore's Save_N.data is binary. A mod writing into it makes the player's save hostage to the mod: uninstall and they are left with orphan keys in a file that is not ours, and a bug on our side corrupts something with no repair path.

A plain-text .dat alongside has none of that. It opens in Notepad, it disappears with the mod, and the worst case of a bug is losing upgrades - never the store.

What the file looks like

slot0.dat
walk=5
sprint=3
cashier=2

# kept for mods that are not currently installed; do not edit
nightowl.late_hours=2
supercart.wheels=1

Plain id=level text. The block at the bottom is the interesting part.

Uninstalling your mod does not delete progress

When Mega Tree reads the file and finds an id it does not recognise - because the mod that registered it is not installed right now - it keeps that line aside and writes it back out untouched on every save.

Player doesWhat happens to bigboxes.capacity=3
Removes your dll, keeps playing, buys something elseStill in the file, under the "kept for mods" comment
Puts your dll backYour Register claims it; the node comes back at level 3
Starts a new saveNothing carried over - it is per slot
Uses two saves with different mod setsEach slot keeps its own kept-lines
This had to be built before the API could open

Until 1.1.0 an unknown id was dropped on read, and the next save wrote the file without it. With no third-party nodes that never mattered. The moment mods can register, it becomes a player who tried a mod, removed it and came back to find the money they spent is gone - silently.

So the kept block is not a nicety. It is the thing that makes uninstalling a mod safe.

The cap is 4096 kept lines per slot, which no realistic mod set will reach.

Registering late is safe

Registration is not tied to load order. If you register a node after a save has already been read - mid-game, after a config change, from a coroutine - Mega Tree checks the kept lines for your id and adopts the level immediately. Your OnLevelChanged does not fire for it, but GetLevel is correct from the next line onwards.

csharp
var handle = tree.Register(definition);
Logger.LogInfo($"level restored from save: {handle.Level}");

Reading the current level

csharp
int lvl = MegaTreeApi.GetLevel("bigboxes.capacity");   // 0 if unknown or not owned

This is a dictionary lookup, so calling it inside a Harmony postfix that runs often is fine - that is the intended usage.

Slots and switching saves

The slot is read from the game's own save system, so it follows the player through every load path - Continue, Load, New Game. If they switch saves without quitting, Mega Tree notices within half a second, reloads the right file and fires SaveLoaded with the new slot index.

Clear your caches on SaveLoaded

Anything you remembered about the previous save - base values keyed by instance id, "already applied" flags, per-day counters - is wrong the moment another slot loads. Pooled objects reuse instance ids across saves, so a stale base value silently corrupts the new game.

csharp
MegaTreeApi.SaveLoaded += slot =>
{
    Base.Clear();
    _appliedToday = false;
};

What is not saved

Only the level number, per node id. Not your definition, not your icon, not your translations - those come from your dll every launch. Which is exactly what makes changing a price or an icon in an update harmless: the player's level is what persists.

Never change an id after release

The id is the key. Renaming bigboxes.capacity to bigboxes.box_size in version 1.1 means every player starts that line from zero, and their old level sits in the kept block forever waiting for an id that will never come back.

If you truly have to rename one, LegacyIds below is the way out.

Renaming an id without losing progress

Sometimes it is unavoidable - you shipped an id that does not fit the rules, or your mod changed shape. List the old names and the level comes with them:

csharp
tree.Register(new UpgradeDefinition
{
    Id        = "pallets.permit",
    LegacyIds = new[] { "pallet_permit" },   // what it used to be called
    // ...
});

On registration, Mega Tree looks for a kept level under each old id and moves the highest one onto the new id. The player never notices.

SituationWhat happens
New id at 0, old id has a levelMoves over, and the log says so
New id already has a levelNothing moves. Someone who already played with the new id outranks any old value
Several old ids with levelsThe highest wins; all of them are cleared from the save
An old id that was never usedSilence, no error
The current id listed among the old onesIgnored
It only runs once

The migration happens when the node registers and finds a kept level. After that the old id is gone from the save file, so leaving LegacyIds in your code forever costs nothing - it simply finds nothing on every later launch.

Telling a player where to look

When someone reports lost progress, these are the two files that matter:

FileWhat it is
BepInEx/config/MegaTree/slotN.datEvery upgrade level, yours included. Text.
AppData/LocalLow/Yolo Games Studio/Megastore Simulator/Save_N.dataThe game's own save. Binary - a text editor shows garbage, and that is normal, not corruption.

Deleting the game save does not delete mod progress, and uninstalling a mod cannot corrupt the game save. They are separate files on purpose.