Lua SaveLoad

From Spring
Revision as of 16:15, 13 March 2010 by Tobi (talk | contribs) (Lua save/load docs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Development < Lua Scripting < Lua SaveLoad

Lua Save/Load support

Motivation

Engine save/load has been broken/unstable for a very long time. I believe the major reasons for this were:

  • In particular for loading too much special code paths were traversed, that were not used for anything else (e.g. creg_Serialize and creg_PostLoad functions in many classes);
  • Each class was responsible for it's own saving and loading;
  • The code for loading was spread out over many classes;
  • Save/load using CREG was extremely slow.
  • Savegames created using CREG were bound to be incompatible between different Spring versions because they relied inherently on the implementation details of every single class involved;
  • The save/load system strived to be 100% perfect, saving every single detail.
  • No clear way to save Lua states (without making Lua aware of it)

I realised we have a pretty decent and reasonably stable Lua interface. So why use this for save/load:

  • The code has been tested in practice (it's used in widgets and gadgets);
  • The interface is reasonably stable, so savegames can be compatible between different Spring versions;
  • Not a single class needs special support for save/load, as save/load uses existing APIs.
  • By simply using the standard call-in mechanism any gadgets can save some state if that is desired. The save/load gadget does not need to get special treatment at all.

Argh and zwzsg had this idea too and implement save/load using Lua only. This is a little bit hacky and it is slow when saving large amounts of data such as e.g. the modified terrain heightmap.

Hence Lua save/load brings engine support for Lua save/load :-)

Idea

Instead of having the engine be responsible for serializing every bit of gamestate to disk, Lua save/load transfers most of the responsibility to the game (developer). The game developer can decide what objects and what properties are important to save, and ultimately a gadget could be created that could be drag 'n dropped in nearly any game. (Argh's and zwzsg's code would be useful for this.)

There are two new call-ins: Load and Save, that allow a Lua save/load system to seamlessly integrate with other interfaces of the engine (e.g. commandline, lobby). Load is called by the engine if it has been instructed to load a game. Save is called by the engine whenever the chat command '/save <filename>' or '/savegame' is given. Both get a userdatum as argument. Using the methods open, read and write on this userdatum the Lua code can read/write chunks of data.

At this moment existing code for reading and writing zip files has been re-used for Lua save/load, so savegames are simply renamed zip files (.ssf)

API documentation

Lua save/load brings two new call-ins:

Load ( zip ) -> nil

This is called after GamePreload and before GameStart. The single argument is a userdatum respresenting a zip file from which the game is being loaded.

On this userdatum the following methods are defined:

  • zip:open(filename): Opens a file within the zip file. Next calls to zip:read will read from this file.
  • zip:read(...): Reads data from the file that is currently open. Arguments and return values are similar to io.read, although only "*all" and num are supported. The special case io.read(0) should work.

Save ( zip ) -> nil

This is called when a chat command '/save <filename>' or '/savegame' is received. The single argument is a userdatum representing the savegame zip file. This is a file with the name <filename> for '/save' and a file with the name 'QuickSave.ssf' for '/savegame'.

On this userdatum the following methods are defined:

  • zip:open(filename): Opens a new file within the zip file. Next calls to zip:write will write to this file.
  • zip:write(...): Writes data to the file that is currently open. Arguments are same as io.write.