{"id":21306077,"url":"https://github.com/chickensoft-games/savefilebuilder","last_synced_at":"2026-04-02T22:58:33.312Z","repository":{"id":243603802,"uuid":"812860196","full_name":"chickensoft-games/SaveFileBuilder","owner":"chickensoft-games","description":"Compose chunks of save data into a single data type by creating loosely coupled save chunks at various points in the scene tree.","archived":false,"fork":false,"pushed_at":"2025-03-31T01:40:32.000Z","size":79,"stargazers_count":11,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-05T16:08:39.669Z","etag":null,"topics":["chickensoft","csharp","godot","save","serialization"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/Chickensoft.SaveFileBuilder","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chickensoft-games.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-10T03:17:51.000Z","updated_at":"2025-03-31T01:39:51.000Z","dependencies_parsed_at":"2024-06-10T05:38:37.073Z","dependency_job_id":"c49643c5-42e2-4157-8296-d3a5bf4c61ab","html_url":"https://github.com/chickensoft-games/SaveFileBuilder","commit_stats":null,"previous_names":["chickensoft-games/savefilebuilder"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chickensoft-games%2FSaveFileBuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chickensoft-games%2FSaveFileBuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chickensoft-games%2FSaveFileBuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chickensoft-games%2FSaveFileBuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chickensoft-games","download_url":"https://codeload.github.com/chickensoft-games/SaveFileBuilder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248938049,"owners_count":21186331,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chickensoft","csharp","godot","save","serialization"],"created_at":"2024-11-21T16:21:22.267Z","updated_at":"2026-04-02T22:58:33.307Z","avatar_url":"https://github.com/chickensoft-games.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 👽 SaveFileBuilder\n\n[![Chickensoft Badge][chickensoft-badge]][chickensoft-website] [![Discord][discord-badge]][discord] [![Read the docs][read-the-docs-badge]][docs] ![line coverage][line-coverage] ![branch coverage][branch-coverage]\n\nCompose chunks of save data into a single data type by creating loosely coupled save chunks at various points in the scene tree.\n\n---\n\n\u003cp align=\"center\"\u003e\n\u003cimg alt=\"Chickensoft.SaveFileBuilder\" src=\"Chickensoft.SaveFileBuilder/icon.png\" width=\"200\"\u003e\n\u003c/p\u003e\n\n## 🥚 Getting Started\n\nFind the latest version of [`Chickensoft.SaveFileBuilder`][nuget] on nuget.\n\n```sh\ndotnet add package Chickensoft.SaveFileBuilder\n```\n\n## 📄 SaveFile and Root SaveChunk\n\nFind the highest node in your scene tree that needs to be concerned with save data to use as the root of your save file. Use [AutoInject] to provide the root save chunk to all its descendant nodes.\n\n\u003e [!TIP]\n\u003e Check out the Chickensoft [Game Demo] for a complete, working example of using SaveFileBuilder to save composed states of everything that needs to be persisted in a game.\n\n```csharp\nusing Chickensoft.Introspection;\nusing Chickensoft.AutoInject;\nusing Chickensoft.SaveFileBuilder;\nusing Godot;\n\n[Meta(typeof(IAutoNode))]\npublic partial class Game : Node3D\n{\n  public SaveFile\u003cGameData\u003e SaveFile { get; set; } = default!;\n\n  // Provide the root save chunk to all descendant nodes.\n  ISaveChunk\u003cGameData\u003e IProvide\u003cISaveChunk\u003cGameData\u003e\u003e.Value() =\u003e SaveFile.Root;\n\n  public void Setup()\n  {\n    SaveFile = new SaveFile\u003cGameData\u003e(\n      root: new SaveChunk\u003cGameData\u003e(\n        onSave: (chunk) =\u003e {\n          // Use root chunk to get child chunks that were added to us\n          // lower in the scene tree.\n          var gameData = new GameData()\n          {\n            MapData = chunk.GetChunkSaveData\u003cMapData\u003e(),\n            PlayerData = chunk.GetChunkSaveData\u003cPlayerData\u003e(),\n            PlayerCameraData = chunk.GetChunkSaveData\u003cPlayerCameraData\u003e()\n          };\n\n          return gameData;\n        },\n        onLoad: (chunk, data) =\u003e\n        {\n          // Break up the game data and send it to the child chunks so that\n          // they can load the data into the nodes they belong to.\n          chunk.LoadChunkSaveData(data.MapData);\n          chunk.LoadChunkSaveData(data.PlayerData);\n          chunk.LoadChunkSaveData(data.PlayerCameraData);\n        }\n      ),\n      onSave: async (GameData data) =\u003e\n      {\n        // Save the game data to disk.\n        var json = JsonSerializer.Serialize(data, JsonOptions);\n        await FileSystem.File.WriteAllTextAsync(SaveFilePath, json);\n      },\n      onLoad: async () =\u003e\n      {\n        // Load the game data from disk.\n        if (!FileSystem.File.Exists(SaveFilePath)) {\n          GD.Print(\"No save file to load :'(\");\n          return null;\n        }\n\n        var json = await FileSystem.File.ReadAllTextAsync(SaveFilePath);\n        return JsonSerializer.Deserialize\u003cGameData\u003e(json, JsonOptions);\n      }\n    );\n\n    ...\n  }\n}\n```\n\n## 🍪 Defining Save Chunks\n\nSaveChunks are smaller pieces of save data that are composed together into the overall save file's data. Simply add a chunk to a descendant node of the scene with the root SaveChunk and register it with the root save chunk once you've resolved dependencies with AutoInject.\n\n```csharp\n[Meta(typeof(IAutoNode))]\npublic partial class Player : CharacterBody3D\n{\n  [Dependency]\n  public ISaveChunk\u003cGameData\u003e GameChunk =\u003e this.DependOn\u003cISaveChunk\u003cGameData\u003e\u003e();\n  public ISaveChunk\u003cPlayerData\u003e PlayerChunk { get; set; } = default!;\n\n  public void Setup()\n  {\n    ...\n\n    PlayerChunk = new SaveChunk\u003cPlayerData\u003e(\n      onSave: (chunk) =\u003e new PlayerData()\n      {\n        GlobalTransform = GlobalTransform,\n        StateMachine = (PlayerLogic)PlayerLogic,\n        Velocity = Velocity\n      },\n      onLoad: (chunk, data) =\u003e\n      {\n        GlobalTransform = data.GlobalTransform;\n        Velocity = data.Velocity;\n        PlayerLogic.RestoreFrom(data.StateMachine);\n        PlayerLogic.Start();\n      }\n    );\n\n    ...\n  }\n\n  public void OnResolved()\n  {\n    // Add a child to our parent save chunk (the game chunk) so that it can\n    // look up the player chunk when loading and saving the game.\n    GameChunk.AddChunk(PlayerChunk);\n\n    ...\n  }\n}\n```\n\nOnce a save chunk has been added to a parent save chunk, the parent save chunk can access it from the callbacks specified by `onSave` and `onLoad`, querying its data or forcing it load data into its node.\n\n\u003e [!TIP]\n\u003e You can define easily serializable types, as well as serialize entire [LogicBlocks] with [Chickensoft.Serialization].\n\n---\n\n🐣 Package generated from a 🐤 Chickensoft Template — \u003chttps://chickensoft.games\u003e\n\n[chickensoft-badge]: https://chickensoft.games/img/badges/chickensoft_badge.svg\n[chickensoft-website]: https://chickensoft.games\n[discord-badge]: https://chickensoft.games/img/badges/discord_badge.svg\n[discord]: https://discord.gg/gSjaPgMmYW\n[read-the-docs-badge]: https://chickensoft.games/img/badges/read_the_docs_badge.svg\n[docs]: https://chickensoft.games/docs\n[line-coverage]: Chickensoft.SaveFileBuilder.Tests/badges/line_coverage.svg\n[branch-coverage]: Chickensoft.SaveFileBuilder.Tests/badges/branch_coverage.svg\n\n[AutoInject]: https://github.com/chickensoft-games/AutoInject\n[Game Demo]: https://github.com/chickensoft-games/GameDemo\n[LogicBlocks]: https://github.com/chickensoft-games/LogicBlocks\n[Chickensoft.Serialization]: https://github.com/chickensoft-games/Serialization\n[nuget]: https://www.nuget.org/packages/Chickensoft.SaveFileBuilder\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchickensoft-games%2Fsavefilebuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchickensoft-games%2Fsavefilebuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchickensoft-games%2Fsavefilebuilder/lists"}