Jump to content
pawelisus

Side change lock for a time period

Recommended Posts

I'm trying to create a script that would block players to their sides for a period of time who try to get more intel about enemy  positons. I've figured out how to get time for how long they are locked but i dont know how to store that information in such way that would prevent it from disappearing. The best way would be when that data dissapeared entirely after restart but most important for me is to find a way to store that data even if player leaves.

Share this post


Link to post
Share on other sites

This should get done server side. You could just store the IDs of players together with their chosen side in an array or a hashmap.

Every time a player reconnects you just look for the ID and can get its prior chosen side. 

 

https://community.bistudio.com/wiki/Array

 

https://community.bistudio.com/wiki/getPlayerUID

 

https://community.bistudio.com/wiki/onPlayerConnected

 

https://community.bistudio.com/wiki/Event_Scripts#initServer.sqf

  • Like 1

Share this post


Link to post
Share on other sites

I think you've made it clear for me. I'll try to make it, in case of problems I won't hesitate to ask. Thanks

 

Share this post


Link to post
Share on other sites

I did not have tested anything but this is the way I would try it.

 

initServer.sqf

SARO_playerSideArray = [];

addMissionEventHandler ["PlayerConnected", 
{
 _this spawn
 {
  //time the player is forbidden to chose another side - in minutes
  private _restrictedChangeTime = 10;

  // all players with these sides chosen will get checked for side change
  private _restrictedSidesArray = [west, east, independent];

  params ["", "_uid", "_name"];
  
  private [ "_dummy", "_playerUnit", "_playerIndex", "_playerNotFound" ];
  
  // wait until the connected client is spawned as player object
  waitUntil
  {
   sleep 1;
   _playerUnit = _uid call BIS_fnc_getUnitByUID;
   not isNull _playerUnit
  };
   
  _playerSide = side _playerUnit;

  // exit if player did not choose a restricted side
  if !( _playerSide in _restrictedSidesArray ) exitWith {};
   
  _playerIndex = SARO_playerSideArray findIf { _x select 0 isEqualTo _uid };
  _playerNotFound = _playerIndex < 0;

  if (_playerNotFound) then
  {
   _dummy = SARO_playerSideArray pushBack [ _uid, _playerSide, diag_tickTime ];                         
  } else
  {
   private _priorSide = SARO_playerSideArray select 1;
   private _timeUntilChange = (diag_tickTime - SARO_playerSideArray select 2) / 60 - _restrictedChangeTime;

   if ( _playerSide isNotEqualTo _priorSide and _timeUntilChange > 0 ) then
   {
     private _string = format 
     [ 
     "%1, before choosing another side you have to play on side %2 for another %3 minutes!",
      _name,
      _priorSide,
      _timeUntilChange
     ];
     
     _string remoteExec ["hint", _playerUnit];

     sleep 3;
     ["end1", BIS_fnc_endMission] remoteExec ["call", _playerUnit];
   };
  };
 };
}];

 

  • Like 2

Share this post


Link to post
Share on other sites

Above code is ready to get tested and debugged. Im not able to do this because Ive no arma 3 pc for another week and also i think i dont like to set up a dedicated server just to test this. Therefore I can help with debugging but I ll not test the code myself.

 

Possible problems I see:

BIS_fnc_getUnitByUID - may not return objNull when player is not spawned yet

"end1" call BIS_fnc_endMission; - idk if this is the corret end for sending player back to lobby.

 

If you test the code and get any error or not intended behavior just post it here and I ll try to help.

  • Like 1

Share this post


Link to post
Share on other sites

I was writing code for this and I think i've done it too but i have two small issues:

1. When I'm trying to get player side it is always WEST whenever In blufor or Opfor. I was using playerSide function, but i've seen that you're doing it other way so i'll change to your way.

2. function endMission "END1" ends whole mission. I think its happening because I didn't configured it propperly. I've noticed that when I call it my character freezes without any briefing screen for something like 15 seconds. I'm doing debugging of this code on clean mission and endMission "END1" works propperly on liberation that I'm working on so if I merge this script to liberation it should work fine

 

 

Share this post


Link to post
Share on other sites

What does the _this spawn do? I mean I've read what it do in the docs but what does it do specificaly to fix the problem

 

Share this post


Link to post
Share on other sites
1 hour ago, pawelisus said:

What does the _this spawn do?

 

It spawns the following code block with params from the EH. This is necessary because the EH is an unscheduled environment where suspension (sleep/waitUntil/etc.) is not allowed. Spawned code runs in a scheduled environment, which allows suspension.

 

 

  • Like 1

Share this post


Link to post
Share on other sites

see also recent commands like:

getUserInfo

It returns a lot of info like the client state number

I didn't dig into it but, if I'm right people disconnecting/connecting means leaving the mission and reloading it on same server (state "connected", state number 2).

What about people leaving for lobby (so staying in mission)?
Or, if you want, how do you understand state "Logged In" (state number 3) and state "role assigned" (state number 6) and how are you detecting that?

I admit the whole sequence is not clear for me, and the sequence: in game - return to lobby - change for another role seems to me difficult to trace. Not sure MEH "playerConnected" is firing here.

  • Like 3

Share this post


Link to post
Share on other sites
2 hours ago, pierremgi said:

sequence: in game - return to lobby - change for another role seems to me difficult to trace. Not sure MEH "playerConnected" is firing here.

Yeah, I missed this and did not cover it in my code...

Hard to trace this server side only. 

Maybe there is a smarter client side only solution by storing the chosen side in profile namespace but idk how client can detect if server actually runs the same mission session or if it was restarted. Maybe one could just use the mission time for this.

Share this post


Link to post
Share on other sites

I think I made it to work like i wanted but I cant figure why endMission "END1"; frezees my character in place and ends entire mission except of kicking only one player. It's propably very obvious why but I'm new to sqf

Share this post


Link to post
Share on other sites

If u want to get help then u need to show ur code and also how/where u execute it.

Share this post


Link to post
Share on other sites

InitServer.sqf

SideLockArray = []; // Array storing data about lock [player Id, server time + for how long player is locked in seconds , player side];

addMissionEventHandler ["PlayerDisconnected", {

	private ["_playerUnit"];
	_exist = false;
	_playeruid = _this select 1;

	_SLArrayLength = Count SideLockArray;

	if (_SLArrayLength != 0) then    // Checks if array isn't empty to prevent making errors
	{
		for "_i" from 0 to _SLArrayLength -1 do {
				_record = SideLockArray select _i;
				_checkeduid = _record select 0;
				if (str _checkeduid == str _playeruid) then {_exist = true};
		};
	};

	if (_exist == false) then {  // If player not present in database we have to add him

		// wait until the connected client is spawned as player object
  		waitUntil
  		{
  			sleep 1;
  			_playerUnit = _playeruid call BIS_fnc_getUnitByUID;
  			not isNull _playerUnit;
  		};

		SideLockArray append [ [_this select 1, time + 30 , side _playerUnit] ];
	
	};
		
}];


addMissionEventHandler ["PlayerConnected", {

	_this spawn {


	if (isNil {SideLockArray select 0} ) then
	{
		format ["Table contents: %1", SideLockArray] remoteExec ["hint"];
	}
	else
	{
		format ["Started with : %1", _this select 1] remoteExec ["hint"];

		_playeruid = _this select 1; // player id who we are looking for
		private ["_playerUnit"];

		// wait until the connected client is spawned as player object
  		waitUntil
  		{
  			sleep 1;
  			_playerUnit = _playeruid call BIS_fnc_getUnitByUID;
  			not isNull _playerUnit;
  		};
		

		_playerside = side _playerUnit;
		_servertime = time;

		// Looking for a player if he's in the array

		for "_i" from 0 to (Count SideLockArray) -1 do {
			_record = SideLockArray select _i;
			_checkeduid = _record select 0; 



			if (str _checkeduid == str _playeruid) then
			{
				_checkedtime = _record select 1;
				_checkedside = _record select 2;
				format ["present in database: %1" ,_playeruid] remoteExec ["hint"];

				if (_playerside != _checkedside && _checkedtime >= _servertime) then { // If he joined different side than his last one he'll get locked
					format ["Player is locked: %1" ,_playeruid] remoteExec ["hint"];

					// endMission "END1"; // - Ending entire mission **That's my problem**

				}
				else 
				{
					SideLockArray deleteAt _i; // Deleting him from Array if he rejoined his side
				};
			};
		
		};
	
	};
      
	};
}];

Firstly i want to make something that works and then optimalise. I'll add for how long someone gets locked as a parameter and I need to add something to break for loops to save time or change it entirely f.e. to while loop but I focused on getting to work first. Of course hints are only there for debugging purposes

Share this post


Link to post
Share on other sites

you are ending the mission server side. This is the problem. I alreqdy showed how to do it on the client.

Also the problem which @pierremgi described persists...

  • Like 1

Share this post


Link to post
Share on other sites
2 minutes ago, sarogahtyp said:

you are ending the mission server side. This is the problem. I alreqdy showed how to do it on the client.

Also the problem which @pierremgi described persists...

When I was using your way same thing happened, Maybe I'm doing something wrong, I'll try second time. In my code when player went to lobby it worked fine, If i understood him correctly

Share this post


Link to post
Share on other sites
17 minutes ago, sarogahtyp said:

you are ending the mission server side. This is the problem. I alreqdy showed how to do it on the client.

Also the problem which @pierremgi described persists...

["end1", BIS_fnc_endMission] remoteExec ["call", _playerUnit]; works like a charm... I'm sorry for my ignorance and thanks a lot for giving me general idea and helping with my problems, Hope I didnt upset you much. Last thing is the @pierremgi problem. I dont think it exists. From my testing, EH PlayerConnected fires when player chooses unit in lobby AND clicks ok, EH PlayerDisconnected fires when he clicks abort in pause menu

  • Like 1

Share this post


Link to post
Share on other sites
4 hours ago, pawelisus said:

 Last thing is the @pierremgi problem. I dont think it exists. From my testing, EH PlayerConnected fires when player chooses unit in lobby AND clicks ok, EH PlayerDisconnected fires when he clicks abort in pause menu

You're testing hosted server. So, yes, abort mission will disconnect the player as well.

Test it on client. When you abort as client, you return to lobby but you need to click on disconnect for leaving the mission. If not, you can join as another character....

 

I'm not testing deeply but what you can do is something like that:

in initServer.sqf

 

{serverNamespace setVariable [_x,nil]} forEach allVariables serverNamespace; // just for test,.... for mission, manage the variables as you want (see below)

 

addMissionEventHandler ["PlayerConnected", {
  params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
  _idstr spawn {
    params ["_id"];
    waitUntil {getUserInfo _id isNotEqualTo [] && {isPlayer (getUserInfo _id #10)}};
    if (isNil {serverNameSpace getVariable _id}) then {
        serverNameSpace setVariable [_id,[getUserInfo _id #2, getUserInfo _id #10, side (getUserInfo _id #10)]];
        diag_log [_id,"playerConnected",serverNameSpace getVariable _id];
        systemChat str [_id,"playerConnected",serverNameSpace getVariable _id];
    };
  };
}];


addMissionEventHandler ["OnUserClientStateChanged", {
    params ["_networkId", "_clientStateNumber", "_clientState"];
    systemChat str [_networkId, _clientStateNumber, _clientState];
    diag_log [_networkId, _clientStateNumber, _clientState];
    if (!isNil {serverNameSpace getVariable _networkId} && _clientStateNumber == 11) then {
        private _nom = getUserInfo _networkId #3;
        hint format ["player %1 is in lobby",_nom]; // displayed on server of course
        // do what you want here. I don't know how to "kick" a player from lobby
    };
}];

 

 

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

×