Cronus Zen Guide
GPC Scripting 4 min read

GPC persistent variables: saving settings with SPVAR, get_pvar and set_pvar

How to make a Cronus Zen script remember settings between sessions: the 64 per-slot SPVAR stores, validated loading with get_pvar's range and default, event-driven saving with set_pvar, and the mistakes that wear out flash or corrupt values.

Updated
GPC script code on a dark editor

Quick answer

GPC gives each memory slot 64 private persistent stores, SPVAR_1 to SPVAR_64, that survive power cycles. Load them in init with get_pvar(slot, min, max, default), which returns the default if the stored value is out of range, and write them with set_pvar only when the user deliberately saves a setting. Never call set_pvar every cycle.

Why do scripts forget things?

Every variable you declare with int lives in RAM. Unplug the Zen and it is gone. For a toggle that resets each session that is fine, but a sensitivity value the player spent ten minutes tuning should still be there tomorrow. Persistent variables solve this.

What is an SPVAR?

SPVAR_1 through SPVAR_64 are 64 persistent stores that belong to the current memory slot. Each holds a signed 32-bit integer and survives power loss. Because they are per slot, two scripts in different slots can both use SPVAR_1 without interfering. You access them through two built-ins:

  • get_pvar(SPVAR_n, min, max, default) reads a store.
  • set_pvar(SPVAR_n, value) writes one.

There is no direct variable syntax; you always go through the functions, then keep a working copy in an ordinary int.

How do I load settings safely?

Load in init, which runs once when the slot starts, and always with a real range:

gpc
int strength;
int mode;

init {
    strength = get_pvar(SPVAR_1, 0, 100, 25);
    mode     = get_pvar(SPVAR_2, 0, 3, 0);
}

get_pvar returns the stored value if it lies between min and max, otherwise the default. This gives you three things for free:

  1. First-run defaults. A fresh slot holds garbage; the range check rejects it and you get 25 and 0.
  2. Protection against a changed layout. If a previous version of your script stored something else in SPVAR_1, an out-of-range value falls back to the default instead of crashing behaviour.
  3. Input validation. A setting can never load as a value your code does not expect.

The official guide's phrasing is worth quoting: "Pick a range that actually validates the field." 0, 32767 validates nothing.

How do I save without wearing out the flash?

The official example separates "changed" from "saved":

gpc
int strength = 25;
int settings_dirty;

main {
    if(event_press(PS5_UP)) {
        strength = strength + 1;
        if(strength > 100) strength = 100;
        settings_dirty = TRUE;
    }
    if(settings_dirty && event_press(PS5_OPTIONS)) {
        set_pvar(SPVAR_1, strength);
        settings_dirty = FALSE;
    }
}

Pressing Up adjusts the working copy and marks it dirty. Only a deliberate press of Options writes to flash, and only if something changed. The guide states the rule directly: do not put set_pvar at base level in main. A write every cycle is hundreds of writes a second into memory with a finite life.

The pattern also gives you an undo for free: if the player changes a value and unplugs without saving, the old value loads next time.

How should I structure a settings menu?

A common layout for a script with several adjustable values:

  1. Enter edit mode with a chord, for example holding L2 and pressing Options. Set editing = TRUE and show a menu line on the OLED.
  2. Select a field with Left and Right, changing an int field index.
  3. Adjust with Up and Down, clamping to each field's range and marking dirty.
  4. Save and exit with Options: write only the fields that are dirty, then editing = FALSE.
  5. Cancel with Circle: reload from get_pvar to discard changes.

The official architecture guide has a page whose title is a design principle in itself: "edit, view and save are different operations." Keep them separate and the script stays predictable.

Where do things go wrong?

  • Saving every cycle. Covered above. If a script's OLED flickers or the Zen feels sluggish while a value is held, look for a set_pvar in the hot path.
  • No range validation. A first run loads a huge number and the script behaves wildly until the user manually fixes every field.
  • Changing what a store means between script versions without changing the range or adding a version field. Recipe 8 in the official examples shows a versioned, packed SPVAR that detects an old layout and resets.
  • Assuming sharing across slots. It does not happen. For shared data the guide documents BVAR storage with indexes 0..1023, a different tool with different ownership rules.
  • Testing only the happy path. The official persistence test matrix is a checklist: fresh slot, saved value, out-of-range value, power cycle, reprogram. Run through it once.

How do I debug a value that won't stick?

  1. Confirm the save code is actually reached. Put set_val(TRACE_1, 1) next to the set_pvar and watch Device Monitor.
  2. Confirm the load range includes the value you saved. A saved 100 with a load range of 0, 99 silently becomes the default.
  3. Confirm you are looking at the same slot. Reprogramming a slot keeps its SPVARs; moving the script to another slot does not.
  4. Read the official persistence diagnosis page, which walks through the same steps in more depth.

What comes next?

With input, timing and persistence covered, you have the three parts of any real script. The remaining piece is feedback: telling the player what state the script is in. Continue with OLED and LED feedback in GPC, or revisit the beginner path at GPC scripting 101.

Frequently asked questions

Are SPVARs shared between slots?
No. The official guide says SPVAR_1 to SPVAR_64 are private to the current memory slot. A script in slot 2 cannot read what a script in slot 3 saved. For values shared across slots the guide documents BVAR storage.
What does get_pvar return the first time, before anything is saved?
The default you pass as the fourth argument, because the stored data will not be inside your min and max range. That is why the range should genuinely validate the field rather than being 0 to 32767.
How often can I call set_pvar?
Only on a deliberate save action. The official guide explicitly says not to put set_pvar at base level in main. Flash memory has a finite number of write cycles and a write every cycle would wear it quickly.
Can I store more than one setting in a single SPVAR?
Yes, by bit packing several small values into one 32-bit integer. The official guide has pages on manual bit packing and a versioned packed SPVAR example. Start with one value per store until you need more.

Sources

Every link was live when this guide was last updated.

  1. 01SPVAR storage (official GPC guide)guide.cronuszen.com
  2. 02Validated persistent setting example (official GPC guide)guide.cronuszen.com
  3. 03Pick storage by lifetime and ownership (official GPC guide)guide.cronuszen.com
  4. 04Persistence diagnosis (official GPC guide)guide.cronuszen.com

This guide is independent and unofficial; product names belong to their owners. Found an error? Use the contact page and we will correct it and note the change.