Jump to content
Sign in to follow this  
bangabob

Detect if player disconnect

Recommended Posts

_addactionUser = (_this select 1);
_id =(_this select 2);

if (!GLB_AlphaRally) exitwith {hint "Alpha Rally is already deployed. Un-deploy Rally point to access it.";};				
sleep 1;

PAPABEAR sideChat format["%1 has picked up the Alpha Rally point",name _addactionUser];
	hint format ["You have %1 seconds to deploy the rally point",_carrytime];
	GLB_AlphaRally = false;publicVariable "GLB_AlphaRally";	
	GLB_AlphaRallyTake=true;publicVariable "GLB_AlphaRallyTake";


_addactionUser addAction["<t color='#ffff00'>Build Alpha Rally</t>","occupation\rallypoints\AlphaRallyBuild.sqf","",1,false,true,"","GLB_AlphaRallyTake"];
waituntil {!GLB_AlphaRallyTake};
_addactionUser removeAction _id;
GLB_AlphaRally = false;publicVariable "GLB_AlphaRally";

This is some code for an addaction which gives a player a rally point.

I need some code which will detect if "_addactionUser" has disconnected and then update GLB_AlphaRally = true. So the action is available again for other players.

Any help appreciated. Thanks

Share this post


Link to post
Share on other sites
There's this example here.

Hmm. I did look at that earlier. I just can't get my head around how i would use it.

If i am understanding this correctly, every time a player disconnects, onplayerdisconnected gets that players name as (_this select 1). And i need to check if

(_this select 1) == _addactionUser from my addaction script.

But can i do that.

BTW i tried several other ways. Including if (!alive _addactionUser) but that doesn't count for disconnecting. And i've even ran a timer which resets the GLB_AlphaRally = true after a set amount of time. But that doesn't work on dedicated servers because the addaction is local.

Share this post


Link to post
Share on other sites

you basically need to check ll playable units against the one disconnecting. Check first to ensure its not the __Server__ uid, then check through playable units uids to see if it is the player leaving.

example...

_id = _this select 0; 
_caller = _this select 1; 
_uid  = _this select 2; 

		//check if the uid given is for player or server
		//__server__ 
		if (_caller != "__SERVER__") then 
		{
			        _player = objNull;
					{

					if (getPlayerUID _x == _uid) exitWith 

					  {
						   _player = _x;
					  };
					} 
					forEach playableUnits;  
                         };

basically any mention to _player is the player disconnecting. not sure how you will link it, but can try to use set variable(and true) to store anything like you want on _addactionUser.

set it to something on the script above and then when _player leaves - set it to something else. have a script that gets the variable for the _player and check when it changes. if that makes sense

Share this post


Link to post
Share on other sites

Thanks Mikie boy . I appreciate you taking the time to write a example.

The thing i really have trouble with is the set/get variable command.(which is what i need to use here).

I've attempted what you said but i don't understand enough to make it work.

Share this post


Link to post
Share on other sites

You need to have in the activation script _whoeveactivated setvariable ["active", 1, true]; this in effect is setting a variable to this player, specific to him and set to a value of 1. U then can call another script to regularly check the value of this player and the active variable. If its 0 then remove whatever was created with the addaction script.

In the onplayerdisconnect script have _player setvariable ["ACTIVE", 0, TRUE];

THIS Is the change that the looping script will detect. Sorry on train typing on a not so smart phone

Share this post


Link to post
Share on other sites

Great help. So this is what i've cobbled together from everything you've told me. Just a rough edit but is this what you mean?

init.sqf

if (isnil {GLB_AddActionUsed}) then {
GLB_AddActionUsed = false;publicvariable "GLB_AddActionUsed";
};
null = [] execvm "actionCheckLoop.sqf";

onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "playerDisconnected.sqf" }; 

Addaction.sqf (Called using action on flagpol)

 
// SET VARIABLE TO CHECK IF ADDACTION USER IS STILL IN GAME
_whoeveactivated = (_this select 1);
_actionID=(_this select 2);
_whoeveactivated setvariable ["active", 1, true];

// ADD ACTION ALREADY USED
if (GLB_AddActionUsed) exitwith 
{
hint "Come back later. Addaction is already used"
};

// GIVE USER ADDACTION
_whoeveactivated addAction["Build Rally","createRally.sqf"];

// SET CURRENT ACTION AS USED
GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed";

waituntil {createRally called};
_whoeveactivated removeAction _actionID;

playerdisconnected.sqf

 
_id = _this select 0; 
_caller = _this select 1; 
_uid  = _this select 2; 

		//check if the uid given is for player or server
		//__server__ 
		if (_caller != "__SERVER__") then 
		{
			        _player = objNull;
					{

					if (getPlayerUID _x == _uid) exitWith 

					  {
						   _player = _x;
					  };
					} 
					forEach playableUnits;  
                         };
		// SET PLAYER AS LEFT
		_player setvariable ["ACTIVE", 0, TRUE]; 

actionCheckLoop.sqf

 while {true} do
{sleep 1;
	_aVariable = _player getVariable "ACTIVE";
	if (_aVariable == 0) then {
		// IF ADDACTION USER DISCONNECTED THEN SET GLOBAL VAR TO ALLOW USE OF ADDACTION AGAIN
		GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";
	};
};						

Edited by BangaBob

Share this post


Link to post
Share on other sites

yeah sort of....

playerdisconnected - _player should be inside that scope.

actionCheckLoop - this wont work as you need to pass the specific player with the actual setvariable - however you could set all players to "active", 0 when they join, that way you could use this method. Remember to set _player to player if running from init.sqf

other way is to run this script as a function and pass the specific player with the setvariable active to it.

see how you get on and let me know -

Share this post


Link to post
Share on other sites
yeah sort of....

playerdisconnected - _player should be inside that scope.

actionCheckLoop - this wont work as you need to pass the specific player with the actual setvariable - however you could set all players to "active", 0 when they join, that way you could use this method. Remember to set _player to player if running from init.sqf

other way is to run this script as a function and pass the specific player with the setvariable active to it.

see how you get on and let me know -

Okay i have got the get/set variables set up.

using a function

 Check_action_FNC = {
_whoeveactivated = (_this select 0);
				//hint format ["%1",_whoeveactivated];

				_aVariable = _whoeveactivated getVariable "ACTIVE";

				hint format ["%1",_aVariable];
				if (_aVariable == 0) then {

				// IF ADDACTION USER DISCONNECTED THEN SET GLOBAL VAR TO ALLOW USE OF ADDACTION AGAIN
				GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";
										};
};					

This function is called every second inside a loop

Addaction script on flag pole.

// SET VARIABLE TO CHECK IF ADDACTION USER IS STILL IN GAME

		_whoeveactivated = (_this select 1);
		_actionID=(_this select 2);
		_whoeveactivated setvariable ["active", 1, true];


// ADD ACTION ALREADY USED
		if (GLB_AddActionUsed) exitwith 
			{
				hint "Come back later. Addaction is already used"
			};

// RUN FUNCTION TO CHECK IF PLAYER DISCONNECTED

				[_whoeveactivated] spawn {
				_whoeveactivated= (_this select 0);

					while {true} do {sleep 1;
						0=[_whoeveactivated] call Check_action_FNC;
								};
								};

// SET CURRENT ACTION AS USED
		GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed";
// GIVE USER ADDACTION
hint "Got rally!";
		_whoeveactivated addAction["Build Rally","createRally.sqf"];

waituntil {GLB_rallyBuilt};
		_whoeveactivated removeAction _actionID;
GLB_AddActionUsed = false;publicvariable "GLB_AddActionUsed";

I dont understand how the onplayerdisconnected command will work.

Should i call it from the init.sqf?

If so i dont understand how "_player setvariable ["ACTIVE", 0, TRUE]; " will be linked to _whoeveactivated.

Hope this makes sense.

Sorry if im missing something obvious. Im just getting fed up of ArmA.lol

Edited by BangaBob

Share this post


Link to post
Share on other sites

init.sqf

player setvariable ["active", 0, true];

if (isDedicated) then
{

onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "OnPlayerDisconnect.sqf" };

}; 

when a player disconnects his id name and uid are passed to the OnPlayerDisconnect.sqf - thus it will trigger automatically.

as for this [_whoeveactivated] call Check_action_FNC; ... you should call this once then have the loop in the function. let that run until it player disconnects.

lets say bob is the character that joins the game. when he activates the addaction - it will be _whoeveactivated setvariable ["Active", 1, true]; which is technically...bob setvariable ["Active", 1, true]; that remains as is until it gets changed through setvariable.

_player is identified by the uid - from checking each uid of all playable units, its then compared against the uid passed to the onplayerdisconnected .sqf. once this is confirmed the name/object of the identified playableunit is assigned to _player. Thus in our case bob is the player leaving, his uid will be found in the array of playable units to match that of the uid passed to the onplayerdisconnected .sqf. Thus - _player is actually bob. therefore when you change _player setvariable ["Active", 0, true]; you are actually saying bob setvariable ["active", 0, true];

now if dave leaves the game - he will become _player at the point he leaves and it will be dave setvariable ["active",0, true]; however dave never had his active variable set to 1, so it doesnt matter, and furthermore even if you changed it. Your while loop is checking bob getvariable "active" - not dave getvariable "active" - you can see it wouldnt matter.

Share this post


Link to post
Share on other sites

Great explantion. I understand now.

However it still doesn't work properly in my tests.

Inside my init.sqf

 


player setvariable ["active", 0, true];

if (isDedicated) then
{
onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "OnPlayerDisconnect.sqf" };
};

if (isnil {GLB_AlphaRally}) then {
GLB_AlphaRally = false;publicvariable "GLB_AlphaRally";
};
null = [] execvm "Myfunction.sqf";

OnPlayerDisconnect.sqf (Where i think im going wrong)

 _id = _this select 0; 
_caller = _this select 1; 
_uid  = _this select 2; 

		//check if the uid given is for player or server
		//__server__ 
		if (_caller != "__SERVER__") then 
		{
			        _player = objNull;
					{

					if (getPlayerUID _x == _uid) exitWith 

					  {
						   _player = _x;
						   _player setvariable ["ACTIVE", 0, TRUE]; 
					  };
					} 
					forEach playableUnits;  
                         };

Its a real pain testing onplayerdisconnected...

Could it be that when i rejoin

its setting "bobs" variable as 0 again.

player setvariable ["active", 0, true];

Actually just realised that doesnt matter because the function would set the GLB_AddActionUsed to false anyway.

Myfunction.sqf

Check_action_FNC = {
_whoeveactivated = (_this select 0);

while {true} do {sleep 1;
				_aVariable = _whoeveactivated getVariable "ACTIVE";

				hint format ["%1",_aVariable];
				if (_aVariable == 0) then {

				// IF ADDACTION USER DISCONNECTED THEN SET GLOBAL VAR TO ALLOW USE OF ADDACTION AGAIN
				GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";
										};

									};
};					 

Share this post


Link to post
Share on other sites

you could try using on playerconnected much like you have done with onplayerdisconnected to set the active variable to 0 for all players.

it could also be that the while loop is not returning anything as it MAY (not sure) not be getting anything for you player as he left - cant be certain on that - trying to think of a better way to do it.

as this can only be used once - you could simply have a global variable to sort this out.

(not at the start of the addaction script - otherwise all those who call it will override it - maybe in one of the if statements);

whoeveactivated = _this select 0; PV it as well

then in the onplayerdisconnected script - have if (_player == whoeveactivated) then {GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";};

Share this post


Link to post
Share on other sites

Thanks very much Mikie boy.

I believe i have a finished product. Just need to test it with a friend to make SURE that the global variable isn't overwritten by anyone trying to access the addaction script after its called once.

So incase anyone is interested this is it.

This script simulates picking up a Rally point, and while its taken no one else can get a rally point.

- Unless the person that picked up the rally point disconnects

- The person that picked up the rally point is killed.

- The final addaction (destroyRally.sqf) is used.

On the map i have a flag pole a fireplace and a marker named "rallyAlpha" and a gamelogic named fob_alpha

flag pole init

this addAction["<t color='#ffff00'>Get Rally Point</t>", "occupation\rallypoints\collectRally.sqf"]; 

I also have a fireplace in the corner of the map named "rallyAlphaObject"

fireplace init

this addAction ["<t color='#ffff00'>Remove RallyPoint</t>", "occupation\rallypoints\DestroyRally.sqf",[rallyALPHA]]; 

init.sqf

if (isDedicated) then
{
onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "occupation\rallypoints\OnPlayerDisconnect.sqf" };
};
PAPABEAR=[independent,"HQ"];
if (isnil {GLB_AddActionUsed}) then {
GLB_AddActionUsed = false;publicvariable "GLB_AddActionUsed";
};

collectRally.sqf

			_whoeveactivated = (_this select 1);
		_actionID=(_this select 2);

// CHECK IF RALLY POINT IS TAKEN
		if (GLB_AddActionUsed) exitwith 
			{
				hint "Come back later. Rally point is already taken";
			};

// RALLY POINT TAKER IS IN GLOBAL VARIABLE. IF HE DISCONNECTS THEN SET RALLY AS NOT TAKEN
GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed";				
whoeveactivated = _this select 1;publicvariable "whoeveactivated";

// RALLY POINT IS READY TO BE PLACED
		GLB_PLANTRALLY=true;publicvariable "GLB_PLANTRALLY";

// COLLECT RALLY POINT (Add backpack)
whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon";sleep 1.3;
whoeveactivated addbackpack "B_Carryall_Base";

// ALERT PLAYERS THAT RALLY POINT IS TAKEN
hint "You have the Rally Point";
PAPABEAR sideChat format["%1 has Collected the rally point from base.",name whoeveactivated];
whoeveactivated addAction["<t color='#ffff00'>Build Rally point</t>","occupation\rallypoints\createRally.sqf","",1,false,true,"","GLB_PLANTRALLY"];

// LOOP CHECK IF RALLY POINT TAKER DIES
[] spawn {
waituntil {GLB_AddActionUsed};
	while {GLB_PLANTRALLY} do {sleep 1; 
		if (!alive whoeveactivated) exitwith {
		PAPABEAR sideChat format["%1 has being killed. Rally point available at base.",name whoeveactivated];
		GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";removeBackpack whoeveactivated;
		};
	};
};

// REMOVE ACTION
waituntil {!GLB_AddActionUsed};
whoeveactivated removeAction _actionID;

createRally.sqf

 			_RallypointCarrier=(_this select 0);
		_whoeveactivated = (_this select 1);
		_actionID=(_this select 2);

	if (!(_whoeveactivated ==_RallypointCarrier)) exitwith {hint "You are not carrying the Rally point"};
_whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon";
sleep 1.3;
removeBackpack _whoeveactivated;

hint "Rally point Deployed";
PAPABEAR sideChat format["%1 deployed the Rally point. Use it to re-deploy.",name _whoeveactivated];
rallyALPHA setpos(getpos _whoeveactivated);

	_degrees = getDir  _whoeveactivated; 
	_spawnPos = [getpos _whoeveactivated, 2, _degrees] call BIS_fnc_relPos; 
	"rallyAlpha" setmarkerpos _spawnPos;
	rallyAlphaObject setpos _spawnPos;
	[rallyALPHA] join basesquad;

GLB_PLANTRALLY=false;publicvariable "GLB_PLANTRALLY";

DestroyRally.sqf

private ["_whoeveactivated","_rallyArray","_fireplace","_rallypoint"];
_fireplace = _this select 0;
_whoeveactivated = _this select 1;
_rallyArray = _this select 3;
_rallypoint = _rallyArray select 0;

_whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon";
sleep 1.3;

hint "Rally point removed";
PAPABEAR sideChat format["%1 has removed the Rally point. It is now available at base.",name _whoeveactivated];

_fireplace setpos [0,0,0];
[_rallypoint] join grpNull;
"rallyAlpha" setmarkerpos (getpos BTC_base_flag_east);

GLB_AddActionUsed =false;publicVariable "GLB_AddActionUsed"; 

onplayerdisconnected.sqf

_id = _this select 0; 
_caller = _this select 1; 
_uid  = _this select 2; 

		//check if the uid given is for player or server
		//__server__ 
		if (_caller != "__SERVER__") then 
		{
			        _player = objNull;
					{

					if (getPlayerUID _x == _uid) exitWith 

					  {
						   _player = _x;
						    if ((_player == whoeveactivated)and GLB_PLANTRALLY) then {GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";
							PAPABEAR sideChat format["%1 has disconnected. Rally point is back at base.",name whoeveactivated];};
					  };
					} 
					forEach playableUnits;  
                         };

NOTE: The codes referring to groups is something to do with my teleport script.

Hope somebody finds this useful

Edited by BangaBob

Share this post


Link to post
Share on other sites

i dont think that will work in its current state - forexample - if (GLB_AddActionUsed) exitwith generally doesnt exit the script it only exits the scope so it will always set whoeveactivated as who ever uses the add action - even though it may be in place - try re-working the if statement section of when its active to ensure it doesnt get over written...

if (GLB_AddActionUsed) then
			{
				hint "Come back later. Rally point is already taken";
			} else {
                                         GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed";				
                                          whoeveactivated = _this select 1;publicvariable "whoeveactivated";
                                        };

Share this post


Link to post
Share on other sites
i dont think that will work in its current state - forexample - if (GLB_AddActionUsed) exitwith generally doesnt exit the script it only exits the scope so it will always set whoeveactivated as who ever uses the add action - even though it may be in place - try re-working the if statement section of when its active to ensure it doesnt get over written...

if (GLB_AddActionUsed) then
			{
				hint "Come back later. Rally point is already taken";
			} else {
                                         GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed";				
                                          whoeveactivated = _this select 1;publicvariable "whoeveactivated";
                                        };

That was my main concern. I will look at it again tomorrow with a fresh perspective. Any ideas on how to prevent my global variable being overwritten?

Share this post


Link to post
Share on other sites

as ive detailed above - should do the trick... give it ago and then let me know.

you could even try and prevent the addaction being run by more than two people accidentally at one time - just a condition at start

Share this post


Link to post
Share on other sites
as ive detailed above - should do the trick... give it ago and then let me know.

you could even try and prevent the addaction being run by more than two people accidentally at one time - just a condition at start

Yes I just realised that. If your if command works(which im sure it will anyway)then I'll stick with my current system else I'll just use a condition on the addaction itself

Share this post


Link to post
Share on other sites

Just in-case you were wondering my original script works just fine, Tested it on a dedicated with a friend and didn't get any conflicts. I tried your if command too but when the person that takes the rally point click on the flag pole again the hint shows about 'coming back later' but then the animation plays and i get a second 'build rally' action.

Share this post


Link to post
Share on other sites

_whoeveactivated = _this select 1;
_actionID= _this select 2;

// CHECK IF RALLY POINT IS TAKEN
if (GLB_AddActionUsed) then 
	{
		hint "Come back later. Rally point is already taken";
	}else
		{

	// RALLY POINT TAKER IS IN GLOBAL VARIABLE. IF HE DISCONNECTS THEN SET RALLY AS NOT TAKEN
		GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed";				
		whoeveactivated = _this select 1; publicvariable "whoeveactivated";

	// RALLY POINT IS READY TO BE PLACED
		GLB_PLANTRALLY=true;publicvariable "GLB_PLANTRALLY";

	// COLLECT RALLY POINT (Add backpack)
		whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon";
		sleep 1.3;
		whoeveactivated addbackpack "B_Carryall_Base";

	// ALERT PLAYERS THAT RALLY POINT IS TAKEN
		hint "You have the Rally Point";
		PAPABEAR sideChat format["%1 has Collected the rally point from base.",name whoeveactivated];
		whoeveactivated addAction["<t color='#ffff00'>Build Rally point</t>","occupation\rallypoints\createRally.sqf","",1,false,true,"","GLB_PLANTRALLY"];

		// LOOP CHECK IF RALLY POINT TAKER DIES
		[] spawn {
		waituntil {GLB_AddActionUsed};
				while {GLB_PLANTRALLY} do 
					{
						sleep 1; 
						if (!alive whoeveactivated) exitwith 
						{
						PAPABEAR sideChat format["%1 has being killed. Rally point available at base.",name whoeveactivated];
						GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";removeBackpack whoeveactivated;
						};
					};
				};

		// REMOVE ACTION
		waituntil {!GLB_AddActionUsed};
		whoeveactivated removeAction _actionID;
		};//else

http://community.bistudio.com/wiki/exitWith EXITWITH Wiki... just for future reference

If the result of condition is true, code is evaluated, and current block with result of code. It only exits the current scope.

exitWith exits the execution of a loop defined by one of commands do, for, count or forEach. When you use exitWith not inside a loops, the behaviour is undefined - sometimes it may exit the script, sometimes some other scope, but this is not intended and designed behaviour of this command, and it is not guaranteed to work reliably.

It exits the loop only, not the script.

Share this post


Link to post
Share on other sites

Thanks Mikie.

Its such a simple thing to put the script in a ELSE command instead of relying on the unreliable exitwith command. Gives me some more confidence that the system will work correctly.

But for the sake of understanding.

			_whoeveactivated = (_this select 1);
		_actionID=(_this select 2);

// CHECK IF RALLY POINT IS TAKEN
		if (GLB_AddActionUsed) exitwith 

Surely this exitwith will see the whole script as its scope? since its not nested within anymore commands?

Share this post


Link to post
Share on other sites

alas no - it will simply jump to the next line - but it can work from time to time - as the wiki states " it is not guaranteed to work reliably." So best to be safe and sure that what you have got works 100 percent :)

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
Sign in to follow this  

×