One feature I'd like to implement is saving the game state on every turn (or every significant user action). "Game state" in this case being the state of the player and all enemies in the level. The level structure itself will be static and I'll just serialize it on generation to json using the included functionality in LibGDX. I'll also probably limit the turn rate to no more than 2 or 3 per second.

The idea is for saving to work like it does in Dark Souls. DS provides no explicit "Save" option, instead it is constantly saving every little action you take in the background.

At a very high level it seems to me that the best way to proceed is to make sure that I only persist those things that have changed each turn, and in general optimise for write speed of my save file over read speed. Sqlite would seem to be the natural way to do that sort of thing but I've no idea what the overhead of sqlite is relative to other methods.

At present I still have only a vague idea of how much information I'll need to store, i.e. what attributes entities will have and how many entities on average will be in a level. Admittedly, this may be something where I'll just have to experiment and profile to find something that's fast enough but I'm interested to hear if anyone has any ideas or has implemented something similar.

I don't there is a "fast" way. Just do it. Of course, you can optimize it and everything if you lack speed. Besides, I don't think you need to save the game every turn. That's what game making is about: get the best quality by using less performance. You might increase performance, but the quality will drop. You might increase quality but the performance will drop. You just need to find a mid-ground that will be good for the player.

Being turn-based, you'll have a bit more time up your sleeve, and should be able to save the state without affecting the user's experience. You could potentially run the save on a separate thread between turns. Of course if you did this, you'd need to ensure that the state doesn't change before the save finishes.

And instead of commiting changes to a DB or disk after every turn, perhaps you could hold them in memory and write them at a more convenient time; such as when the user exits the game. (Or perhaps when the changes reach a 'critical mass' and you want to re-use the memory).

Like you've pointed out however, you probably need to go and experiment a bit. You might be trying to prematurely optimise something that is a non-issue.

I would save the entire game state with Kryo between turns. This is very likely fast enough for a turn-based game on mobile. On desktop it is fast enough until you are saving 7-8MB of data. Kryo is binary and the data is small, so this is quite a bit of data. Saving as JSON with libgdx might be ok, but being a text format it has never been intended for high performance. You could look at jackson for JSON if it is too slow and you want human readable.

I would save the entire game state with Kryo between turns. This is very likely fast enough for a turn-based game on mobile. On desktop it is fast enough until you are saving 7-8MB of data. Kryo is binary and the data is small, so this is quite a bit of data. Saving as JSON with libgdx might be ok, but being a text format it has never been intended for high performance. You could look at jackson for JSON if it is too slow and you want human readable.

Kyro does object serialization, correct? Wouldn't this mean rhat the format of the save file would be directly dependent on the layout of my objects? So, if I update the layout of my objects then existing save files would become invalid? This would be true of any object serialization scheme. I remember reading about such a concern somewhere, might've been here.

Still, if Kyro is fast enough that I can just brute force serialize everything on every turn (actually I'd still make sure I only serialize things that have changed) it might be worth the hassle of managing outdated save files (which may not even be a problem for my game anyway).

Out dated save files can be handled most easily by using Kryo's TaggedFieldSerializer. This lets you add fields without breaking anything. You can't change field types. You can't remove fields, instead you just mark them @Deprecated. You can rename fields, since it uses @Tag(3) annotations, not field names. You could use CompatibleFieldSerializer instead to be able to remove fields, but it has some allocation overhead during serialization. At any rate, if you change your classes too much, you could break saves that are in the middle of a game and might be missing data for fields you've added.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org