open Outcast is a total conversion mod for Crysis Wars that should become an unofficial successor of the Action-Adventure Outcast (by Appeal).
The following article describes how we managed to store all kinds of data, such as entity positions or the player's inventory, when travelling between different levels in Crysis Wars. This way changes to a level can be restored when visiting it again.
Posted by s87 on May 29th, 2010
Enabling free traveling between levels, in contrast to completing them one-by-one, poses the challenge of storing changes in the level you are leaving and restoring them when returning to it.
Although Crysis Wars doesn't have this feature built-in, the SDK allows the possibility to implement a persistence system doing exactly this.
When thinking of storing data in a game the first thing that may come to mind is the Savegame system. This naive approach did the trick for us:
Sounds too simple to be true? Correct.
Problems arise as soon as you try to save regularly: After loading, the local data of the levels would stay just the same. We solved this issue by storing the current local data and local data of saved games separately. For it a folder named the same as the regular savegame file is created and the local files are copied into it when saving, while they are moved out of it to the folder containing the current data when loading.
When taking a closer look at the C++ code of the Crysis (Wars) SDK you may notice that many classes have functions named Serialize(...) or FullSerialize(...). It is these that take care of what a class should store when saving, and read from a savegame file when loading.
They all require a TSerialize object as a parameter that has to be created from an instance of a class implementing the ILoadGame or ISaveGame interface, depending on what you want to do.
In order to write such Serialize functions for custom classes it pays off to check out the ISerialize interface. I won't elaborate further on that since this article is NOT a tutorial.
You may find some ideas in the Code Snippets section though. :)
Now you’ve got an impression of how data can be saved and loaded; but these processes need to be triggered at the right time:
Our solution was to add an alternative travelling console command, that saves the local data and invokes the "map" command with the target level as parameter (this method works in non-devmode as well, since the console commands are called by code rather than by console).
For restoring the local data at the right time, we simply used the ILevelSystemListener interface and implemented the OnLoadingComplete function accordingly. The loading could also be done with a custom FlowNode - you'd have to include that node in each map you want to remember changes after travelling though.
Most of the following things weren't documented anywhere (or at least we didn't find any tutorials or similar) so you may find them useful.
With the following code you can create your TSerialize object needed by Serialize functions when saving:
... and for loading it can be done as shown below.
Now we have some kind of TSerialize object but how can we handle it? Let's save the player's inventory for example:
And load it again:
Creating a custom console command is quite easy. First of all you need to declare the C++ function that will be called by the console command in Game.h:
Then you will need to implement the function and register the new console command in GameCVars.cpp:
If you want to listen to events of the level system, your class (could be a FlowNode for example) needs to implement the ILevelSystemListener interface: