As promised, I wrote some logic to work with get_friends and check_player extensions. But first I’d like to thank one more person for his donation and support. Thank you, Andrey! Большое спасибо, Андрей, за поддержку!

Now the logic. Both examples use the same principle: send request to extension then keep checking extension until result is ready. There is a 10 seconds timeout built in to release spawned script if something went wrong. If you do use these extensions, you will be responsible for clearing extension memory yourself (mostly on busy and long running servers).

First example is for get_friends extension. When player joins, server requests a friendlist for this player from Steam. The idea is to pass this list to player’s PC so that friend search among existing players is then done locally, on player’s PC. The code should go to the bottom of init.sqf and will automatically display compiled array of friend UIDs in a hint, when the player joins dedicated server.

I made it so that server passes UIDs as a string to save bandwidth and server CPU, which then call compiled on the client. The transfer is done using publicVariableServer and publicVariableClient commands, which are not persistent and more secure. The client also generates random number string which then it expects to receive back from the server together with results. What you do with the friendlist after you receive it on the client is up to you. The code:

onPlayerConnected { "get_friends" callExtension _uid; }; "#PV_FL" addPublicVariableEventHandler { 0 = _this select 1 spawn { if (isDedicated) then { _player = objectFromNetId (_this select 0); _puid = getPlayerUID _player; _time = time + 10; private "_FL"; waitUntil { _FL = "get_friends" callExtension _puid; _FL != "WAIT" || {_FL = "[]"; time > _time} }; missionNamespace setVariable ["#PV_FL", [ _this select 1, _FL ]]; owner _player publicVariableClient "#PV_FL"; } else { if ( _this select 0 isEqualTo (uiNamespace getVariable "_rnd") ) then { _FL = uiNamespace getVariable ["_FL", []]; if (_FL isEqualTo []) then { _FL = call compile (_this select 1); uiNamespace setVariable ["_FL", _FL]; }; //deal with FL here hint str _FL; }; }; }; }; if (!isDedicated) then { 0 = 0 spawn { waitUntil {!isNull player}; _rnd = str random diag_tickTime; uiNamespace setVariable ["_rnd", _rnd]; missionNamespace setVariable ["#PV_FL", [netId player, _rnd]]; publicVariableServer "#PV_FL"; }; };

Second example is for check_player extension. I have plans to use it with another extension I’m making, so I made a simple example that would just log people connecting and disconnecting into debug_console ran on the server. For normal player it would look like this:


For a player with Steam bans it would look something like this:


Could be used by server admins with remote desktop connection to monitor joining players. The code also goes into init.sqf:

onPlayerConnected { if (_uid == "") exitWith {}; "debug_console" callExtension format [ "Player %1 connected #1111", _name ]; 0 = [_name, _uid] spawn { _name = _this select 0; _uid = _this select 1; _check = { { _cond = _x select 1 != "0" && _x select 1 != "none"; if (_cond) then { "debug_console" callExtension format [ "Player %1 (%2) has Steam bans: %3 > %4 #1100", _name, _uid, _x select 0, _x select 1 ]; }; _cond } count _this; }; "check_player" callExtension _uid; _time = time + 10; private "_bans"; waitUntil { _bans = "check_player" callExtension _uid; _bans != "WAIT" || {_bans = "[]"; time > _time} }; if (_bans == "[]") then { "debug_console" callExtension format [ "Player check failed for %1 (%2) #1001", _name, _uid ]; } else { if ((call compile _bans) call _check == 0) then { "debug_console" callExtension format [ "Player %1 - OK #0100", _name ]; }; }; }; }; onPlayerDisconnected { "debug_console" callExtension format [ "Player %1 disconnected #0001", _name ]; };