Jump to content
Sign in to follow this  
sxp2high

BTK Player Restore (Multiplayer Autosave)

Recommended Posts

It happened to all of us: You are in the middle of an epic coop session, when suddenly ArmA crashes, or you get disconnected from the server for some reason. You rejoin and start from the FOB again. Your loadout is gone and your team is 5km away. This addon makes autosaves every 10 seconds and you will resume exactly where you left off. Not only that, it saves Weapon, backpack, backpack content, weapon on back (ACE), animation, current weapon, damage and more...

So let's say you are lying on the ground, your leg is broken, and you have grenade in your hand when ArmA crashes. After rejoining you will be lying with a broken leg on the same spot and the grenade will still be in your hand.

This will be released soon as addon and script versions. The addon will work for all missions with JIP functionality and the script version can be used by mission makers to enable this feature in their missions...

Initially created for a mission of mine a while ago, I decided to make this an addon, so this feature can be enjoyed in all JIP compatible missions. :thumbs-up:

-6KLl97sW9U

What exactly is being saved?

_saveStatus = [_name, _position, _direction, _animationChecked, _damage];
_saveGear = [_magazines, _items, _weapons, _backpack, _backpackWeapons, _backpackMagazines, _weaponOnBack, _currentMuzzle];

Any feedback? Has this been done before and I missed it? :D


ADDON HAS BEEN RELEASED!

Edited by sxp2high

Share this post


Link to post
Share on other sites

Would you want to save it as UID instead of name, just in case xXxGh0sTKill4HxXx disconnects accidentally just as the other xXxGh0sTKill4HxXx logs in and suddenly takes over his body? Also how does it handle ACRE radios?

Share this post


Link to post
Share on other sites

It does use UID to identify the savegames, it just saves the name as well into the savegame (no reason atm, may be of some use in the future).

Thanks a lot for reminding me of ACRE, haven't considered/tested that yet. I will make sure to support that as well! :D

Share this post


Link to post
Share on other sites

Perhaps add the ability to add additional variables to the save status value? That way if addon makers have a player variable that is crucial to their gameplay, they can ensure it gets added to the save feature.

Share this post


Link to post
Share on other sites

Addon makers? Note sure what you mean, can you give me an example of what that usage could look like maybe?

Share this post


Link to post
Share on other sites

How is it done technically? With profileNamespace?

Share this post


Link to post
Share on other sites

Nope, it's simply setVariable on a logic. It could cause quite a bit of network traffic with many players, probably better to set it to 30 or 60 seconds to reduce that. But I think it should be ok.

I'm an open source guy, so here are the files so far if you want to take a look: btk_fnc_playerSave.sqf btk_fnc_playerLoad.sqf

Any ideas for improvements are most welcome! :)

Share this post


Link to post
Share on other sites

sounds awesome, can you explain the process of how it works a bit more in detail. i take it its not like the hives dayz have been running with a database etc? also how is server performance looking? every 10 seconds with 40 + people might bog down the server fps a bit, not sure. if this works without great performance losses kudos, you would give so many people a reason to keep playing.

Share this post


Link to post
Share on other sites

It's not possible to use scripts to detect a crash is it? Because what if somebody DC'd on purpose, and didn't want their old data?

Share this post


Link to post
Share on other sites

No offense but this has been in the MSO for over 4 years. It does cause major network traffic with upwards of 15 players, causing major desync during connecting and disconnecting states. For that fix the MSO now has an SPS option in the ACE menu: Save player state. That is save your current location there and then without the MSO constantly re-checking and re-saving your status and causing lag. It has allowed the longest MSO ever at 20 days and we hope to improve it. I mean congratulations on this modification, it'll be great for a single script/option for mission makers but we did make this ourselves such a long time ago.

Share this post


Link to post
Share on other sites

I wrote a variant on this for my old 'MSO' several years ago, as 'Nomad', despite claims (like the above), the script itself is lightweight and uses as much traffic (if not less) as any network synchronous script in ACE or any other mod which does anything complicated.

The traffic itself is controlled by how often the loop is run (1 second is perfectly fine, but if your really worried, >10).

If you want to make it a bit more fancy, use a random sleep so that all players aren't synchronously all broadcasting their updates. However, this has been tested with upwards of 30 players on a low end connection and is not a real concern.

The functionality as it was originally implemented is simple.

A player maintains the following in a loop:

_saveStatus = [_name, _position, _direction, _animationChecked, _damage];
_saveGear = [_magazines, _items, _weapons, _backpack, _backpackWeapons, _backpackMagazines, _weaponOnBack, _currentMuzzle];

_string1 = format ["%1_status", getPlayerUID player];
_string2 = format ["%1_gear", getPlayerUID player];
missionNamespace setVariable [_string1, _saveStatus];
missionNamespace setVariable [_string2, _saveGear];
publicVariable _string1;
publicVariable _string2;

Add a script which when the players starts playing (throw it in init.sqf) that checks for this variable, and if it exists, it runs a set of code which restores the players state from the above variables.

Such as:

_status = missionNamespace getVariable _string1;
if (!isnil "_status") then {
    player setpos (_status select 1);
    player setdir (_status select 2);
    // etc
};

Simple. Not scary. Super easy. Not really necessary as an addon.

Edited by Rommel

Share this post


Link to post
Share on other sites

Would there be a way to also capture how many lives are left like the MSO does so when they re join they get the number of ,oives again untill reset or after 24 hours etc..?

Share this post


Link to post
Share on other sites
No offense but this has been in the MSO for over 4 years.

I know. However this is supposed to work with ALL missions, that are JIP compatible. If you play one of the very few missions who have a similar feature, the addon should be disabled while palying them, so they don't interfere.

...too much to quote...

Thanks a lot. Good to know that I don't have to worry about traffic. Random sleep is also a great idea.

Would there be a way to also capture how many lives are left like the MSO does so when they re join they get the number of ,oives again untill reset or after 24 hours etc..?

If you implement the script version, you can of course edit the files to fit the needs of a specific mission (quite easily), however for the addon version this is not possible/too much work. I would have to check for missionName and add many missions to support their specific features, the mission names also may vary because of edited mission files and whatnot.

If you are part of a group that only plays just a handful of missions over and over, you might just edit the files and repack the addon to support special features of those missions. (I would gladly help you out with that if you don't know how to do so). My group for instance has over 1000 missions to choose from and I simply want to have this for all of them. :)

We will test the addon version tomorrow and I will release a beta version after that. :thumbsup:

Share this post


Link to post
Share on other sites

@rommel

Sorry for the newbness, when you say a loop or the player, how exactly would you implement that?

Thanks

Share this post


Link to post
Share on other sites

any way to create a database for the server to save the mission itself? for example, ur running a mission, any mission, server crashes you load back in and pick up where you left off from? saving enemy pos, civilian pos, objectives yada yada ?

Share this post


Link to post
Share on other sites

I know this is slightly off topic but to answer the question above,

MSO 4.5 does just that and saves all data such as enemy pos, civilian pos, objectives etc to an external mysql DB.

It achieves this via it's persistentDB module which is an expanded version of my original persistentDB scripts. The MSO persistentDB module we are working on for 4.5 is a little further advanced than the vanilla persistentDB scripts at present (at present the vanilla persistentDB does not save enemy pos, civilian pos, objectives etc but it does save player data, mission time and other things) but once we have finalised the 4.5 module I may look at migrating the updates to vanilla which was originally designed to work in any mission.

Please be aware that world objects are not automatically DB aware by default in the Arma2 engine so static and spawned objects of any kind have to be named and be made DB aware via script.

links:

Vanilla PersistentDB

MSO 4.5 (includes PersistentDB module)

Also see here

Edited by [KH]Jman

Share this post


Link to post
Share on other sites
It's not possible to use scripts to detect a crash is it? Because what if somebody DC'd on purpose, and didn't want their old data?

I haven't considered this. That's a tough one. Let me think about it...

@rommel

Sorry for the newbness, when you say a loop or the player, how exactly would you implement that?

Thanks

Take a look at my files, I am also running a loop of course:

while {true} do {
sleep 10; // Autosave interval
waitUntil {alive player};
_saved = [] call btk_fnc_playerSave;
};

sounds awesome, can you explain the process of how it works a bit more in detail. i take it its not like the hives dayz have been running with a database etc? also how is server performance looking? every 10 seconds with 40 + people might bog down the server fps a bit, not sure. if this works without great performance losses kudos, you would give so many people a reason to keep playing.
any way to create a database for the server to save the mission itself? for example, ur running a mission, any mission, server crashes you load back in and pick up where you left off from? saving enemy pos, civilian pos, objectives yada yada ?

Please don't confuse my addon with database stuff (DayZ style). This is only meant to save your progress for ONE SESSION. I am not trying to enable persistent long term missions with this. It is simply for "small" COOP missions (1-6 hours) to prevent frustration of being disconnected or game crashes.

If you want to have persistent mission data, that you can play over multiple sessions, please look into Jman's excellent persistentDB stuff. :thumbsup:

If you ever heard this on teamspeak:

"Oh no - my game just froze, now I have to drive all the way to the frontline again... well, i quit for today."

Then this addon is for you :D :D

Edited by sxp2high

Share this post


Link to post
Share on other sites
I haven't considered this. That's a tough one. Let me think about it...

What about having a countdown? For most the game probably takes like 5 minutes to launch, so if they don't come back onto server for up to 10 minutes then the script doesn't recall their old data?[

Edited by Khaki

Share this post


Link to post
Share on other sites
@rommel

Sorry for the newbness, when you say a loop or the player, how exactly would you implement that?

Thanks

Seeing he probably won't check back on this i'll poke him in the face when i talk to him tonight for you :P

Share this post


Link to post
Share on other sites
@rommel

Sorry for the newbness, when you say a loop or the player, how exactly would you implement that?

Thanks

*Argh my face*

As I've been obligated to respond by a squad member; I must point you to sxp2high's response, which sums it up perfectly.

Take a look at my files, I am also running a loop of course:

while {true} do {
sleep 10; // Autosave interval
waitUntil {alive player};
_saved = [] call btk_fnc_playerSave;
};

Would there be a way to also capture how many lives are left like the MSO does so when they re join they get the number of ,oives again untill reset or after 24 hours etc..?

As sxp2high also mentioned, this is very simple to do with a few if statements and a tracked variable. What is a little more complex is doing this in an extensible, non-limiting way.

Perhaps as inspiration, I'll give some insight on how nomad worked:

if (isdedicated) exitwith {};

waituntil {not isnull player};
waituntil {!isMultiplayer || getplayeruid player != ""};

[
[
	/*{deaths player} // handled by nomad */
	{typeof player;},
	{magazines player;},
	{weapons player;},
	{typeof (unitbackpack player);},
	{getmagazinecargo (unitbackpack player);},
	{getweaponcargo (unitbackpack player);},
	{getposATL player;},
	{damage player;},
	{rating player;},
	{score player;},
	{viewdistance;},
	{if(isnil "terraindetail")then{1;}else{terraindetail;};},
	{getDir player;},
	{rank player;}
],
[
	{
		_dayspassed = 1 + time / 86400;
		_maxLives = nomadRespawns * (nomadReinforcements * _dayspassed);
		if (_this > _maxLives) then {_disconnect = true;};
	},
	{
		if (typeof player != _this) then {_disconnect = true;};
	},
	{
		{player removemagazine _x;} foreach (magazines player);
		{player addmagazine _x;} foreach _this;
	},
	{
		{player removeweapon _x;} foreach ((weapons player) + (items player));
		{player addweapon _x;} foreach _this;
		player selectweapon (primaryweapon player);
	},
	{
		if (_this != "") then {
			player addbackpack _this;
			clearweaponcargo (unitbackpack player);
			clearmagazinecargo (unitbackpack player);
		};
	},
	{
		for "_i" from 0 to ((count (_this select 0))-1) do {
			(unitbackpack player) addmagazinecargo [(_this select 0) select _i,(_this select 1) select _i];
		};
	},
	{
		for "_i" from 0 to ((count (_this select 0))-1) do {
			(unitbackpack player) addweaponcargo [(_this select 0) select _i,(_this select 1) select _i];
		};
	},
	{player setposATL _this;},
	{player setdamage _this;},
	{player addrating (-(rating player) + _this);},
	{player addscore (-(score player) + _this);},
	{setviewdistance _this;},
	{
		setterraingrid ((-10 * _this + 50) max 1);
		terraindetail = _this;
	},
	{player setdir _this;},
	{player setunitrank _this;}
]
] call rmm_nomad_start; 

Now, what should be apparent, is that this massive parameter list, is actually making use of the fact code can be data in SQF (a very powerful feature indeed!); and I have essentially passed in several lambdas which act as 'getters' and 'setters'.

The 'getters' are the first array of functions, which must return some value.

The return value from these functions are then stored in the player state.

Upon re-connect, the second array (the `setters`) of first class functions are then called using those saved values as parameter `_this`, and the state restored based on the heuristics in those functions.

Example?

[
[
	/*{deaths player} // handled by nomad */
	{getposATL player;},
],
[
	{}, // do nothing
	{player setposATL _this;}
]
] call rmm_nomad_start; 

This does the simplest functionality possible, it 'gets' the players position every update, then sets it upon re-connection.

This design works great for mission makers who want full control over what happens where; and don't want to worry about the funky ArmA 2 network issues.

I agree it is a code smell that nomad handles the special case for player respawn/deaths, and if you noticed it, there was also variable `_disconnect` injected into the major example above which can be used to force the player to be disconnected.

Hope that helps.

PS. As for the player not wanting their old data? Simple solution: Escape -> Respawn.

Edited by Rommel

Share this post


Link to post
Share on other sites

Thanks again Rommel! Some great stuff in there for sure. Player rank, score, rating, viewDistance and terrainGrid are all things I forgot about, I will definitely add those!

I was also thinking about storing code in the beginning, instead of values, but I don't think it's necessary for what I'm trying to accomplish...

From YouTube:

does it save data like earplugs and sunglasses which are already in use? How about ACRE radio settings and vehicle positions?

Great questions!

- Earplugs and other ACE items in use are not supported yet. I will look into it. Thanks for reminding me of that!

- ACRE radio settings are not saved, I might look into that as well.

- Vehicles are planned. If you disconnect while being inside a vehicle, you will resume inside that vehicle (if it still exists and has empty seats of course)

- Vehicle positions are not being saved, this addon is purely for PLAYERS, not for any kind of mission data. This must be done via database.

Share this post


Link to post
Share on other sites

Small update

First couple of tests were successful, no problems at all. I still have to add some "bad animations" though.

Vehicles are now supported:

If you disconnect as commander, you'll resume as commander. Including multiple turret support. You'll resume in the exact same turret. :)

ACE Earplugs are now supported:

If you're wearing them on disconnect, you'll wear them after rejoin.

ACE Gas masks, masks, glasses are now supported:

If you are wearing a mask/glasses, you'll wear it after rejoin.

I'm now adding ACRE radio stuff, radio frequency, volume, etc. - which should be no problem thanks to their excellent API!

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

×