Jump to content
Sign in to follow this  
Freghar

Something is adding standard backpack after init EH

Recommended Posts

Hello,

I use a simple loadout modification logic performed on any unit (editor-placed or spawned mid-mission) using the init EventHandler. When I however

removeBackpack _this;
_this addBackpack "I_UAV_01_backpack_F";
(or any backpack for that matter) from init EH, I find this backpack on the ground below the unit when the game starts, with the unit wearing the default backpack.

This can be likely attributed to something calling addBackpack after my init EH,

Adds a backpack for a unit. If a unit already has a backpack, the old backpack will be placed on the ground under the unit.

but as this is reproducible even on vanilla game with a very simple mission, I can't think of what that would be. Happens in SP (editor preview) as well.

Obviously, can be reproduced only with units which have backpack by default, ie. B_soldier_AAR_F.

Doing the code above in a scheduled environment works, but is obviously bad as it breaks MP setups - the init EH seems to run on the server and if I was to defer the loadout modification using spawn, the unit could change locality to its player client mid-execution.

I use CBA's "init" EH, but this seems to be reproducible with Mod-based config.cpp init EH as well, without any other mods.

Any ideas, please?

Share this post


Link to post
Share on other sites

If you spawn a soldier mid game has the same problem?

Share this post


Link to post
Share on other sites

If you spawn a soldier mid game has the same problem?

Good idea - no, it happens only on mission init, createVehicle / Curator-spawned load correctly my backpack with nothing on the ground.

Share this post


Link to post
Share on other sites

Then I bet whats happening is the EH init is executing before the unit is already "loaded" in the map. With editor placed just do any modifications in traditional init box and problem solved.

Share this post


Link to post
Share on other sites

Yes, that's the whole point - execute the EH before the simulation (mission) starts, so there's no additional ingame overhead. Doing any extra work via init lines is also exactly something I wanted to avoid as it would be very tedious for >100 units and multiple missions.

My current workaround is to

  • defer loading for time == 0 to a postInit function - doesn't work for JIP
  • save loadout via setVariable onto the unit after I changed it
  • hook the Local EH (as the last place on the server) and restore the loadout there, assuming Local EHs get to run before the actual transfer
  • spawn waitUntil in case the unit isn't transferred away, restoring the loadout "some time" after (possibly when time > 0), or iterating over all units in a postInit function, looking for saved loadouts, restoring them
This is kind of very ugly to do, but is the only reliable way I can think of (no race conditions).

Would be really great to find what's causing it though, it's not anything in functions_f*.pbo, so is it an engine thing? Maybe backpack loading was accidentally added after init EH, contrary to other gear?

Share this post


Link to post
Share on other sites

Simple reproducer (for anyone interested); create a mod with

class CfgPatches
{
	class TEST_init_eh
	{
		units[] = {};
		weapons[] = {};
		requiredAddons[] = {"A3_Modules_F"};
	};
};

class CfgVehicles
{
	class B_Soldier_base_F;
	class B_Soldier_AAR_F: B_Soldier_base_F
	{
		class EventHandlers
		{
			init = "_this = _this select 0; systemchat str _this; removeBackpack _this; _this addBackpack ""I_UAV_01_backpack_F""";
		};
	};
};
and start the game with it, go into editor, place down Assist. Autorifleman, hit preview. You should see the added UAV backpack on the ground, with default backpack on the back.

Modifications of the rest of the loadout work fine, it's just the backpack. :(

Share this post


Link to post
Share on other sites

Just so you know; your inheritance is wrong and might break stuff.

 

It should be:

class B_Soldier_support_base_F;
class B_soldier_AAR_F : B_Soldier_support_base_F {
    // stuff
};

Share this post


Link to post
Share on other sites

Just so you know; your inheritance is wrong and might break stuff.

 

It should be:

class B_Soldier_support_base_F;
class B_soldier_AAR_F : B_Soldier_support_base_F {
    // stuff
};
Sure, thanks, as mentioned - I use CBA_fnc_addClassEventHandler in the real code, this was just a quick-n-dirty reproducer.

Share this post


Link to post
Share on other sites

Thinking about it a bit more - there's actually no clean (sleep-less) workaround possible if one wants to support join-in-progress.

Because even if the EH is added in postInit and the logic is called separately for allUnits, after all units are on their respective clients, the original problem persists for JIP; init EH still fires on the server, followed by (few ms) transfer to the client.

This could potentially be caught be the Local EH, but not really as both init EH and local EH can be (and are) used independently:

  • init EH can trigger for units that won't be transferred and there's no defined point in time of a running game where we could detect it, we would have to blindly sleep
  • local EH can fire for a simple headless client locality change mid-mission, no units created
  • if we set some state variable in init EH and expect it in local EH (or register local EH from init EH), it can trigger false positives - AI unit spawned on the server, moved to a headless client few minutes after
And since there's no "unit spawned for a JIPed player" flag passed to init EH, it cannot possibly know what the unit is used for. Similarly for local EH.

Even if we would use the arguments passed to local EH and check if the client JIPed, it has no indication of whether the client just entered the game - the local EH might have fired minutes after a headless (or any other) client JIPed into the game.

Fixing the backpack on the engine / BIS side is the only solution I can think of.

Share this post


Link to post
Share on other sites

Why is sleep "unclean"?

 

I can't see a practical reason for not using it given what you are trying to do.

 

In your example, you are doing things counter to the order of initialisation, so you receive the results you get.

 

You can "fix" this by configging the unit to have the backpack in the first place.  There is no sense in using a config eventhandler to work around something that you could do by changing the backpack in the config.

 

class B_soldier_AAR_F : B_Soldier_support_base_F {
            backpack = "I_UAV_01_backpack_F";
};
 
Works as expected.
  • Like 2

Share this post


Link to post
Share on other sites

Why is sleep "unclean"?

Because I would need to to pick an arbitrary number and state "I think that this should be enough", it may work most of the time, but is not a reliable way of doing things. Essentially it's a band-aid on race conditions.

(Exceptions exist, to cases that are outside one's control, like waiting ~2 seconds for BIS_fnc_showNotification.)

 

I can't see a practical reason for not using it given what you are trying to do.

It wouldn't really help much in my case anyway - for playable units, the init EH still triggers on a different client than the script would need to run, even if I put sleeps everywhere.

The "useful sleeps" would be just deciding how long can there potentially be between an init EH and a Local EH before the script considers the the unit being spawned ingame (and not as a result of a JIP player) and restore my backpack.

 

In your example, you are doing things counter to the order of initialisation, so you receive the results you get.

 

You can "fix" this by configging the unit to have the backpack in the first place.  There is no sense in using a config eventhandler to work around something that you could do by changing the backpack in the config.

 

 

class B_soldier_AAR_F : B_Soldier_support_base_F {
            backpack = "I_UAV_01_backpack_F";
};
 

Works as expected.

As mentioned, I'm using CBA_fnc_addClassEventHandler because this all is a mission (framework), not a mod, unfortunately, and there's currently no way of doing this in vanilla game (no EntityInit mission EH, in contrast to existing EntityRespawned / EntityKilled).

(The full thing is at https://github.com/CntoDev/template/tree/0964053642d/features/Custom_Factions, essentially a system to define loadouts for unit classes, enabling one to define player and AI loadouts, per-mission. The backpack config bit was a simplified example as this "bug" happens only with backpacks.)

Share this post


Link to post
Share on other sites

You should really add CBA to the title of the thread to make it more clear. I wouldn't attempt to suggest a solution for you because you use 3rd party addon that can actually screw things up. Everything works as expected if your code is added to unit init in editor.

Share this post


Link to post
Share on other sites

Because I would need to to pick an arbitrary number and state "I think that this should be enough", it may work most of the time, but is not a reliable way of doing things. Essentially it's a band-aid on race conditions.

 

 

I can't see a problem with a waitUntil and check some conditions rather than arbitrary "sleep 3" or somesuch.

 

TBH in the case of playable units, I'd do the loadout stuff in initPlayer/initPlayerServer or similar and then you know it's been selected and a player is that unit.

 

I've not used CBA much but something like this should be ok for MP (untested):

 
fnc_bp = {
    if (isServer) then {
        (_this select 0) spawn {
            waitUntil {
                time > 0
            };
            systemchat str _this;
            removeBackpack _this;
            _this addBackpackGlobal "I_UAV_01_backpack_F"
        };
    };
};


["B_Soldier_AAR_F","init",fnc_bp] call CBA_fnc_addClassEventHandler; 

Share this post


Link to post
Share on other sites

You should really add CBA to the title of the thread to make it more clear. I wouldn't attempt to suggest a solution for you because you use 3rd party addon that can actually screw things up. Everything works as expected if your code is added to unit init in editor.

But the point wasn't in the actual full complete code or how I use it, the point behind this thread was that there's an inconsistency between backpacks and the rest of the unit gear w.r.t. init EH and this can be reproduced using a vanilla game. The /fix/ would be to either modify the loadout (engine-side) before or after the init EH, not split across it in this way.

Share this post


Link to post
Share on other sites

I can't see a problem with a waitUntil and check some conditions rather than arbitrary "sleep 3" or somesuch.

 

TBH in the case of playable units, I'd do the loadout stuff in initPlayer/initPlayerServer or similar and then you know it's been selected and a player is that unit.

 

I've not used CBA much but something like this should be ok for MP (untested):

 

 

fnc_bp = {
    if (isServer) then {
        (_this select 0) spawn {
            waitUntil {
                time > 0
            };
            systemchat str _this;
            removeBackpack _this;
            _this addBackpackGlobal "I_UAV_01_backpack_F"
        };
    };
};


["B_Soldier_AAR_F","init",fnc_bp] call CBA_fnc_addClassEventHandler; 
Thanks for the effort, but that unfortunately has the same problem I mentioned before - when a player joins in progress, the code (removeBackpack + addBackpackGlobal or whatever other code) races with the locality change of the new unit (if a new unit was spawned for the joining player).

This wouldn't be an issue if all the commands used were AG+EG (as they would just continue running, regardless of locality), but commands like addPrimaryWeaponItem (and others I need to run with the backpack code) don't have an AG variant. So the script needs to run completely on either the server or the JIP'ed client. This conflicts with the "spawn" as spawned script can run alongside the server->client unit transfer and the locality can change in the middle of the script.

That's where unscheduled environment comes in as I can just load the loadout (incl. backpacks) fully in the init EH on the server and the unit won't be transferred until all the code has run. This works perfectly in theory, .. except for this backpack "bug" as something is trying to add a backpack after I'm done with the loadout from the init EH (unscheduled).

Share this post


Link to post
Share on other sites

I get you now - as KK mentioned, you should probably have explained all that earlier as it's taken a while to get to root of your issue.

 

Have you actually tried doing it like above and using remoteExec for the AL/EG commands to cover locality issues?

 

As mentioned, I've had no problems with doing it all playerside / or serverside with remoteExec etc.  You should maybe check out a different approach (or make a bug report and hope it's addressed quickly).  I would go for different approach personally as bug fixing can take 2 days or 2 months (or more - who knows?)   ;)

Share this post


Link to post
Share on other sites

Well, a simple test reveals that at the time of config init EH execution, unit doesn't have a backpack. So you are adding custom backpack before engine adds stock backpack, so this is why yours gets removed. And since you cannot add backpack this way in vanilla game without modding it, this problem IS directly CBA related. If you do however mod vanilla yourself, then you don't need to mess with init at all.

Share this post


Link to post
Share on other sites

I get you now - as KK mentioned, you should probably have explained all that earlier as it's taken a while to get to root of your issue.

 

Have you actually tried doing it like above and using remoteExec for the AL/EG commands to cover locality issues?

 

As mentioned, I've had no problems with doing it all playerside / or serverside with remoteExec etc.  You should maybe check out a different approach (or make a bug report and hope it's addressed quickly).  I would go for different approach personally as bug fixing can take 2 days or 2 months (or more - who knows?)   ;)

Probably - I always try to distill the issue itself to what's important, so that people don't have to go reading thousands of code lines to understand the big picture, though sometimes this oversimplified example gets misunderstood as my actual use case. :(

Using remoteExec would indeed work, it's just that doing locality check or remoteExec of each individual command is kind of annoying when the idea was to use essentially exported arsenal loadouts. I might just go with the spawn approach and specify that it's dangerous for playableUnits, but still generally useful for the rest (ie. AI units).

I've spent about quite a few weeks on this particular part so yes, I've tried many different approaches and this one seemed nicely non-intrusive, efficient and usable at time == 0. Well, until I found this.

I'm used to solving hard programming problems, it's just that usually I can see the source and send patches back, except ... well, I obviously can't do that with the Arma engine.

Anyway, thanks for the help.

 

Well, a simple test reveals that at the time of config init EH execution, unit doesn't have a backpack. So you are adding custom backpack before engine adds stock backpack, so this is why yours gets removed. And since you cannot add backpack this way in vanilla game without modding it, this problem IS directly CBA related. If you do however mod vanilla yourself, then you don't need to mess with init at all.

Yes, I know it makes sense if you oversimplify it like that. Please let me use an analogy to better explain;

Imagine that the NT kernel (Windows) crashes when it receives any multimedia key press. Let's say Windows refuses the fix the issue, because a "keyboard" is something out of its scope as an OS and it works fine with all the standard 1990s keyboards they have. However XYZ media player developers really want users to be able to use multimedia keys found on some keyboards, yet they get a reply that that's something not possible with stock Windows and if they really need it, they should mod the NT kernel.

All this discussion however hides the real fact that multimedia keys are really just regular keycodes and there's no reason for the kernel to crash on them, so there's actually a real bug (or "undocumented feature") that's being refuted because the original use case is outside the bounds of what Windows supports.

I realize it's impossible to support / add features for whatever crazy schemes others come up with, but am I wrong for viewing Arma as a "library" to base development on? Shouldn't this library be then consistent with its workings or at least document the weird cases which cannot be easily fixed, even if the workings are mainly used by foreign content?

You can either load the loadout before the init EH (great for me) or after the init EH (destroying my use case), I'd be fine with either as there was no guarantee of order to start with, but splitting gear load across the init EH really seems like an inconsistency worth fixing (if it can reasonably be done). Or declaring that it cannot be done because it's an ABI set in stone.

Share this post


Link to post
Share on other sites

..............

I don't see how your analogy is an analogy. Firstly, I personally don't think the delay in adding backpack by the engine is a bug. Perhaps there is a reason that init should run before it. I don't think this is something new, and if it isn't then changing the order of init now would probably be rejected due to backward compatibility. Secondly, there is always the wrong way of doing things in Arma and the right way. Maybe the way you chose it not the most optimal one?

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  

×