Jump to content
MrDj200

Save Loadout and Position on disconnect

Recommended Posts

Hello,

 

I need some help with this.

I want to save a players position, loadout and maybe group when a player leaves the server.

As we have some problems with people crashing or having IP resets or just needing to restart, this would be really neat.

 

I looked at onPlayerDisonnected and the EH PlayerDisconnected, but I don't really know where to save the data, and how to get the position.

 

Any help would be appreciated!

 

-Dj

Share this post


Link to post
Share on other sites

Not between server restarts, don't want to use a DB, or is the "profileNamespace" able to save things between game restarts(client)?

That'd be pretty neat to save some other things...

Share this post


Link to post
Share on other sites

Just leaving this here so I remember, I'll check back later tonight with solution. 

Share this post


Link to post
Share on other sites

Hmm, I've been playing around with namespaces and just noticed JIP players do not get the missionNameSpace synced?

How do I sync that?

Share this post


Link to post
Share on other sites

Here we go! Half a month late. Written up on December 15, forgotten about until today. Oops.

 

This should save a disconnecting players loadout, position and facing on the server and will broadcast it back to the player when he/she reconnects as long as the mission isn't restarted.

It does not handle group at this time since it was a maybe (just make sure you select the same group when reconnecting and you should be good). 


It's meant to go in the init.sqf, if you got the CfgRemoteExec whitelist enabled you need to add TAG_fnc_loadClientData to it.

You could also load TAG_fnc_loadClientData through functions library and put the mission eventhandlers in initServer.sqf instead.

 

Disclaimer: I have not done thorough testing. Just a syntax check and a basic logic check. So there might be some edge cases which might be bugged (It's also perfectly possible I missed something :P).

Other than that it should do it's job.

 

EDIT: The below code is broken, BIS_fnc_exportInventory has been updated and I missed to update position and direction after multiple disconnects.

See this post for working code.

TAG_fnc_loadClientData = {
	_this params ["_loadoutStr", "_positionASL", "_dir"];
	call compile _loadoutStr;
	player setDir _dir;
	player setPosASL _positionASL;
};

if(isServer) then {
	addMissionEventHandler [
		"HandleDisconnect", 
		{
			params ["_body", "_id", "_uid", "_name"];
			
			if(!isNull _body) then {			
				//Init storage var
				if(isNil "TAG_disconnectedLoadouts") then {
					TAG_disconnectedLoadouts = [];
				};
				
				//Save loadout as script for easy broadcast
				private _loadoutStr = [player, "script", false] call BIS_fnc_exportInventory;
				{
					private _index = _loadoutStr find _x;
					if(_index > -1) then {
						private _strArray = toArray _loadoutStr;
						_strArray deleteRange [_index, count _x];
						_loadoutStr = toString _strArray;
					};	
				} forEach ["// Remove existing items","// Add containers","// Add weapons", "// Add items", "// Set identity"];
					
				//Find in storage
				private _uidIndex = TAG_disconnectedLoadouts find _uid;
				if(_uidIndex > -1) then {
					//Found -> update
					private _loadoutIndex = _uidIndex + 1;
					TAG_disconnectedLoadouts set [_loadoutIndex, _loadoutStr];
				} else {
					//Not found -> Add new
					TAG_disconnectedLoadouts pushBack _uid;
					TAG_disconnectedLoadouts pushBack [_loadoutStr, getPosASL _body, getDir _body];
				};
			};
			false
		}
	];

	addMissionEventHandler [
		"PlayerConnected", 
		{
			params ["_id", "_uid", "_name", "_jip", "_owner"];
			if(_jip) then {
				private _clientData = missionNamespace getVariable ["TAG_disconnectedLoadouts", []];
				private _uidIndex = _clientData find _uid;
				if(_uidIndex > -1) then {
					private _loadoutIndex = _uidIndex + 1;
					(_clientData select _loadoutIndex) remoteExec ["TAG_fnc_loadClientData", _owner];
				};
			};
		}
	];
};

 

  • Thanks 2

Share this post


Link to post
Share on other sites
On 31/12/2017 at 6:39 AM, mrcurry said:

Here we go! Half a month late. Written up on December 15, forgotten about until today. Oops.

 

This should save a disconnecting players loadout, position and facing on the server and will broadcast it back to the player when he/she reconnects as long as the mission isn't restarted.

It does not handle group at this time since it was a maybe (just make sure you select the same group when reconnecting and you should be good). 


It's meant to go in the init.sqf, if you got the CfgRemoteExec whitelist enabled you need to add TAG_fnc_loadClientData to it.

You could also load TAG_fnc_loadClientData through functions library and put the mission eventhandlers in initServer.sqf instead.

 

Disclaimer: I have not done thorough testing. Just a syntax check and a basic logic check. So there might be some edge cases which might be bugged (It's also perfectly possible I missed something :P).

Other than that it should do it's job.


TAG_fnc_loadClientData = {
	_this params ["_loadoutStr", "_positionASL", "_dir"];
	call compile _loadoutStr;
	player setDir _dir;
	player setPosASL _positionASL;
};

if(isServer) then {
	addMissionEventHandler [
		"HandleDisconnect", 
		{
			params ["_body", "_id", "_uid", "_name"];
			
			if(!isNull _body) then {			
				//Init storage var
				if(isNil "TAG_disconnectedLoadouts") then {
					TAG_disconnectedLoadouts = [];
				};
				
				//Save loadout as script for easy broadcast
				private _loadoutStr = [player, "script", false] call BIS_fnc_exportInventory;
				{
					private _index = _loadoutStr find _x;
					if(_index > -1) then {
						private _strArray = toArray _loadoutStr;
						_strArray deleteRange [_index, count _x];
						_loadoutStr = toString _strArray;
					};	
				} forEach ["// Remove existing items","// Add containers","// Add weapons", "// Add items", "// Set identity"];
					
				//Find in storage
				private _uidIndex = TAG_disconnectedLoadouts find _uid;
				if(_uidIndex > -1) then {
					//Found -> update
					private _loadoutIndex = _uidIndex + 1;
					TAG_disconnectedLoadouts set [_loadoutIndex, _loadoutStr];
				} else {
					//Not found -> Add new
					TAG_disconnectedLoadouts pushBack _uid;
					TAG_disconnectedLoadouts pushBack [_loadoutStr, getPosASL _body, getDir _body];
				};
			};
			false
		}
	];

	addMissionEventHandler [
		"PlayerConnected", 
		{
			params ["_id", "_uid", "_name", "_jip", "_owner"];
			if(_jip) then {
				private _clientData = missionNamespace getVariable ["TAG_disconnectedLoadouts", []];
				private _uidIndex = _clientData find _uid;
				if(_uidIndex > -1) then {
					private _loadoutIndex = _uidIndex + 1;
					(_clientData select _loadoutIndex) remoteExec ["TAG_fnc_loadClientData", _owner];
				};
			};
		}
	];
};

 

 

Hello how are you, look I am still learning this scripting and I do not understand much how to put your script to work, could you if it is not too much trouble to explain briefly how to make it work with some quick steps of example?

 

Thanks

Share this post


Link to post
Share on other sites
On 15/09/2018 at 8:54 AM, redburn said:

 

Hello how are you, look I am still learning this scripting and I do not understand much how to put your script to work, could you if it is not too much trouble to explain briefly how to make it work with some quick steps of example?

 

Thanks


I'm pretty sure I mentioned this but it's no trouble. :)

 

Rereading my own instructions I'd say slap the code provided above in your init.sqf inside your mission folder and you should be good.

If you do not have your init.sqf then one will not be provided for you, you must create said init.sqf yourself inside your mission folder.

If you are unaware how to create a text-file and change it's extension then only The Google can help you.

If you are unaware how to google then may whatever diety you choose to worship have mercy on your soul.

 

 

 

 

 

P.s. Jokes aside, it should be pretty straightforward but let me know if you run into any trouble. ^^

  • Haha 2

Share this post


Link to post
Share on other sites
On 17/9/2018 at 4:29 AM, mrcurry said:


I'm pretty sure I mentioned this but it's no trouble. :)

 

Rereading my own instructions I'd say slap the code provided above in your init.sqf inside your mission folder and you should be good.

If you do not have your init.sqf then one will not be provided for you, you must create said init.sqf yourself inside your mission folder.

If you are unaware how to create a text-file and change it's extension then only The Google can help you.

If you are unaware how to google then may whatever diety you choose to worship have mercy on your soul.

 

 

 

 

 

P.s. Jokes aside, it should be pretty straightforward but let me know if you run into any trouble. ^^

 

I only mentioned it because you said that if there were functions you had to do something else, but it´s ok :)

Share this post


Link to post
Share on other sites

Hi, 
i tried to use your code, and the positioning thing is just working for the first time. The loadout save isn`t working at all.
Do you know how to fix it?

Share this post


Link to post
Share on other sites
On 3/11/2020 at 9:54 PM, Sergeant_Emerald said:

Hi, 
i tried to use your code, and the positioning thing is just working for the first time. The loadout save isn`t working at all.
Do you know how to fix it?

TAG_fnc_loadClientData = {
	_this params ["_loadout", "_positionASL", "_dir"];
	player setUnitLoadout _loadout;
	player setDir _dir;
	player setPosASL _positionASL;
};

if(isServer) then {
	addMissionEventHandler [
		"HandleDisconnect", 
		{
			params ["_body", "_id", "_uid", "_name"];
			
			if(!isNull _body) then {			
				//Init storage var
				if(isNil "TAG_disconnectedLoadouts") then {
					TAG_disconnectedLoadouts = [];
				};
				
				//Get data
				private _loadout = getUnitLoadout _body;
				private _position = getPos _body;
				private _direction = getDir _body;
					
				//Find in storage
				private _uidIndex = TAG_disconnectedLoadouts find _uid;
				if(_uidIndex > -1) then {
					//Found -> update
					private _loadoutIndex = _uidIndex + 1;
					TAG_disconnectedLoadouts set [_loadoutIndex, [_loadout, _position, _direction]];
				} else {
					//Not found -> Add new
					TAG_disconnectedLoadouts pushBack _uid;
					TAG_disconnectedLoadouts pushBack [_loadout, _position, _direction];
				};
			};
			false
		}
	];

	addMissionEventHandler [
		"PlayerConnected", 
		{
			params ["_id", "_uid", "_name", "_jip", "_owner"];
			if(_jip) then {
				private _clientData = missionNamespace getVariable ["TAG_disconnectedLoadouts", []];
				private _uidIndex = _clientData find _uid;
				if(_uidIndex > -1) then {
					private _loadoutIndex = _uidIndex + 1;
					(_clientData select _loadoutIndex) remoteExec ["TAG_fnc_loadClientData", _owner];
				};
			};
		}
	];
};
  • Like 1
  • Thanks 2

Share this post


Link to post
Share on other sites
On 3/18/2020 at 9:06 AM, mrcurry said:

TAG_fnc_loadClientData = {
	_this params ["_loadout", "_positionASL", "_dir"];
	player setUnitLoadout _loadout;
	player setDir _dir;
	player setPosASL _positionASL;
};

if(isServer) then {
	addMissionEventHandler [
		"HandleDisconnect", 
		{
			params ["_body", "_id", "_uid", "_name"];
			
			if(!isNull _body) then {			
				//Init storage var
				if(isNil "TAG_disconnectedLoadouts") then {
					TAG_disconnectedLoadouts = [];
				};
				
				//Get data
				private _loadout = getUnitLoadout _body;
				private _position = getPos _body;
				private _direction = getDir _body;
					
				//Find in storage
				private _uidIndex = TAG_disconnectedLoadouts find _uid;
				if(_uidIndex > -1) then {
					//Found -> update
					private _loadoutIndex = _uidIndex + 1;
					TAG_disconnectedLoadouts set [_loadoutIndex, [_loadout, _position, _direction]];
				} else {
					//Not found -> Add new
					TAG_disconnectedLoadouts pushBack _uid;
					TAG_disconnectedLoadouts pushBack [_loadout, _position, _direction];
				};
			};
			false
		}
	];

	addMissionEventHandler [
		"PlayerConnected", 
		{
			params ["_id", "_uid", "_name", "_jip", "_owner"];
			if(_jip) then {
				private _clientData = missionNamespace getVariable ["TAG_disconnectedLoadouts", []];
				private _uidIndex = _clientData find _uid;
				if(_uidIndex > -1) then {
					private _loadoutIndex = _uidIndex + 1;
					(_clientData select _loadoutIndex) remoteExec ["TAG_fnc_loadClientData", _owner];
				};
			};
		}
	];
};

Thank You!

Share this post


Link to post
Share on other sites

I tried to use the script above over the weekend:

- blank mission with one playable character, an arsenal and a vehicle.

- The code above copied into in it.sqf.

- on joining I walked about 15 metres and to the right, turned 180 from starting orientation, and dripped numerous weapons and items from inventory.

- I then disconnected and logged back on. 

 

I spawned back in original position, with original gear.

 

Can anyone confirm this script still works, and if there are any other server side settings I need to make it work?

 

Thanks!

Share this post


Link to post
Share on other sites

First of all, this code is supposed to save loadout/position/direction on server during the mission on server. So, in multiplayer session, during the session (as far as the server is running the mission).

 

If you want to save something in SP or even hosted MP at home, you must save (what you want) in your profileNameSpace. You can use the MEHs  "handleDisconnect" & "playerConnected" as above but your data must be saved in profileNameSpace, not missionNameSpace.

  • Like 1

Share this post


Link to post
Share on other sites

So i tried again, changing missionNamespace to profileNamespace. no joy. 

 

as per above, hosted server. There is stuff mentioned above about whitelists, etc, which i do not understand. Is there anyone who uses this script that can help?

 

thanks

Share this post


Link to post
Share on other sites
3 hours ago, Noel Collins said:

So i tried again, changing missionNamespace to profileNamespace. no joy. 

 

as per above, hosted server. There is stuff mentioned above about whitelists, etc, which i do not understand. Is there anyone who uses this script that can help?

 

thanks

did you change it also in handledisconnect EH ? Without your final code, difficult to help.

Share this post


Link to post
Share on other sites

Original Attempt was with code in init.sqf exactly as above on hosted server, with nothing else done.

This attempt the same code was as below, only change marked in red.:

i dont see a namespace in the handle disconnect EH?

 

thanks

 

 

 

TAG_fnc_loadClientData = {

        _this params ["_loadout", "_positionASL", "_dir"];

        player setUnitLoadout _loadout;

        player setDir _dir;

        player setPosASL _positionASL;

};

 

if(isServer) then {

        addMissionEventHandler [

               "HandleDisconnect",

               {

                       params ["_body", "_id", "_uid", "_name"];

                      

                       if(!isNull _body) then {                    

                               //Init storage var

                               if(isNil "TAG_disconnectedLoadouts") then {

                                      TAG_disconnectedLoadouts = [];

                               };

                              

                               //Get data

                               private _loadout = getUnitLoadout _body;

                               private _position = getPos _body;

                               private _direction = getDir _body;

                                     

                               //Find in storage

                               private _uidIndex = TAG_disconnectedLoadouts find _uid;

                               if(_uidIndex > -1) then {

                                      //Found -> update

                                      private _loadoutIndex = _uidIndex + 1;

                                      TAG_disconnectedLoadouts set [_loadoutIndex, [_loadout, _position, _direction]];

                               } else {

                                      //Not found -> Add new

                                      TAG_disconnectedLoadouts pushBack _uid;

                                      TAG_disconnectedLoadouts pushBack [_loadout, _position, _direction];

                               };

                       };

                       false

               }

        ];

 

        addMissionEventHandler [

               "PlayerConnected",

               {

                       params ["_id", "_uid", "_name", "_jip", "_owner"];

                       if(_jip) then {

                               private _clientData = profileNamespace getVariable ["TAG_disconnectedLoadouts", []];

                               private _uidIndex = _clientData find _uid;

                               if(_uidIndex > -1) then {

                                      private _loadoutIndex = _uidIndex + 1;

                                      (_clientData select _loadoutIndex) remoteExec ["TAG_fnc_loadClientData", _owner];

                               };

                       };

               }

        ];

};

Share this post


Link to post
Share on other sites

TAG_disconnectedLoadouts also needs to be changed, the script in its current form relies on that global variables are defined in missionNamespace unless otherwise specified.

 

But just changing out which namespace is used is gonna cause undefined behaviour when the same server runs multiple missions running the script.

 

I've been planning to rewrite this using hashmaps anyway so I'll see about writing up a version for profileNamespace too

  • Like 1

Share this post


Link to post
Share on other sites

Here is my contrib. I added some log lines. Seems to work, but should be tested deeper:


 

TAG_fnc_loadClientData = {
      params ["_loadout", "_positionASL", "_dir"];
      waitUntil {!isNull player};
      player setUnitLoadout _loadout;
      player setDir _dir;
      player setPosASL _positionASL;
    };

if (isServer) then {
  profileNameSpace setVariable ["TAG_disconnectedLoadouts",nil];

  addMissionEventHandler ["HandleDisconnect",
    {
      params ["_body", "_id", "_uid", "_name"];
      if(!isNull _body) then {
          private _loadout = getUnitLoadout _body;
        private _position = getPos _body;
        private _direction = getDir _body;
        if(isNil {profileNameSpace getVariable "TAG_disconnectedLoadouts"}) then {
          profileNameSpace setVariable ["TAG_disconnectedLoadouts",createHashMapFromArray [[_uid,[_loadout,_position,_direction]]]];
        } else {
          (profileNameSpace getVariable "TAG_disconnectedLoadouts") set [_uid,[_loadout,_position,_direction]];
        };
diag_log [_uid,(profileNameSpace getVariable "TAG_disconnectedLoadouts")];
      };
      false
    }
  ];

  addMissionEventHandler ["PlayerConnected",
    {
      params ["_id", "_uid", "_name", "_jip", "_owner"];
      if(_jip) then {
        private _clientData = profileNamespace getVariable ["TAG_disconnectedLoadouts", []];
        if (_clientData isEqualTo []) exitWith {};
        private _value = _clientData get _uid;
diag_log ["<<<<<after connect>>>>",_value,_this];
      [_value,TAG_fnc_loadClientData] remoteExec ["spawn", _owner];
      };
    }
  ];
};

 

  • Like 1

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×