u/BumblebeeElegant6935

Persistence — A source-generated save/load system for Godot 4 C#
▲ 29 r/GodotCSharp+1 crossposts

Persistence — A source-generated save/load system for Godot 4 C#

I've been working on a C# library for Godot called Persistence, a save/load system built around Roslyn source generation.

The main goal is to avoid manually building dictionaries and writing serialization/deserialization boilerplate for every object that needs to be saved.

You mark the data you want to persist with [Save], implement ISavable, and Persistence generates the serialization code for you:

public partial class Player : CharacterBody2D, ISavable
{
    public string SaveKey => "player";
    public int SaveVersion => 1;

    [Save] public int Health = 100;
    [Save] public string PlayerName;
    [Save] public Vector2 Position;
}

Saving and loading can then be handled through SaveManager:

SaveManager.Save("slot1", savableNodes);

SaveManager.Load("slot1", savableNodes);

Persistence currently uses JSON for its save files. I chose JSON because, for the kinds of games I typically work on, it provides more than enough capacity while keeping save files easy to inspect and debug.

Custom data

For types that aren't directly serializable, Persistence provides ISerializable.

This is especially useful for custom game data such as inventory slots, quest data, stats, or other structures that don't map directly to Godot's Variant types:

public class InventorySlot : ISerializable
{
    public string ItemId;
    public int Count;

    public Dictionary Serialize() => new()
    {
        ["itemId"] = ItemId,
        ["count"] = Count
    };

    public void Deserialize(Dictionary data)
    {
        ItemId = data["itemId"].AsString();
        Count = data["count"].AsInt32();
    }
}

It can then be used directly inside an ISavable:

[Save] public InventorySlot Weapon;
[Save] public List<InventorySlot> Inventory;

ISerializable is also the main way to handle custom types that don't have built-in serialization support.

Manual serialization alongside [Save]

You don't have to choose between generated and manual serialization. Both can be used together.

Persistence provides OnSerialize and OnDeserialize hooks for cases where [Save] isn't enough:

public void OnSerialize(SaveData saveData)
{
    saveData.Set("customField", someValue);
}

public void OnDeserialize(SaveData saveData)
{
    someValue = saveData.Get("customField", default);
}

This lets you use [Save] for the straightforward fields while manually handling special cases in the same class.

Save versions & migrations

Save data can also be versioned so changes to a game's data structure don't immediately invalidate existing saves.

For example, if version 0 stored health under "HP" and version 1 changed it to "Health":

public class PlayerMigration_V0_To_V1 : SaveMigration
{
    public override string SaveKey => "player";
    public override int FromVersion => 0;

    public override SaveData Migrate(SaveData saveData)
    {
        saveData.Set("Health", saveData.Get("HP", 100));
        return saveData;
    }
}

The migration can then be registered when loading:

var migrations = new MigrationRegistry(new SaveMigration[]
{
    new PlayerMigration_V0_To_V1()
});

SaveManager.Load("slot1", savableNodes, migrations);

Migrations can be chained, allowing old saves to be upgraded through multiple versions:

Save v0
   ↓
V0 → V1
   ↓
V1 → V2
   ↓
Save v2

Other features

  • Source-generated serialization/deserialization
  • Save slots
  • Custom save keys
  • Manual serialization hooks
  • Godot Variant-compatible types
  • List<T>, arrays, and Godot.Collections.Array<T>
  • Nested ISerializable types
  • Save data versioning and migrations

The project is still relatively young, but the core system is usable and covers the save/load needs I've encountered so far.

github.com
u/BumblebeeElegant6935 — 21 hours ago
▲ 76 r/godot

What do you think about the current state of C# in Godot?

I've been using C# with Godot for around 1.5 years now, after previously using GDScript, and I feel like C# has improved quite a lot since Godot 4.

Personally, I've really enjoyed using it. It also made me learn a lot of things that I didn't really think about when I was using GDScript, especially with the wider .NET ecosystem and software architecture.

One thing I really like about C# is the amount of language and tooling available for structuring larger projects. Things like static classes, extension methods, reflection, source generators, and the wider .NET ecosystem give you a lot of ways to organize code and keep things readable. Obviously, you can over-engineer with these features too, but having them available is something I've found useful.

I also really like that I can use external .NET libraries alongside Godot plugins without feeling too restricted to the engine's ecosystem.

The main thing I feel is still lacking is the community/resources around C#. There are tons of Godot tutorials, examples, and discussions, but a lot of them are GDScript-focused. Sometimes you end up having to figure out the C# equivalent yourself or dig through the API.

I'm not saying C# needs to replace GDScript. I'm just curious how other C# users feel about it. Do you think the C# side of Godot is in a good place right now?

reddit.com
u/BumblebeeElegant6935 — 10 days ago

Takobi AI

download link: https://godotengine.org/asset-library/asset/5314

repo link: https://github.com/AhmedGD1/takobi_ai

Hi, I’ve been working on a Behavior Tree library for Godot C#.

Most AI/BT tools in the ecosystem are GDScript-first, so I built this specifically for C# workflows and editor tooling.

Features

  • Live BT debugger (Editor dock, real-time node status)
  • Blackboard binding with $key syntax
  • Custom inspectors (methods, signals, comparisons)
  • SubTree support (reuse + nesting)
  • Built-in Performance Monitor integration
  • Cached execution path (minimal allocations)

HSM support is also in progress.

Feedback is welcome 👍

u/BumblebeeElegant6935 — 2 months ago