Jump to content
FoxClubNiner

JIP Woes Regarding Unit Loadouts

Recommended Posts

This one is a little tricky to explain. Right now I have it all working minus this JIP issue. Let me explain.

 

What I want:

1. Players can equip scuba gear via addAction. (working as intended)

2. If scuba gear is equipped they can restore their loadout via addAction. (working as intended)

3. If a player leaves (game crashes) and returns I want them to be able to pick up where they left off. Meaning if they had scuba gear on when they left then when they return the addAction should be to let them equip their loadout (not working as intended)

The problem:
3. If a player leaves (game crashes) and returns while they had scuba gear on, when they return they are still wearing scuba which seems normal. However, the addAction available is "Equip SCUBA", which doesn't make sense because they already have scuba. I need the returning player to have "Equip Loadout".
 

initPlayerLocal:

scubaEquipped = false; // This makes sure the first addAction is "Equip SCUBA Gear"

The addActions within a sqf:

ptboat addAction ["<t color='#FFFF00'>Equip SCUBA Gear</t>", "scripts\scubagear.sqf", nil, 7, false, true, "", "_this in (crew _target) && !scubaEquipped"]; //Shows up if you are in the boat and have your regular loadout
ptboat addAction ["<t color='#FFFF00'>Equip Loadout Gear</t>", "scripts\loadoutgear.sqf", nil, 7, false, true, "", "_this in (crew _target) && scubaEquipped"]; //Shows up if you are in the boat and have your SCUBA

scubagear.sqf

playerLoadout = getUnitLoadout player; //saves the loadout before equipping scuba gear so it can we recalled with equip loadout action
//a bunch of items removed then scuba gear added to inventory.
scubaEquipped = true; //removes the "Equip SCUBA gear" addaction and replaces it with "Equip Loadout Gear"

loadoutgear.sqf

player setUnitLoadout playerLoadout; //recalls the loadout that was saved in scubagear.sqf
scubaEquipped = false; //removes "Equip SCUBA gear" addaction and replaces it with with "Equip SCUBA Gear"

It's really hard to explain. I might make a video. But basically if I player leaves and rejoins his "progess" isn't saved. progress meaning which addaction state should be shown for him. Now that I think about it more. Maybe I need a way to save the client state if they crash and then call it when they return. I'm not sure if that's possible

.

Share this post


Link to post
Share on other sites

Edit: After sleeping on it and reading your post again I realize you may not have loadout-restoration in place. If so Solution 1 won't work!

I've added solutions for a client-side and a server-side variant. These are all mutually exclusive with each other.

 

Solution 1: (Original post)

On 6/29/2024 at 7:10 PM, FoxClubNiner said:

scubaEquipped = false;

 

Vanilla diving gear is placed in the goggles slot ( the stuff that makes you able to see and breathe under water anyway ). So as long as the your equipment uses the same technique you can check what the player has equipped to figure out which state the variable should be in.

 

Here's a version pf your initPlayerLocal.sqf that supports multiple types of diving gear, you just have to fill the _goggles with the correct classnames.

private _goggles = ["G_Diving"];
private _equipped = goggles player;
private _index = _goggles findIf { _x ==_equipped };
scubaEquipped = _index >= 0;

If you use a mod that defines diving gear differently you might need to use a different command to get the value for _equipped.


Solution 2: Client-side saving

initPlayerLocal.sqf

Spoiler

//initPlayerLocal.sqf
if( not didJIP ) then {
	// If player joined at mission start just set value to false
	scubaEquipped = false; 
	// and reset missionProfileNamespace
	missionProfileNamespace setVariable [ "playerLoadout", nil ];
	missionProfileNamespace setVariable [ "scubaEquipped", nil ];
	saveMissionProfileNamespace;
} else {
	// Is a JIP client	
	playerLoadout = missionProfileNamespace getVariable [ "playerLoadout", [] ];
	scubaEquipped = missionProfileNamespace getVariable [ "scubaEquipped", false ];

	private _validLoadout = !( playerLoadout isEqualTo [] );
	// Only apply scuba gear if this wouldn't break the scuba-actions
	switch (true) do {
		case ( scubaEquipped and _validLoadout ): {
			// Loadout is valid and scuba gear is equipped, nothing to do.
		};
		case ( not scubaEquipped ): {
			// Apply the stored loadout, if any
			if( _validLoadout ) then {
				player setUnitLoadout playerLoadout;
			};
		};
		default {
			// If we get here something has gone wrong, loadout is invalid but we have should be in scuba wearing state.			
			diag_log text "Error reading player loadout, data dump follows.";
			diag_log text format ["playerLoadout = %1", playerLoadout];
			diag_log text format ["scubaEquipped = %1", scubaEquipped];
			diag_log text "Mission Profile Namespace variables:";
			private _variables = ["playerLoadout", "scubaEquipped"];
			{
				diag_log text format ["Var: %1", _x];
				diag_log text format ["Val: %1", missionProfileNamespace getVariable _x ];
			} forEach _variables;
			
			// Fall back to non-scuba mode
			scubaEquipped = false;

			// Let the player know
			[] spawn { sleep 3; systemChat "There was an error reading your loadout, relevant data dumped to log." };
		};
	};
};

// Add eventhandler to reset variables at end of mission.
addMissionEventHandler [
	"Ended",
	{
		missionProfileNamespace setVariable [ "playerLoadout", nil ];
		missionProfileNamespace setVariable [ "scubaEquipped", nil ];
		saveMissionProfileNamespace;
	}
];

 

 

scubagear.sqf

Spoiler

//scubagear.sqf
playerLoadout = getUnitLoadout player; //saves the loadout before equipping scuba gear so it can we recalled with equip loadout action
//a bunch of items removed then scuba gear added to inventory.
scubaEquipped = true; //removes the "Equip SCUBA gear" addaction and replaces it with "Equip Loadout Gear"

// Since the state has changed store the new state in profile
missionProfileNamespace setVariable [ "playerLoadout", playerLoadout ];
missionProfileNamespace setVariable [ "scubaEquipped", true ];
saveMissionProfileNamespace;

 

 

loadoutgear.sqf

Spoiler

player setUnitLoadout playerLoadout; //recalls the loadout that was saved in scubagear.sqf
scubaEquipped = false; //removes "Equip SCUBA gear" addaction and replaces it with with "Equip SCUBA Gear"

// Since the state has changed store the new state in profile
missionProfileNamespace setVariable [ "scubaEquipped", false ];
saveMissionProfileNamespace;

 

 

Solution 3: Server-side

The drawback with doing it client-side is saving cannot be reactive that if a player leaves before the mission ends and rejoins as JIP after the mission has ended and been restarted, there's no way to for the client alone to tell the difference between the sessions.

 

On 6/29/2024 at 7:10 PM, FoxClubNiner said:

Now that I think about it more. Maybe I need a way to save the client state if they crash and then call it when they return. I'm not sure if that's possible

As Mando would say; This is the way.

 

... more coming soon ...

  • Like 2

Share this post


Link to post
Share on other sites

Yep. Here is another way. I'm using just 1 addAction (with different menus), and I prefer a code rather than 2 sqf. I add also a team switch option (in case of use for the team switch menu).

in initPlayerLocal.sqf:


 

sleep 1;  // important as far as the loadout of a player may be not instantaneous!

private _isScuba = getText (configfile / "CfgWeapons" / vest player / "ItemInfo" / "vestType") == "Rebreather";
private _actionMenu = ["<t color='#FFFF00'>Equip SCUBA Gear</t>","<t color='#FFFF00'>Equip Loadout Gear</t>"] select _isScuba;

// make a loadout for diving:
player setVariable ["scubaDiver",[
  ["arifle_SDAR_F","","","",["20Rnd_556x45_UW_mag",20],[],""],
  [],
  ["hgun_P07_snds_F","muzzle_snds_L","","",["16Rnd_9x21_Mag",16],[],""],
  ["U_B_Wetsuit",[["FirstAidKit",1],["30Rnd_556x45_Stanag_red",3,30],["20Rnd_556x45_UW_mag",2,20],["16Rnd_9x21_Mag",2,16],["SmokeShellBlue",2,1],["Chemlight_blue",4,1]]],
  ["V_RebreatherB",[]],
  ["B_AssaultPack_blk_DiverExp",[["ToolKit",1],["MineDetector",1],["DemoCharge_Remote_Mag",3,1]]],
  "",
  "G_B_Diving",
  [],
  ["ItemMap","","ItemRadio","ItemCompass","ItemWatch",""]
  ]
];


// core of the code in action
private _actionCode = {
        params ["_tgt","_caller","_id"];
        private _actMenu = (_tgt actionParams _id) select 0;
        systemChat _actMenu;
        if (_actMenu isEqualTo "<t color='#FFFF00'>Equip SCUBA Gear</t>") then {
            _actMenu = "<t color='#FFFF00'>Equip Loadout Gear</t>";
            _caller setVariable ["savedLoadout",getUnitLoadout _caller,TRUE];
            _caller setUnitLoadout (_caller getVariable ["scubaDiver",getUnitLoadout _caller]);
            comment "<other stuff here>";
        } else {
            _actMenu = "<t color='#FFFF00'>Equip SCUBA Gear</t>";
            _caller setUnitLoadout (_caller getVariable ["savedLoadout",getUnitLoadout _caller]);
            comment "<other stuff here>";
        };
        _tgt setUserActionText [_id,_actMenu];
    };


// add action:
ptboat addAction [_actionMenu, _actionCode,nil,7,false,true,"","_this in (crew _target)"];


// optional, in case of team switching possibility:

addMissionEventHandler ["TeamSwitch", {
    params ["_previousUnit", "_newUnit"];
    if (!isNull ptboat) then {
        private _isScuba = getText (configfile / "CfgWeapons" / vest _newUnit / "ItemInfo" / "vestType") == "Rebreather";
        private _actionMenu = ["<t color='#FFFF00'>Equip SCUBA Gear</t>","<t color='#FFFF00'>Equip Loadout Gear</t>"] select _isScuba;
        ptboat setUserActionText [actionIDs ptboat findif {"Equip" in ((ptboat actionParams _x)#0)},_actionMenu];
    };
}];

 

Note: The initial loadout is saved in a (public) variable on the unit of the player. It seems to me a way for recovering the loadout (saved when action was triggered), even after a crash.

  • Like 1

Share this post


Link to post
Share on other sites

Wow! First off, thank you both very much for the help! These look like possible solutions. However most if not all of what you wrote in the scripts has gone over my head. Its just simply beyond my skill level. I do appreaciate the notes though. As I re-read them I'm trying to parse out what they do. Still, I always try to implement any given help. I will trying copy and pasting your code in a few different ways to see if I get some success and report back either way!

Share this post


Link to post
Share on other sites

Thank you for the help Mr. Curry! I tested your code. After I load in and go to "Equip SCUBA Gear" I get an error message directing me to line 2 in equipscuba.sqf. The error states that there is a missing ;. I double checked line 2 and there is a semicolon there. Can you look it over and see if there is a mistake please? Also I am posting a Youtube Video that showcases the problem I was trying to describe in my original post. I am using Pierre's code for this test but it has the same problem as mine so it's a good example.

Thank you for the help Pierre! Here is a video where I test your code, it has the same problem as the code in my original post.

 

 

Share this post


Link to post
Share on other sites
30 minutes ago, FoxClubNiner said:

*video*

 

You hit the nail about the game not knowing about your previous loadout when you reconnect, and it hints at the core problem MP code has to solve: state syncing 🙂

 

42 minutes ago, FoxClubNiner said:

Thank you for the help Mr. Curry! I tested your code. After I load in and go to "Equip SCUBA Gear" I get an error message directing me to line 2 in equipscuba.sqf. The error states that there is a missing ;. I double checked line 2 and there is a semicolon there. Can you look it over and see if there is a mistake please?

 

I double-checked what I posted and it seems syntacticly correct, also line 2 in scubagear.sqf is unchanged from the OP. My guess is some sort of invisible formatting characters snuck in with the copy to/from the forums. I've seen it before when I combine code and spoilers like that.

 

A quickfix can be to check for hidden characters using a competent code editor like notepad++ or vscode. The hidden usually look like weird symbols or question marks.

Or just brute force it by rewriting the offending line (including comments) manually.

 

I'll upload a clean copy "soon", hopefully together with a working server-side version.

 

Share this post


Link to post
Share on other sites
13 hours ago, FoxClubNiner said:

Thank you for the help Pierre! Here is a video where I test your code, it has the same problem as the code in my original post.

 

Hello. In your video, when reconnected, you are neither with former gear nor scuba gear.

If you were in full scuba gear, you should have a rebreather (vest) and the action menu ready for former gear. With former gear, a uniform should be visible.

Here, you have a weapon (diver) but neither uniform nor vest.


I can reproduce that in my own dedicated server, with 2 players (Vanilla, but I guess it's not important)
So it seems there is a lack of sync in this case. You can check for my (public) variable still OK in debug console (if allowed) : player getVariable "savedLoadout"  , after reconnexion of course.

Did you place the code in initPlayerLocal.sqf ?
And important did you let the sleep  command at the begin of the code? It seems to me important. Add more seconds for further check.

No clue about what happens in your case. The incomplete loadout (you have a SDAR as weapon) is not easy to understand.
 

Share this post


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

 

Hello. In your video, when reconnected, you are neither with former gear nor scuba gear.

If you were in full scuba gear, you should have a rebreather (vest) and the action menu ready for former gear. With former gear, a uniform should be visible.

Here, you have a weapon (diver) but neither uniform nor vest.


I can reproduce that in my own dedicated server, with 2 players (Vanilla, but I guess it's not important)
So it seems there is a lack of sync in this case. You can check for my (public) variable still OK in debug console (if allowed) : player getVariable "savedLoadout"  , after reconnexion of course.

Did you place the code in initPlayerLocal.sqf ?
And important did you let the sleep  command at the begin of the code? It seems to me important. Add more seconds for further check.

No clue about what happens in your case. The incomplete loadout (you have a SDAR as weapon) is not easy to understand.
 


Yes I placed it where you said and it was a copy/paste job so it is as you have written it.

Regarding the SCUBA after a certain time period on land it gets thrown in the backpack and you have shorts on if I remember correctly.

 

Share this post


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

 

Hello. In your video, when reconnected, you are neither with former gear nor scuba gear.

If you were in full scuba gear, you should have a rebreather (vest) and the action menu ready for former gear. With former gear, a uniform should be visible.

Here, you have a weapon (diver) but neither uniform nor vest.


I can reproduce that in my own dedicated server, with 2 players (Vanilla, but I guess it's not important)
So it seems there is a lack of sync in this case. You can check for my (public) variable still OK in debug console (if allowed) : player getVariable "savedLoadout"  , after reconnexion of course.

Did you place the code in initPlayerLocal.sqf ?
And important did you let the sleep  command at the begin of the code? It seems to me important. Add more seconds for further check.

No clue about what happens in your case. The incomplete loadout (you have a SDAR as weapon) is not easy to understand.
 

 

After a solid 2,5 hours of testing I'm pretty sure this is a very niche bug with setUnitLoadout that we've stumbled across...

From my tests it only happens under these circumstances:

  1. The player is in a vehicle
  2. setUnitLoadout is applied to the player
  3. The player disconnects before leaving the vehicle, switching seats does not avoid the issue.
  4. The server and mission is configured so AI takes over the player unit (disabledAI = 0;)

The symptom seems to always to be that the uniform and vest disappears. It'd be interesting to see what other players see... when exactly does the uniform and vest actually disappear?

I've disabled everything else custom in the mission, including your script Pierre and it still happens.

 

So yeah I wouldn't bet my life on it but it looks like super niche issue that just happens to line up perfectly with your script Pierre and @FoxClubNiner's requirements... Well done! 😄

 

It should be posted to the bug tracker if it isn't already... but I wouldn't hold my breath for a fix anytime soon.

Share this post


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

 

After a solid 2,5 hours of testing I'm pretty sure this is a very niche bug with setUnitLoadout that we've stumbled across...

From my tests it only happens under these circumstances:

  1. The player is in a vehicle
  2. setUnitLoadout is applied to the player
  3. The player disconnects before leaving the vehicle, switching seats does not avoid the issue.
  4. The server and mission is configured so AI takes over the player unit (disabledAI = 0;)

The symptom seems to always to be that the uniform and vest disappears. It'd be interesting to see what other players see... when exactly does the uniform and vest actually disappear?

I've disabled everything else custom in the mission, including your script Pierre and it still happens.

 

So yeah I wouldn't bet my life on it but it looks like super niche issue that just happens to line up perfectly with your script Pierre and @FoxClubNiner's requirements... Well done! 😄

 

It should be posted to the bug tracker if it isn't already... but I wouldn't hold my breath for a fix anytime soon.


Incredible if true! I havent retried your script yet. I just got done taking 5 hours to get a freaking helicopter to land. I need a break lol. But I should be able to retry it tomorrow!

Share this post


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

 

After a solid 2,5 hours of testing I'm pretty sure this is a very niche bug with setUnitLoadout that we've stumbled across...

From my tests it only happens under these circumstances:

  1. The player is in a vehicle
  2. setUnitLoadout is applied to the player
  3. The player disconnects before leaving the vehicle, switching seats does not avoid the issue.
  4. The server and mission is configured so AI takes over the player unit (disabledAI = 0;)

The symptom seems to always to be that the uniform and vest disappears. It'd be interesting to see what other players see... when exactly does the uniform and vest actually disappear?

I've disabled everything else custom in the mission, including your script Pierre and it still happens.

 

So yeah I wouldn't bet my life on it but it looks like super niche issue that just happens to line up perfectly with your script Pierre and @FoxClubNiner's requirements... Well done! 😄

 

It should be posted to the bug tracker if it isn't already... but I wouldn't hold my breath for a fix anytime soon.

 

OK, I got it! I never disconnected/back to lobby, staying in a vehicle. On reconnection/back in game the uniform and vest are missing.

It seems there are some feedbacks in tracker for setUnitLoadout with server:
https://feedback.bistudio.com/search/query/zMIm7Cjamb64/#R

 

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

×