Jump to content
twistking

How to avoid "naked" players loadout bug in MP

Recommended Posts

Hello,
i am aware that loadouts not initiating properly is a common problem on big and complex servers, but since i started doing loadouts by script instead of using eden, it happens frequently on our server even on very small missions. I tried using the cba enforce loadouts option, but that does not stop it from happening, but makes it so that running the loadouts scripts from the console has no effect. Without the option i can at least manually load the loadouts for each player with the console.

I assume that my way of doing the laodouts in the first place is not ideal, since the problem occurs so frequrntly.

Here is how i do it:
On init field of playable unit:

this execVM "scripts\loadout_a.sqf";

and the script would look something like this:

params ["_unit"];

if (!local _unit) exitWith {};

removeAllWeapons _unit;
removeAllItems _unit;
removeAllAssignedItems _unit;
removeUniform _unit;
removeVest _unit;
removeBackpack _unit;
removeHeadgear _unit;
removeGoggles _unit;

_unit addWeapon "rhs_weap_ak74";
_unit addPrimaryWeaponItem "rhs_acc_dtk1983";
_unit addPrimaryWeaponItem "rhs_30Rnd_545x39_7N6M_AK";

_unit forceAddUniform "rhsgref_uniform_ttsko_mountain";
_unit addVest "rhs_6b5_sniper_khaki";

_unit addItemToUniform "FirstAidKit";
for "_i" from 1 to 2 do {_unit addItemToUniform "rhs_30Rnd_545x39_7N6M_AK";};
for "_i" from 1 to 4 do {_unit addItemToVest "rhs_30Rnd_545x39_7N6M_AK";};
for "_i" from 1 to 2 do {_unit addItemToVest "rhs_mag_rgd5";};
_unit addHeadgear "rhsgref_6b27m_ttsko_forest";

_unit linkItem "ItemMap";
_unit linkItem "ItemCompass";
_unit linkItem "ItemWatch";

***

Would there be a better way to do unit loadouts, that maybe works more reliably?

I thought of just doing a trigger a second after mission start, that would just fire and manually reload the loadout:

[p1] execVM "scripts\loadout_a.sqf";
[p2] execVM "scripts\loadout_b.sqf";
[p3] execVM "scripts\loadout_c.sqf";

but this will give an error if not all player slots are populated, since some playable objects referenced will not be existent in the mission.

 

***

What is best practice for doing loadouts from a script in a coop environment to avoid problems with laodouts not working.

Thanks a lot!

 

 

Share this post


Link to post
Share on other sites

If you start with the code (init.sqf), why don't you set all the loadout via editor ?

 

Share this post


Link to post
Share on other sites
19 minutes ago, pierremgi said:

If you start with the code (init.sqf), why don't you set all the loadout via editor ?

 

can you elaborate? i am not sure what you mean...

i do not want to use the eden editor loadout editor (right click on unit -> edit loadout), because that is very tedious to do if you have a bunch of units that need custom loadouts. way faster to do it with code, where you can quickly copy/paste segments. and quicker to make small edits.
 

i would have no issue with doing the loadout with code in the editor without calling external scripts, but i do not see why this would be different from calling a script from the same location:
is there a difference between doing object init: this do a versus in object init: this execvm "script_that_does_a.sqf"

Share this post


Link to post
Share on other sites

In editor, you can save/load custom loadouts, so you don't need to do a lot of work. You can select several units at the same time, apply a saved basic loadout, then apply saved custom loadouts on specific units...

Anyway, you can do exactly the same via script.

The fact is MP must be compliant with MP initialization order.

As you can see, the init fields are running soon, and before a player joins, on server,... then each time a player joins (running everywhere). At this time, your code exits with no-local unit. Good.

The good question is: is your player already on unit, so local or not? Probably. So, in best case, you are running again the code for applying the loadout, again.

 

Imho, the editor is same as:
if (isServer) then { apply loadout };  // there is not yet player, so no locality other than server, and the sync will occur on JIP. Nothing more.

 

Note: for a reason i don't know, addWeaponGlobal is broken on dedicated server (so multiple examples can fail, using it)

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
59 minutes ago, pierremgi said:

In editor, you can save/load custom loadouts, so you don't need to do a lot of work. You can select several units at the same time, apply a saved basic loadout, then apply saved custom loadouts on specific units...

Anyway, you can do exactly the same via script.

The fact is MP must be compliant with MP initialization order.

As you can see, the init fields are running soon, and before a player joins, on server,... then each time a player joins (running everywhere). At this time, your code exits with no-local unit. Good.

The good question is: is your player already on unit, so local or not? Probably. So, in best case, you are running again the code for applying the loadout, again.

 

Imho, the editor is same as:
if (isServer) then { apply loadout };  // there is not yet player, so no locality other than server, and the sync will occur on JIP. Nothing more.

 

Note: for a reason i don't know, addWeaponGlobal is broken on dedicated server (so multiple examples can fail, using it)


thanks a lot. i will definitely play around with the save/load function in eden. there is however another benefit of using code for laodout that i forgot. when running mods like rhs, you end up with hundreds (even thousands?) of items in the asset browser. i solved this with an excel document, where i have all the classnames organized, so finding what i need is actually way faster than using the editor UI.
therefore i will also do more testing with code-based loadouts.

 

two more questions:
when you say JIP, that would also include players that joined the mission before mission start, correct? so it would be technically JIP even the player joined before mission start, because the server init is done server only and when client actually takes control it does a "JIP" sync where information from earlier inits is done. Is this correct? So basically everytime a playable unit changes locality to a client is technically a JIP?!

 

"if (isServer) then { apply loadout };  // there is not yet player, so no locality other than server, and the sync will occur on JIP. Nothing more."
Isn't that the same as if (!local _unit) exitWith {}; with the only difference that "if isServer" will only run once at server init, while my variant will run once at server init (when unit is still local to server) and a second time when player takes control?

I think i do understand what you explained with the init order and locality, but i am still unsure what i can do witht hat knowledge to avoid the loadout failures. Running the script two times should only increase the chances of the loadout being loaded, no?

Share this post


Link to post
Share on other sites

... or in other words: i understand that i want to call the loadout a little bit later, since eden-init-fields are called so early that locality issues can arise.
however, if i call them at a point where locality should be settled, i will get errors for calling the loadouts for units that did not end up in the mission because of vacant slots.

if i want to emulate the eden loadout functionality with code, how would i set it up?
i remember that it used to work when i called the loadouts from init.sqf, but that would give the errors with vacant player slots... only because of that i tried calling the loadouts from the eden object init fields...

Share this post


Link to post
Share on other sites
53 minutes ago, twistking said:

... or in other words: i understand that i want to call the loadout a little bit later, since eden-init-fields are called so early that locality issues can arise.
however, if i call them at a point where locality should be settled, i will get errors for calling the loadouts for units that did not end up in the mission because of vacant slots.

if i want to emulate the eden loadout functionality with code, how would i set it up?
i remember that it used to work when i called the loadouts from init.sqf, but that would give the errors with vacant player slots... only because of that i tried calling the loadouts from the eden object init fields... 

If these loadouts are for player slots only, you want to run your script from init.sqf (or initPlayerLocal.sqf).

 

You need to make sure the code runs only for players and awaits until the player object is available. Simple example goes like this:

// init.sqf
if (hasInterface) then {
	waitUntil {
		!isNull player
	};
	[player] execVM "scripts\loadout_a.sqf";
}

Here's a battle-tested example with different loadouts for different unit types.

https://github.com/foley-dev/arma3-close-quarters/blob/master/init.sqf#L25

https://github.com/foley-dev/arma3-close-quarters/blob/master/scripts/player/loadout.sqf

 

I used setUnitLoadout here but your approach with addItem/removeItem is perfectly valid too.

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

only way i have found to solve this is to periodically check uniform on remote machine (for instance server). if unit is naked on remote machine then bounce code back to player to re-apply uniform.

 

have only had issues with uniform tho, not other gear

 

tl;dr server checks players periodically for ((uniform _x) isequalto "") and prompts that player to reapply their uniform

  • Thanks 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

×