Save/Load revisited
Moderator: Moderators
- KingRaptor
- Zero-K Developer
- Posts: 838
- Joined: 14 Mar 2007, 03:44
Save/Load revisited
A certain bumped 3 year old thread reminded me of my partially completed work on save/load support for ZK. Since I'm working on SP content/functionality for ZK at the moment, this was, as they say, relevant to my interests.
As I recall, the developer consensus was that engine support for savegames beyond the existing Lua API is unlikely to ever be provided. Out of curiosity, is this still the case?
There were two reasons I previously postponed work on ZK's save/load system, which I'll bring up here:
1) Units and features do not remember their unitIDs/featureIDs
Mod-side solution is to map the old unitIDs to the new ones, and have gadgets use the map to get the updated unitIDs when loading. This can be difficult and bug-prone, especially in more compelx gadgets.
Engine feature request: Allow Spring.CreateUnit to take a unitID argument (and featureID arg for Spring.CreateFeature), allowing the gadget to recreate the units/features with their original IDs and eliminate the need for a mapping function. Throw an error if the ID is already taken or out of bounds.
2) The loaded game starts at t=0, rather than the time of the saved game (i.e. n gameframes in)
Since SP (e.g. chicken mode, missions) often relies on time ingame to schedule events, this is highly undesirable.
Mod-side solution: Save the gameframe and use it as an offset in every instance where gameframe/gameseconds is used. Difficult and bug-prone.
Engine feature request: Game starts at saved time upon loading a game.
Would these be too hard/time-consuming or considered too hacky to implement?
As I recall, the developer consensus was that engine support for savegames beyond the existing Lua API is unlikely to ever be provided. Out of curiosity, is this still the case?
There were two reasons I previously postponed work on ZK's save/load system, which I'll bring up here:
1) Units and features do not remember their unitIDs/featureIDs
Mod-side solution is to map the old unitIDs to the new ones, and have gadgets use the map to get the updated unitIDs when loading. This can be difficult and bug-prone, especially in more compelx gadgets.
Engine feature request: Allow Spring.CreateUnit to take a unitID argument (and featureID arg for Spring.CreateFeature), allowing the gadget to recreate the units/features with their original IDs and eliminate the need for a mapping function. Throw an error if the ID is already taken or out of bounds.
2) The loaded game starts at t=0, rather than the time of the saved game (i.e. n gameframes in)
Since SP (e.g. chicken mode, missions) often relies on time ingame to schedule events, this is highly undesirable.
Mod-side solution: Save the gameframe and use it as an offset in every instance where gameframe/gameseconds is used. Difficult and bug-prone.
Engine feature request: Game starts at saved time upon loading a game.
Would these be too hard/time-consuming or considered too hacky to implement?
Re: Save/Load revisited
I was looking at 1 recently for 'hot swapping' units in a gadget but it isn't feasible there (due to tombstoned unitIDs), however, I think it might be feasible for this - My view is no guarantee of anything, mind.
Re: Save/Load revisited
not sure if this helps, at list it bumps this thread:
backlink to the feature request: http://springrts.com/mantis/view.php?id=3041
backlink to the feature request: http://springrts.com/mantis/view.php?id=3041
Re: Save/Load revisited
Not sure if you want us to discuss it here or on mantis, but there are a couple of things I'd like to mention:
1) I want a /load that work in-game as well, preferably without the need of a Spring restart. Textures may also need saving as well?
2) It may be expensive to save the whole lua state, it would be great to be able to at least somehow mark things transient.
Btw, full engine saving aside, it'd be great if we could get that ID param for units/features create methods soon, as it would make full lua or engine assisted saving mechanisms much easier.
1) I want a /load that work in-game as well, preferably without the need of a Spring restart. Textures may also need saving as well?
2) It may be expensive to save the whole lua state, it would be great to be able to at least somehow mark things transient.
Btw, full engine saving aside, it'd be great if we could get that ID param for units/features create methods soon, as it would make full lua or engine assisted saving mechanisms much easier.
Re: Save/Load revisited
kloot implemented 1) Units and features do not remember their unitIDs/featureIDs
see https://github.com/spring/spring/commit ... 8697105a02
see https://github.com/spring/spring/commit ... 8697105a02
- KingRaptor
- Zero-K Developer
- Posts: 838
- Joined: 14 Mar 2007, 03:44
Re: Save/Load revisited
Good to hear; would #2 be possible as well?
Re: Save/Load revisited
I'm the necroer of topics
I'm the poster of bump-posts
I subvert the engine api
I replace its function calls
Awaken, awaken, awaken awaken
Load the save that must be taken
It has come to my mind that - provided it is possible to poison the SpringRTS Lua API by replacing functions with impostors - should be possible to implement issue 2) with a rather small amount of code.
Here's the plan:
1) in gadget handler:
2) In save/load gadget:
If this works, this should resolve issue 2 with approximately 20 LOC (maybe add same amount as needed to poison widget land too), as opposed to manually subverting 462 mentions of gameframe in (for example) ZK.
(note that many of those would actually be localized, so actual linecount for "brutal approach" is lower)
This should also seamlessly subvert any userland widgets, which is a clear benefit.
It is probably important to first subvert the function to ensure all localizations are also subverted, and then set the value of game frame offset, which is only available after save/load gadget does its thing.
I'm the poster of bump-posts
I subvert the engine api
I replace its function calls
Awaken, awaken, awaken awaken
Load the save that must be taken
It has come to my mind that - provided it is possible to poison the SpringRTS Lua API by replacing functions with impostors - should be possible to implement issue 2) with a rather small amount of code.
Here's the plan:
1) in gadget handler:
Code: Select all
GG.gameFrameOffset = 0;
local UnpoisonedGetGameFrame = Spring.GetGameFrame;
Spring.GetGameFrame = function() return UnpoisonedGetGameFrame() + GG.gameFrameOffset end
(and similar override for gadget:GameFrame)
Code: Select all
GG.GameFrameOffset = MagicallyExtractFromSaveData();
(note that many of those would actually be localized, so actual linecount for "brutal approach" is lower)
This should also seamlessly subvert any userland widgets, which is a clear benefit.
It is probably important to first subvert the function to ensure all localizations are also subverted, and then set the value of game frame offset, which is only available after save/load gadget does its thing.
Re: Save/Load revisited
No, you have to do it once in the gadget handler, and once in the widget handler.Anarchid wrote:This should also seamlessly subvert any userland widgets, which is a clear benefit.
Some gadgets and widgets will still fails, especially those that needs to do stuff at the start of the game:
- They may detect game started by looking at frame number, by using GameStart or a similar callings, by checking, or simply by running code when the gadget/widget is loaded.
- Sometimes the action at the beginning of the game has to be done again. Sometimes it must not be done again (for exemple, spawning commander). Sometimes values must be stored (like, times per teams on a KOTH gadget).
You can't apply a blanket strategy to automatically fix every gadget transparently.
Well coded widgets may be more resilient, since it always was possible to switch widgets on and off midgame.
But otherwise, yes, the idea of overriding Lua API in the save/load gadget works. I use it myself. But it's unclean. And has issues when gadgets race to be the first to run.
- KingRaptor
- Zero-K Developer
- Posts: 838
- Joined: 14 Mar 2007, 03:44
Re: Save/Load revisited
*bump*
Thanks to GoogleFrog's work, the ZK implementation of save/load is almost fully functional. But I've had two major issues I still can't solve:
1) gadget:Load() is called after gadget:GamePreload().
Currently I know of no other way to detect whether this is a loaded savegame, which means I can't block unwanted things happening in GamePreload.
2) The player still isn't assigned to the right team on game load (even though startscript.0 lists the correct player name). Trying to work around by moving all players with Spring.AssignPlayerToTeam() doesn't work either.
Here is a save (Zero-K v1.3.9.0, Comet Catcher Redux) that demonstrates the issue, and the startscript used to generate it.
Does anyone know of a workaround for either of these issues?
Thanks to GoogleFrog's work, the ZK implementation of save/load is almost fully functional. But I've had two major issues I still can't solve:
1) gadget:Load() is called after gadget:GamePreload().
Currently I know of no other way to detect whether this is a loaded savegame, which means I can't block unwanted things happening in GamePreload.
2) The player still isn't assigned to the right team on game load (even though startscript.0 lists the correct player name). Trying to work around by moving all players with Spring.AssignPlayerToTeam() doesn't work either.
Here is a save (Zero-K v1.3.9.0, Comet Catcher Redux) that demonstrates the issue, and the startscript used to generate it.
Does anyone know of a workaround for either of these issues?
Re: Save/Load revisited
does the player0's name in script.txt match the name in springsettings.cfg ?2) The player still isn't assigned to the right team on game load (even though startscript.0 lists the correct player name). Trying to work around by moving all players with Spring.AssignPlayerToTeam() doesn't work either.
https://springrts.com/wiki/Springsettings.cfg#name
Re: Save/Load revisited
So save/load is actually workign well?
I can try it myself if its reasonably supported.
I can try it myself if its reasonably supported.
- KingRaptor
- Zero-K Developer
- Posts: 838
- Joined: 14 Mar 2007, 03:44
Re: Save/Load revisited
Ah, no it doesn't.abma wrote:does the player0's name in script.txt match the name in springsettings.cfg ?2) The player still isn't assigned to the right team on game load (even though startscript.0 lists the correct player name). Trying to work around by moving all players with Spring.AssignPlayerToTeam() doesn't work either.
https://springrts.com/wiki/Springsettings.cfg#name
(Still makes it annoying to test unless you already have a lobby client or equivalent that supports it; "why u no just use the name in startscript?!" But if it'll work correctly in the release version then I guess it's fine.)
Re: Save/Load revisited
I would think that something such as the Eris or Pluto projects would be the route towards save/load. We'd be able to serialise an entire lua VM and save to disk, then load it, call a few API calls to tell the game it's just been reconstituted, and resume without needing special save/load mechanisms in game content ( beyond UI )
Re: Save/Load revisited
Sounds like a reasonable approach.AF wrote:I would think that something such as the Eris or Pluto projects would be the route towards save/load. We'd be able to serialise an entire lua VM and save to disk, then load it, call a few API calls to tell the game it's just been reconstituted, and resume without needing special save/load mechanisms in game content ( beyond UI )
It may be needed or atleast useful if save/load functions would be there to override some of the behavior tough.
Also i havent checked up but, does save/load support multiplayer with different players?