Add a persistable state
Two common bugs: a state that silently won't (de)serialize because its type was never
registered, and a state that never gets saved because it wasn't added to the central
SaveService. This skill prevents both. Read the FileHandler and SaveService sections
in src/Game/Common/README.md and use
SaveService.cs as the reference.
Steps:
Define the state as a plain POCO in
<Module>/Domain/<Name>State.cs(public get/set properties, sane defaults, no logic, no Godot). If it lives in aCollectionRepository, give it anint Id(indexes/deserialization rely on it).Put it in a repository (
SingleRepository<T>orCollectionRepository<TKey,TValue>), created and seeded in GameLevel.Register the type in
GameLevelnext to the others:_jsonConverterStateService.Register(typeof(<Name>State));Without this line the serializer skips it. This is the step people forget — do not skip it.
Add the repository to SaveService. Saving is centralized — do NOT write file I/O in the module service. Take the new repository in the
SaveServiceconstructor and add it to both methods, keeping the list order identical:// Save(): single state → GetOne(), collection → GetAll() var data = new List<object?> { _idRepository.GetOne(), ..., _<name>Repository.GetOne() }; // Load(): single → Delete()+Update((T)data[i]!); collection → DeleteAll()+loop Update(key,(T)value!)Bump the
data is not { Count: N }guard inLoadto the new slot count. Pass the repository intoSaveServicefrom GameLevel. Also reset it in NewGameService (Delete()+Update(new ...)for single,DeleteAll()for collections) so "new game" clears it too.Custom field types (not handled by System.Text.Json) need a converter like
Vector2JsonConverterregistered inJsonConverterStateService.Observable state? If the state is observable, remember
SaveService.Loadreplaces the object — subscribers must re-subscribe after a load (seeadd-observer).Test with a mocked
IJsonStateFileHandlerService(seeSaveServiceTestsandadd-tests), then runverify.