Jump to content

Could autosave be implemented as a mod?


mvandemar
 Share

Recommended Posts

I didn't dig too deep into the tutorials yet because I am hoping this might actually be a quick, easy, down and dirty thing that someone would know the answer to. I was finally getting a decent game going tonight when it crashed on me just now (yay!), which is when I discovered that autosave is not something that is implemented in the game. I noticed that mods incorporate Javascript, and I know that native Javascript has the ability to utilize timers. Is there a way to set a timer to autosave the game every 60 seconds? I am not even worried about incremental saves that would allow me to roll back a game, I am strictly speaking in terms of being able to recover from a crash. Since the game is still in development I am guessing this could be hugely beneficial to have.

Thanks!

-Michael

  • Like 1
  • Thanks 3
Link to comment
Share on other sites

1 minute ago, stanislas69 said:

You also have quicksaves if I'm not mistaken.

Ok, cool, did not know about that... but it doesn't appear to work, or if it does it would not help with a crash. I just initialized a game, hit SHIFT-F5, saw the message that the game was saved, and then quit. I then restarted 0 A.D. and went to Load game from the menu, and there was no quicksave. I started a game, hit SHIFT-F8 and got this message:673309162_Screenshotfrom2019-02-2701-57-16.png.0993157fd02ea19b9b827d14c568cf92.png

It looks like you can only Quicksave and Quickload within an active session, which would not work for crashed games.

-Michael

 

Link to comment
Share on other sites

12 hours ago, stanislas69 said:

Well you should be able to load a quicksave from the menu :)

Should, as in it's how it is supposed to work? Or should as in you feel like it should be there if it isn't?

And do you know anything about modding? Does my idea sound like something that is doable if so?

-Michael

Link to comment
Share on other sites

13 hours ago, mvandemar said:

and went to Load game from the menu, and there was no quicksave.

13 hours ago, stanislas69 said:

Well you should be able to load a quicksave from the menu :)

I just tried it ( to make sure): quicksaving doesn't add an entry in the list for loadable games.

 

I strongly support the wish for an autosave feature! :)

  • Like 1
Link to comment
Share on other sites

I confirm that this should be doable in Javascript only, and actually we would be happy to have this in the main game, so we'd rather have a patch that a mod :)

I think that what you discovered about quickloading is not intended behavior. Quick save/load is supposed to be useful in case of crashes... So yeah, patch welcome!

  • Like 4
Link to comment
Share on other sites

Ok, so, I tested @vladislavbelov's patch. It was obviously designed for an earlier version of 0ad, but it did essentially work with a few flaws.

I went with 4417_autosave.2.patch on the assumption that was the newer version of the patch. The code in binaries/data/mods/public/gui/session/session.js originally looked like this in his diff:

function GetSimState()
{
	    if (!g_SimState)
	 
	    onSimulationUpdate();
	    setTimeout(displayGamestateNotifications, 1000);
	
	    // Report the performance after 5 seconds (when we're still near
	    // the initial camera view) and a minute (when the profiler will
	    // have settled down if framerates as very low), to give some
	
	    Engine.SendGameReport(reportObject);
}

The code was supposed to be inserted just after the setTimeout command. The newer code in 0ad though differs, so after I inserted the code it looks like this:

function GetSimState()
{
	if (!g_SimState)
		g_SimState = Engine.GuiInterfaceCall("GetSimulationState");

	if (!g_IsNetworked && !g_IsReplay && Engine.ConfigDB_GetValue("user", "autosave") == "true")
	{
		g_AutosavePeriod = +Engine.ConfigDB_GetValue("user", "autosave.period") * 60000; // the autosave period is set in minutes
		// Prevent the autosave spamming for invalid values
		if (g_AutosavePeriod >= 60000)
			setTimeout(autosaveGame, g_AutosavePeriod);
	}

	return g_SimState;
}

Everything else looks the same as his diffs. His code calls for the default autosave.period to be 10, I set it to 5 for testing purposes. Note that it did create an autosave file, which I was able to reload and restart the game at the correct point, however...

1) Minor layout bug in the settings screen causes the last two settings in the settings screen to get pushed down over the Reset button:

1929234926_Screenshotfrom2019-02-2720-16-52.png.67d33235a6bd0d29a35143045e71f9bc.png

2) When it saves, it goes into an infinite loop of saving, completely freezing the game and making it unplayable:

781377793_Screenshotfrom2019-02-2720-34-50.png.e461d84d523ec57c3b15c39e53988525.png

Note that I alt-tabbed to the ~/.local/share/0ad/saves folder and watched the autosave.0adsave last modified date updating in real time, so I know that's what was happening, and I was able to reproduce this issue each time I tested.

3) Even though it's set to create 3 autosaves, I think, it only ever created autosave.0adsave. This includes when I reloaded, it didn't move on to autosave.1adsave on the next autosave, it just went back into the same infinite loop of saving autosave.0adsave.

Other than those issues though, it definitely works. :) I am hoping that the infinite loop is just because the code inside of function GetSimState() needs to be moved to a different location, although of course I have no idea where that should be.

 

 

  • Thanks 1
Link to comment
Share on other sites

Just now, Itms said:

Done!

Thanks! :)

I came up with a workaround for the infinite loop issue. In binaries/data/mods/public/gui/session/session.js I added the following global:

var g_AutosaveInitialized = false;

And then in @vladislavbelov code I modified the if statement to only trigger if it's false, and immediately set it to true the first time around:

function GetSimState()
{
	if (!g_SimState)
		g_SimState = Engine.GuiInterfaceCall("GetSimulationState");

	if (!g_IsNetworked && !g_IsReplay && Engine.ConfigDB_GetValue("user", "autosave") == "true" && !g_AutosaveInitialized)
	{
		g_AutosaveInitialized = true;
		g_AutosavePeriod = +Engine.ConfigDB_GetValue("user", "autosave.period") * 60000; // the autosave period is set in minutes
		// Prevent the autosave spamming for invalid values
		if (g_AutosavePeriod >= 60000)
			setTimeout(autosaveGame, g_AutosavePeriod);
	}

	return g_SimState;
}

This works, although it feels a bit hacky, like maybe there's simply a better place to initialize the autosave routine? Y'all would know better than me on that one though.

It's still only saving the one file though each time, autosave.0adsave. Based on the last reply on the ticket it looks like he meant to save up to 3 autosaves, but I don't see where in the code that would happen. Either way though, it's definitely more enjoyable playing knowing that if the game does crash I don't lose everything. :)

Thank you guys!

-Michael

 

Link to comment
Share on other sites

I was able to fix the options screen by increasing the height by 44px. In binaries/data/mods/public/gui/options/options.xml I changed line 17:

<object name="options" type="image" style="ModernDialog" size="50%-476 50%-316 50%+476 50%+316">

to:

<object name="options" type="image" style="ModernDialog" size="50%-476 50%-338 50%+476 50%+338">

Worked fine, although maybe I overshot by a couple px:

923213493_Screenshotfrom2019-02-2804-04-02.png.4a21b93507e6205edc6623053dc435a9.png

I don't know what the gui standards are for line height in this window so I just guessed.

-Michael

Link to comment
Share on other sites

The infinite loop is present because you applied the patch incorrectly. (It can be kinda tricky with patches not having full context.)

The first call to autosaveGame() is done in init(), not GetSimState(). And then autosaveGame() will correctly keep on recursively calling itself with the given interval.

Edited by Guest
Link to comment
Share on other sites

Don't know. I no longer have any 0ad source files locally and it's a pain trying to do it in the browser. But the init() function should be around L~250. Put that stuff above the last setTimeout in that function.

Link to comment
Share on other sites

  • 1 year later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...