Rolly Docs

Export and import saves as JSON

Write a save as Rolly Save JSON text to read it, attach it to a bug report or change it by hand, and import such a file as a new slot to test with.

Sheet
09 of 64
Rev
1.0.0
Updated
On this sheet

Export from the editor

In the Save Inspector, open the slot, profile or file and choose JSON > Export as JSON…:

Figure 1. Export Slot 1 as JSON: the file name Slot 1 over the export folder's path, Include Thumbnail, and Values Readable or Bytes Only.
  • File name: 1 to 64 letters, digits, spaces, _ and -, written as <name>.json in the export folder. An earlier Rolly Save JSON export of that name is replaced; any other file there is never replaced, and Export stays off.
  • Include Thumbnail, with the picture’s size; “No thumbnail” for a save without one.
  • Values: Readable writes values as numbers, names and texts; Bytes Only writes each value as its saved bytes in Base64, exact for every type. A save written with other versions than this build’s exports bytes only.

The export decodes values in slices of the editor’s frame, with progress and Cancel in the edit bar, and ends with the file’s size and Show in Explorer.

Export from your game

An export writes the slot’s newest valid copy: its header, every chunk and every record. With Readable Values on, values read as numbers, names and texts when the save’s package version and every custom version it records match this build’s. A version this build registers that the save does not record does not count, so your packaged game’s saves export readable values from the editor. A save that records a version at another number, as after an update changed it, exports each value as its saved bytes in Base64, which is exact for every type. Include Thumbnail off leaves the picture out. Exports work in every build, and on clients, from that machine’s storage. An export reads values on the game thread a slice at a time, at most JSON Export Time per Frame each frame, and writes the file as each record is read.

Blueprint

  • Export Rolly Slot to JSON File writes <File Name>.json in the export folder of Project Settings > Plugins > Rolly Save > Sharing Saves, through a temporary file. File Name follows the rules of Export Rolly Slot to File: 1 to 64 letters, digits, spaces, _ and -. An export replaces an earlier JSON export of that name, but never another file: that fails with Name Collision and the setup message ForeignFile. Files work on Windows, Mac and Linux.
  • Export Rolly Slot to JSON Text gives the same text in Json, on every platform, for a bug reporter of your own. Text longer than Max JSON Import Size fails with Invalid Data, gives no text and the setup message TextTooLarge. Compact, under the node’s advanced pins, leaves out line breaks and indentation, for a shorter text to upload.

C++

URollySaveSubsystem* Save = URollySaveSubsystem::Get(this);
Save->ExportSlotToJson(TEXT("Slot 1"), TEXT("Bug 12"));
Save->ExportSlotToJsonString(TEXT("Slot 1"), /*bIncludeThumbnail*/ false, /*bReadableValues*/ true,
	[](const FRollySaveResult& Result, const FString& Json)
	{
		// Attach Json to the report when Result succeeded.
	});
Save->ImportSlotFromJson(TEXT("Bug 12"), TEXT("Imported 1"));
C++

RollySaveJson::Write and RollySaveJson::Read (Json/RollySaveJson.h) turn an FRollySaveFile into JSON text and back without a game, as tools need.

Console

  • rolly.save.json.export <slot> <file name> [-profile] [-compact] exports a slot, or with -profile the profile of that key, as <file name>.json; -compact leaves out line breaks and indentation. Put a name with spaces in quotes.
  • rolly.save.json.import <file name> <slot> imports <file name>.json as a new slot.

Both run in the world the command is typed in, or in the first game world, and write their end to the log.

Read and change the JSON

The file is one object: format (RollySaveJson), version (1), source (the slot, copy and sequence it came from; ignored on import), header and chunks.

  • header holds the versions, gameDataVersion, kind, key, displayName, saveTime (in ticks), writer, metadata, thumbnail and edit when set, and carried, header fields of a later version.
  • Each chunk has its id, key and flags, then records, carried for a chunk of a later version, or bytes.
  • Each record has its subject, class (an index into imports, or null), its tables names, imports and references, and sections.
  • A section holds values (PROP and PATH), objects (INLN), fields (ACTR and COMP; ACTR’s asleep is true or false, and its levelInstance is {"loaded", "asset", "design"} with the level and its design as indexes into imports, design absent when it is the level), instances (INST and INSK: flags, mesh, designCount, customFloats and the removed, changed and added entries), destruction (GCOL: flags, collection, structureHash, the pieces’ state and dynamicState, and the transforms of the broken pieces), pcgOutput (PCGI: a list of instances bodies, one per mesh, in the order of the meshes’ paths) or bytes. A section of flags this version does not know travels as bytes.
  • A value is {"name", "type", "value"}, or {"name", "type", "bytes", "shown"} when it travels as bytes; shown is for reading and is ignored on import. A struct’s value is an array of its members; a map’s entries are {"key", "value"}; a reference is null, {"saved": {"kind", "text"}}, {"import": {"path", "class", "hard"}} or {"owned": <index>}. A property bag, such as a StateTree’s parameters, is {"head", "values"}: head holds its layout as saved, in Base64, and values its values as a struct’s members; a bag without values has head only. Change a value inside values and keep head as it is: an import checks the values against the layout and refuses a bag whose values its head does not have.

Change a value in place and keep its type. Names typed by hand that the record’s names table lacks are added to it; numbers are exact: whole numbers inside their type, floats and doubles as decimal text, and "NaN", "Infinity" or "-Infinity" as strings. Keys are case-sensitive and may come in any order, except that a value’s type comes before its value; a key the format lacks, or one given twice, is refused.

Import a JSON file

In the editor, choose JSON > Import JSON as Slot… in the Save Inspector. The file opens read-only first, with its records and values as the slot will hold them, and a banner says whether it passes Rolly Save’s import check, which reads a large file over several frames; nothing is written yet. Import as Slot… then asks the slot’s name, the JSON’s own slot or the file’s name to start with, and sums up what it writes.

Figure 2. Slot 1.json opened in the Save Inspector before its import: the banner says it passes the import check, and Import as Slot is offered.

From your game:

Import Rolly Slot from JSON File reads <File Name>.json from the export folder and stores it as the new slot Slot Name. Before anything reaches storage it:

  1. refuses a file larger than Max JSON Import Size unread (Invalid Input, setup message TooLarge);
  2. reads the text token by token and refuses, at its line and column, a syntax error or a value past a bound, such as a name of more than 1,023 characters, 300 for an Int8 or a record whose values would take more memory than is left of the decoded save’s 1 GiB, counted as each value is read (Damaged, NotImported; such a save imports when exported again with Readable Values off); a later format is NewerFormat (Newer Version);
  3. refuses readable values when the file records its package version or a custom version at another number than this build’s (Invalid Data, ValuesNeedVersions): export such a save again with Readable Values off;
  4. refuses a profile’s or the slot index’s JSON (Invalid Input, KindNotSlot) and a Game Data Version above the project’s (Newer Version, NewerGameData);
  5. writes and reads the file it holds as storage would, then runs every check of Import Rolly Slot from File: each record’s structure, the versions and the run rules (Damaged, CheckFailed).

An import never overwrites: a slot that holds a save fails with Slot Exists. The imported save is marked as edited (the header field edit, tool 2), and the game’s later saves of a game loaded from it keep the mark, so a bug report from a hand-edited save can be told apart. Starting a new game drops it.

Each refusal names the file and what to fix in the Message Log; the setup messages list them.

Allow JSON imports in Shipping builds

Imports run in the editor and in Debug and Development builds; Shipping and Test builds import only with JSON Import in Shipping on. In Project Settings > Plugins > Rolly Save > Sharing Saves:

Setting Default Does
Max JSON Import Size (MiB) 256 (1 to 2,048) Larger JSON files are refused unread, and Export Rolly Slot to JSON Text makes no longer text
JSON Export Time per Frame 4 ms (0.5 to 50) How long an export may read values on the game thread each frame: lower keeps frames steadier while a game exports, higher finishes sooner
JSON Import in Shipping Off Lets Shipping and Test builds import JSON, such as builds sent to testers. Off, players cannot load hand-edited saves through JSON; export works in every build

With JSON Import in Shipping off, an import in a Shipping or Test build fails with Invalid Input and the setup message ImportOff.