Live data from Hacker News

Serialization for C# Games

chickensoft.games

11–20 of 51 posts

Re: Serialization for C# Games

#11
post #5

In my personal projects I’ve been using variations on the same simple code for saving/loadings objects for a decade or so, and have very few problems. The heart of the code is this interface - public interface IStashy { void Save (T t, K id); T Load (K id); IEnumerable LoadAll (); void Delete (K id); K GetNewId (); } And implementations of that are very stable over time. Objects get serialized as json and stored in a…

> I generally won’t remove a property, but mark it as obsolete and stop using it. Presumably because loading will break? > - If I’ve added a new Boolean property, I’d tend to name it such that it defaults to false, or if it must default to true, have it stored in a nullable boolean, and if it loads as null (from an older instance of the type), set it to the default. Why?

`default(Boolean)` is false, so you can load an old object and it'll substitute the default, rather than having to throw an error on a missing property. You could do the same with, say, a new Int32 field, so long as it should default to zero.

Similarly, `default(Nullable)` is (wait for it) null, so you can do "oldVal ?? true".

Re: Serialization for C# Games

#12

Naive question: is there a reason why SQLite wouldn’t work for something like this?

Well you still need to solve for what happens when a new version of your app (maybe with a new embedded version of SQLite) loads up an old data file saved by an old version of your app. The old version might not contain all the tables you need, and the ones it has may not have the columns you expect. So you need to run some data migrations on the database. Now you no longer have a serialization problem but instead yo…

Could solve this with a migration framework (I'm sure there is something for sqlLite). I've also done something similar with object/document storage. Store the version of the schema in the record and write a map function for each version from the previous.

Re: Serialization for C# Games

#13
post #6

RunUO has an implementation of this and it's like 25 years old but still worked really well

Wow clicked into the thread to see if anyone might mention RunUO :) it’s the only exposure I’ve had to serialization in C# I always wondered how it ranked compared to other approaches.

As someone that also fell in love with C# with RunUO. I never actually looked at the Serialization at the time. Need to spend some time in RunUO or the fork soon.

https://github.com/runuo/runuo/blob/master/Server/Serializat...

Re: Serialization for C# Games

#14
post #11

Earlier quoted context omitted.

> I generally won’t remove a property, but mark it as obsolete and stop using it. Presumably because loading will break? > - If I’ve added a new Boolean property, I’d tend to name it such that it defaults to false, or if it must default to true, have it stored in a nullable boolean, and if it loads as null (from an older instance of the type), set it to the default. Why?

`default(Boolean)` is false, so you can load an old object and it'll substitute the default, rather than having to throw an error on a missing property. You could do the same with, say, a new Int32 field, so long as it should default to zero. Similarly, `default(Nullable )` is (wait for it) null, so you can do "oldVal ?? true".

(I meant to respond to the gp comment here, soz. I agree with everything the parent comment says.)

> Presumably because loading will break?

I think the object will still load ok, I’m not sure if it would break because it’s been so long since I was in a scenario where I wanted to really delete a property. Normally when I make it obsolete there is also some new property or properties that have replaced it. When loading the object, if the (now obsolete) property is not null, I translate its value into the new property/ies (I.e., “migrate” it into the new properties), then null out the old property value, so that the migration only happens that one time.

I guess using something allegedly “simple”, over a long time, only appears simple because you will slowly internalise any idioms you’re using, and they don’t take much thought anymore.

Looking back — I’ve used this pattern for over 20 years, across various platforms. I’ve had a backing source that is anything from xml files to json to sqlite to in memory (for rapid tests) in a few languages. Things that seem natural or intuitive (to me) at this point are just habits that are rusted on, whether good or bad.

Sometimes I start building fast indexing systems on top of it, or archiving systems or record versioning… and the better tool would be to switch to a db or to a more full featured key value store. But it’s such a lot of fun!

Re: Serialization for C# Games

#16

Naive question: is there a reason why SQLite wouldn’t work for something like this?

You could use it, but it's not really solving the same problem.

For a game, you generally don't need the relational database features. You aren't doing queries. You just want to load an entire level into memory, or save an entire level. For the serialization and persistence aspect, I don't see an advantage of SQLite over just calling JsonSerializer.Serialize().

The author's system then adds a bunch of features like version tolerance, AOT compilation of class metadata for iOS, polymorphic serialization, support for List and Dictionary, integration with the Godot game engine, etc. As far as I know, SQLite doesn't help you with any of that.

Anything that can write data to disk can ultimately save and load your game data; it's just a question of how easily.

Re: Serialization for C# Games

#17
post #5

In my personal projects I’ve been using variations on the same simple code for saving/loadings objects for a decade or so, and have very few problems. The heart of the code is this interface - public interface IStashy { void Save (T t, K id); T Load (K id); IEnumerable LoadAll (); void Delete (K id); K GetNewId (); } And implementations of that are very stable over time. Objects get serialized as json and stored in a…

(Blogpost with an implementation of IStashy is here — https://secretgeek.net/stashy_gist)

Re: Serialization for C# Games

#18

Sometimes, when battling these issues, I wish the Smalltalk-style approach[1][2] was more popular/feasible. Basically, saving the entire state of the VM is a fundamental operation supported by the language. Only truly transient things like network connections require special effort. There are some echoes of this with things like Lua's Pluto/Eris, or serializable continuations in other languages (eg: Perl's Continuity…

I don't, in fact I mostly hate serializations systems. IMO they lead to extremely long load times. It might be more work to put the data that actually needs to be saved into some binary blob but it's the difference between a game that loads instantly and a game (like Source games) that takes 10-20 infuriating seconds per level every time you die.

Re: Serialization for C# Games

#19

Naive question: is there a reason why SQLite wouldn’t work for something like this?

For simpler games with simple state which can be expressed in relationships, it is definitely a good solution. However, as games get more complex, modeling the game state in just relations is harder. Its much simpler to model state in an object like structure. At least for me.

Re: Serialization for C# Games

#20

Sometimes, when battling these issues, I wish the Smalltalk-style approach[1][2] was more popular/feasible. Basically, saving the entire state of the VM is a fundamental operation supported by the language. Only truly transient things like network connections require special effort. There are some echoes of this with things like Lua's Pluto/Eris, or serializable continuations in other languages (eg: Perl's Continuity…

A full memory dump for a game will nowadays often be multiple gigabytes, that's a non-starter.

Even back in the day, Game Maker had a function to dump the state to disk that was intended for game saves. It sucked - turns out there's a bunch of state that you don't want in your savefile - keybinds, settings, even most game state actually.

Save state should be opt-in, not opt-out, and on top of that a VM/memory dump makes it a very big pain to opt-out.

Post reply on HN