Publishing & Deployment Issues May 24, 2026

GameMaker Studio 2 Steam Demo Writes Saves to Preview AppData After YYC Export - How to Fix

Fix GameMaker Studio 2 Steam demos that write saves under the wrong LOCALAPPDATA subtree after YYC export. working_directory vs ini paths, save_path_map.json, gamemaker_steam_export_receipt_v1.json, and installed Steam smoke.

By GamineAI Team

GameMaker Studio 2 Steam Demo Writes Saves to Preview AppData After YYC Export - How to Fix

Problem: Your GameMaker YYC export passed G3 cold launch on the one-evening export pipeline. After fest_demo Steam promotion, players report progress resets every launch. File Explorer shows *`.ini** or buffer saves under a **preview / IDE**%LOCALAPPDATA%subtree—not the path insave_path_map.json`.

Who is affected now: Teams shipping Windows YYC fest demos in June–October 2026 after the GameMaker export/save resource shipped. Export receipts pass while save APIs still resolve to IDE Run semantics: wrong display name, stale #macro SAVE_DIR, or working_directory assumptions copied from internal QA.

Fastest safe fix: Probe saves on Steam-installed exe only → lock save_dir / ini basename macros for all retail branches → diff save_path_map.json and gamemaker_steam_export_receipt_v1.json between internal and fest_demo → set save_root_match: true and gate_save_root_match: pass before SteamPipe → run Gate 6 installed smoke → add save_path to Wednesday metadata diff.

Direct answer

Progress is not “lost”—it is stored under the preview AppData profile your fest binary still uses. Branch promotion copied Game Options and macros from a profile QA tested in the IDE, not the packaged YYC save root players hit on Steam. ini_open, buffers, and custom save_dir helpers must target the same logical company/game pair on every retail branch. Fix the map, the macros, the re-export, and the receipt together; IDE Run and VM test do not validate fest behavior.

Why this issue spikes in June 2026

  1. The GameMaker export/save sanity resource made save_path_map.json standard—teams promote fest_demo before save_root_match exists on fest evidence.
  2. YYC exports are default for performance; teams still validate saves during IDE Run where working_directory points at temp folders, not the Steam install path.
  3. Display name or game project name changed for store branding while ini basenames stayed on the old folder.
  4. Playtest vs fest_public isolation fails when both branches share slot UI but different #macro SAVE_DIR values—see playtest isolation playbook.

Pair with 12 Free Defold GDevelop Ren'Py save-path audit templates. For GDevelop preview-folder drift, see GDevelop save-path help.

Symptoms and search phrases

  • Saves work in GameMaker IDE Run; Steam-installed demo always starts at level one.
  • %LOCALAPPDATA% contains two folders—one with old project display name, one with fest title.
  • gamemaker_steam_export_receipt_v1.json shows G3 pass but no save_root_match row.
  • QA validated Thursday YYC zip; fest_demo depot behaves differently.
  • ini_open("save.ini") succeeds but file appears under unexpected subtree.
  • working_directory in debug overlay shows Steam common path while saves land elsewhere.
  • Playtest branch saves persist; fest_public does not (shared slot label, different macro).
  • After enabling DEBUG_MODE on demo, saves write to dev-only folder.

Root causes (check in order)

  1. working_directory used as save root — correct beside exe on Steam; wrong during IDE Run; fest build never re-tested packaged.
  2. #macro SAVE_DIR or save_dir still points at preview — internal playtest path baked into shared scripts.
  3. Game Options display name changed — Windows save area follows product name; ini still uses old basename.
  4. Branch promotion copied options, not save macrosfest_demo Game Options differ; GML macros unchanged.
  5. DEBUG_MODE / dev define enabled on demo — alternate save branch in if (DEBUG_MODE) still compiled into retail.
  6. Duplicate gameproject / renamed .yyp without map update — new folder under AppData; players perceive reset.
  7. Wrong depot promoted — playtest binary on fest branch (see save-slot label case study).

Beginner path (first 20 minutes)

Prerequisites: Windows YYC build installed from Steam or local zip (not IDE Run), GameMaker project using ini and/or buffer saves.

  1. Install from fest_demo (or fest-profile local export identical to Steam).
  2. Play to first save trigger; note the time.
  3. Search %LOCALAPPDATA% for files modified in the last 10 minutes.
  4. Compare folder name to expected_localappdata_subtree in save_path_map.json.

Common mistake: Pressing Run in the IDE after export—always validate the packaged exe Steam ships.

Fastest safe fix path

Step 1 — Prove where the Steam build writes (packaged YYC only)

  1. Install from fest_demo branch.
  2. Delete documented save folders from old map (backup first).
  3. Launch; trigger save at first checkpoint.
  4. Locate new files:
Get-ChildItem -Path $env:LOCALAPPDATA -Recurse -ErrorAction SilentlyContinue |
  Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-10) } |
  Select-Object FullName, LastWriteTime

Optional in-game probe (remove before ship or guard with globalvar dev flag):

// One-shot overlay — fest debug build only
show_debug_message("working_directory=" + working_directory);
show_debug_message("LOCALAPPDATA=" + environment_get_variable("LOCALAPPDATA"));
save_open_ini();
show_debug_message("ini_slot0_exists=" + string(ini_key_exists("slot0")));
ini_close();

Pass: Path matches expected_localappdata_subtree in map—not IDE preview or retired product name.
Fail: Two subtrees exist → continue to Step 2.

Outbound references: GameMaker — Saving And Loading Data, Game Options, Microsoft — LOCALAPPDATA.

Step 2 — Normalize save_dir macros and ini basenames

Centralize save identity—no scene variables with absolute paths:

#macro SAVE_COMPANY "YourStudio"
#macro SAVE_GAME    "FestDemo2026"
#macro SAVE_INI     "demo_progress_v1.ini"

function save_open_ini() {
    ini_open(SAVE_INI); // resolves under GameMaker save area for packaged game
}
Anti-pattern Fix
ini_open(working_directory + "save.ini") Use basename only; let runtime pick save area
Different SAVE_INI per branch (playtest.ini vs demo.ini) One retail basename; version inside file
if (DEBUG_MODE) ini_open("dev_save.ini") Same basename; separate Steam branch, not define
Display name changed, SAVE_GAME macro stale Update macro + map together

Add to save_path_map.json:

{
  "schema": "save_path_map_v1",
  "engine": "gamemaker_studio_2",
  "company": "YourStudio",
  "game": "FestDemo2026",
  "export_type": "YYC",
  "expected_localappdata_subtree": "%LOCALAPPDATA%/YourStudio/FestDemo2026/",
  "ini_basenames": [
    {
      "slot_id": "demo_progress",
      "file": "demo_progress_v1.ini",
      "forbidden_substrings": ["preview", "internal_playtest"]
    }
  ],
  "save_format_version": 1
}

Lock Game Options → General → Game Settings display name to match game field before re-export.

Step 3 — Diff maps and receipts between branches

Before promoting fest_demo:

fc /n release-evidence\gamemaker\internal\save_path_map.json `
       release-evidence\gamemaker\fest_demo\save_path_map.json

Extend gamemaker_steam_export_receipt_v1.json:

{
  "schema": "gamemaker_steam_export_receipt_v1",
  "gamemaker_runtime": "2024.11.0.000",
  "export_type": "YYC",
  "gates": {
    "G3_cold_launch": "pass",
    "G6_save_root_match": "pass"
  },
  "save_root_probe": {
    "working_directory": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\FestDemo2026\\",
    "verified_localappdata_subtree": "%LOCALAPPDATA%/YourStudio/FestDemo2026/",
    "ini_basename": "demo_progress_v1.ini",
    "slot_count_after_round_trip": 3
  },
  "save_root_match": true,
  "build_label": "gm-nextfest-2026-05-24-rc1",
  "branch": "fest_demo"
}

Block promotion if save_root_match is not true or G6_save_root_match is not pass.

Step 4 — Re-export YYC fest profile and upload depot

  1. Open Windows / Steam Game Options preset for fest—not internal debug preset.
  2. Confirm *`#macro SAVE_` values match map before Create Executable**.
  3. Run save round-trip: save → quit exe → relaunch → load on same AppData subtree.
  4. Upload to fest_demo depot only.
  5. Log build_label in BUILD_RECEIPT.

Step 5 — One-time migration for early fest testers

If an old AppData subtree already shipped:

/// obj_save_controller — Create
if (!variable_global_exists("save_migrated_v1")) {
    if (file_exists_legacy_preview_ini()) {
        ini_open("demo_progress_v1.ini");
        // copy keys from legacy ini_read_* helpers
        ini_close();
        global.save_migrated_v1 = true;
    }
}

Ship player-facing note: first launch after patch may import progress—or reset if corrupt. Align store FAQ save claims.

Step 6 — Installed Steam smoke (Gate 6)

Run S4–S6 from Wednesday demo build smoke on the Steam-installed YYC build. IDE Run and unzipped Thursday folder do not satisfy this step.

Working dev path (proof table)

Check Command / artifact Pass signal
Save macros locked Grep SAVE_DIR, ini_open No absolute paths; one retail basename
Map parity fc save_path_map.json internal vs fest No differences
Save round-trip Gate 6 log Same AppData subtree after relaunch
Branch gate gamemaker_steam_export_receipt_v1.json save_root_match: true, G6_save_root_match: pass
Installed smoke Wednesday S4–S6 on Steam build Slot count unchanged
BUILD_RECEIPT row save_path column Hash of map + ini_basename

Attach evidence under release-evidence/gamemaker/<branch>/ beside export pipeline outputs—export sanity and persistence are separate gates.

Verification checklist

  • [ ] save_path_map.json identical on internal and fest_demo evidence folders.
  • [ ] SAVE_* macros unchanged since freeze week (or migration shipped).
  • [ ] No retired display name in verified %LOCALAPPDATA% path on installed Steam build.
  • [ ] save_root_match: true in fest receipt.
  • [ ] Save round-trip passes twice on fest build_label.
  • [ ] Gate 6 installed smoke GREEN.
  • [ ] Wednesday metadata diff includes save_path column.
  • [ ] DEBUG_MODE off on demo retail defines.
  • [ ] Playtest and fest use different ini basenames if both live—isolation playbook.

Prevention

  1. Treat branch promotion as “re-run Gates G3 + G6,” not “copy depot ID.”
  2. Add save_path_map.json to Monday export checklist beside texture page audit.
  3. Ban branch-specific ini basenames without documented migration—grep ini_open in scripts.
  4. Add CI job: fail if fest save_path_map.json ≠ internal or SAVE_GAME macro drifts.
  5. Pair with Construct NW.js save help in multi-engine studios.

Troubleshooting

Symptom Fix
IDE Run OK, Steam reset Re-run Step 1 on installed YYC; lock macros
Two AppData folders Old display name—migration or accept reset
ini exists, load empty Read basename ≠ write basename in script
Only fest branch fails Wrong depot promoted; verify build_label overlay
Playtest OK, fest bad Separate playtest_progress_v1.ini vs demo_progress_v1.ini
Export receipt pass, players fail Receipt from IDE Run, not Steam exe
VM export OK, YYC bad Rare—re-probe; confirm same Game Options preset

FAQ

Is this the same as GDevelop preview-folder drift?
Same branch promotion class—GDevelop save-path help uses Storage roots; GameMaker uses ini save area + display name + *`#macro SAVE_`**.

Does the one-evening export pipeline cover saves?
The GameMaker export sanity blog covers G1–G5; add G6_save_root_match for persistence before Steam upload.

YYC vs VM—does export type change save path?
Usually no—path drift comes from IDE vs packaged and macros, not YYC alone. Always probe the Steam-installed binary you ship.

Can I change the window title without breaking saves?
Store window title can differ from save identity—lock SAVE_GAME macro and Game Options display name together.

Does Steam Cloud fix this?
Only if implemented and FAQ-accurate. Default ini is local—document canonical path in save_path_map.json. If Cloud overwrites newer local saves after mid-cycle enable, see Steam Cloud sync overwrite fix.

Related links

Prove saves on the Steam-installed GameMaker YYC exe—IDE Run is not your fest demo.