Skip to content

Save games

Craftwright doesn’t save anything by itself. Crafters, stations and the built-in inventory export their state as plain structs, and import it again. The structs use soft object paths for items and recipes, so they work as SaveGame properties of any USaveGame, or with your own serializer.

Component Export Import Struct
Craftwright Crafter Export Save Data Import Save Data (Data, Catch Up Offline Time = true) FTACraftwrightCrafterSaveData
Craftwright Station Export Queue Save Data Import Queue Save Data (Data, Catch Up Offline Time = true) FTACraftwrightQueueSaveData
Craftwright Inventory Export Save Data Import Save Data (Data) FTACraftwrightInventorySaveData

In Blueprint, search for “Crafter Save Data”, “Queue Save Data” or “Inventory Save Data” when you pick a variable type.

The crafter also has Export Queue Save Data and Import Queue Save Data for its queue alone. Imports run on the server and replace the current state.

Struct Fields
FTACraftwrightCrafterSaveData Queue (a queue save data), Known Recipes (each with Recipe and Uses Left) and Tracked Recipes (each with Recipe and Count)
FTACraftwrightQueueSaveData Jobs, Tray, Fuel Remaining (stations: seconds left on the burning fuel item) and Saved At Utc
FTACraftwrightSavedJob Recipe, Count, Completed, Unit Duration (with the job’s speed), Elapsed (progress of the current unit), Consumed (what the job took, for refunds), Salvage (the job salvages) and Luck (the crafter’s luck when the job was queued)

Jobs keep their speed, luck and whether they salvage. | FTACraftwrightInventorySaveData | Items: each with Item (a soft path) and Count |

Not saved: the crafter’s Crafter Tags and recipe books, the stations’ settings and anything else you set up in the editor. Those come from your assets and Blueprints. Always Known recipes come from the books and need no saving.

On import:

  • Items and recipes that can’t be loaded any more (renamed or deleted assets) are skipped.
  • Finished jobs are skipped; the rest are queued in their saved order with their progress, and the first one works.
  • Jobs get new job ids.
  • Crafter jobs belong to the crafter again. Station jobs have no crafter after loading: their outputs and refunds go into the station’s tray, and any crafter in range can cancel them.
  • The built-in inventory takes the saved contents as they are, without checking its slots.

When Catch Up Offline Time is on (the default), importing a crafter or station queue simulates the time that passed since Saved At Utc, the UTC time of the export. A smelter left running overnight has its ingots ready when the game is loaded.

  • The time is limited by the component’s Max Offline Seconds (default 0, no limit). Set it to, for example, 3600 to catch up at most an hour.
  • Stations burn fuel during the catch-up. When the fuel runs out, the remaining time is not used, as in play. Is Powered is evaluated at load time.
  • Units finished during the catch-up deliver their outputs right away: crafter jobs into the crafter’s inventories, station jobs into the station’s tray.
  • Turn Catch Up Offline Time off for games where time should stop while they are closed, or when you load a save into a running session.
  1. Create a SaveGame Blueprint (or C++ class) with variables for the save structs, for example Crafter (crafter save data), Bag (inventory save data) and Forge (queue save data). For stations and chests placed in the level, use a map from a stable id (for example the actor’s name or a GUID you assign) to the save data.

  2. To save, on the server: call Export Save Data on the player’s crafter and inventory and Export Queue Save Data on each station, store the results in the save game object and call Save Game to Slot.

  3. To load, on the server: Load Game from Slot, then Import Save Data on the inventories first, then Import Save Data on the crafter and Import Queue Save Data on each station.

In C++:

MySaveGame.h
UCLASS()
class UMySaveGame : public USaveGame
{
GENERATED_BODY()
public:
UPROPERTY(SaveGame)
FTACraftwrightCrafterSaveData Crafter;
UPROPERTY(SaveGame)
FTACraftwrightInventorySaveData Bag;
UPROPERTY(SaveGame)
TMap<FName, FTACraftwrightQueueSaveData> Stations;
};
// Save (server)
Save->Bag = Inventory->ExportSaveData();
Save->Crafter = Crafter->ExportSaveData();
Save->Stations.Add(ForgeActor->GetFName(), ForgeStation->ExportQueueSaveData());
// Load (server): inventories first
Inventory->ImportSaveData(Save->Bag);
Crafter->ImportSaveData(Save->Crafter, /*bCatchUpOfflineTime*/ true);
if (const FTACraftwrightQueueSaveData* Data = Save->Stations.Find(ForgeActor->GetFName()))
{
ForgeStation->ImportQueueSaveData(*Data, true);
}

Every field of the structs is marked SaveGame, so they also work with save systems that serialize SaveGame properties of actors and components.