Jump to content
Twiznak

addEventHandler "Fired", HideObjectGlobal, Not working on dedicated server

Recommended Posts

Hi everyone! This is a bit of a read, but I hope what I have to share is worth the read. I have come to the forums in search of help, but first I would like to share my success with everyone. I have put together an addEventHandler that turns all satchel charges into "tree cutters". I got this from PierreMGI in a 5 year old post on Armaholic forums https://www.armaholic.com/forums.php?m=posts&q=31114.  It forms one of the core logistics features in my Valhalla missions. It sets damage to maximum (1) on all trees and bushes within a 15m radius of the charge, when the charge is detonated. Works on dedicated servers.

 

Tree Cutter eventHandler. Add to initPlayerLocal.sqf && onPlayerRespawn.sqf:

 

player addEventHandler 
["fired", 
	{  
		if ("SatchelCharge_remote_ammo"== _this select 4) then 
		{  
			"Tree Cutter Charge Placed, Effective range 15m!" remoteExec ["hint"];
			_charge = _this select 6;
			0 = [_charge] spawn 
				{  
					_pad = createVehicle ["Land_HelipadEmpty_F", player, [], 0, "CAN_COLLIDE"];
					_charge = [_this, 0, objNull] call BIS_fnc_param;  
					waituntil {sleep 0.1; isNull _charge}; 
					{ _x setDamage 1 } foreach (nearestTerrainObjects [_pad,["tree","bush"],15]);
					deleteVehicle _pad;
				}
		}
	}
];

Never be at the mercy of vegetation again! 

 

Now my Problem. The above code works everywhere except Tanoa. Tanoa's trees: 1, Don't have a "ruin" model, or destroyed state that they can be put in. Even when damage set to maximum, they still stand. 2, they don't have a configure class. The dubug console command 

hint str(typeOf cursortarget); copyToClipboard str(typeOf cursortarget);

that I got from Haleks in the post 

always returns "". Which according to the description in typeOf means they don't have a config class. Making them nigh impossible for me to target by classname directly. So I went with a hideObjectGlobal approach that works on locally hosted games, but not on dedicated servers.

Tanoa Tree Hider eventHandler.

player addEventHandler 
["fired", 
	{  
		if ("SatchelCharge_remote_ammo"== _this select 4) then 
		{  
		"Tree Cutter Charge Placed, Effective range 15m!" remoteExec ["hint"];
		_charge = _this select 6;
		0 = [_charge] spawn 
			{  
				_pad = createVehicle ["Land_HelipadEmpty_F", player, [], 0, "CAN_COLLIDE"];
				_charge = [_this, 0, objNull] call BIS_fnc_param;  
				waituntil {sleep 0.1; isNull _charge}; 
				{ _x hideObjectGlobal true } foreach (nearestTerrainObjects [_pad,[],25,false]);
				deleteVehicle _pad;
			}
		}
	}
];

I am too wrapped up in my own conundrum to see the solution. Would someone please show me the corrections that need to be made in order for the Tanoa tree hider event handler to work on dedicated servers. Thank you for reading and I hope the these tree cutters help you dominate the battlefield!

Edited by Twiznak
I forgot to credit Pierre for his script. Sorry Pierre!

Share this post


Link to post
Share on other sites
29 minutes ago, Twiznak said:

call BIS_fnc_param

:face_palm:
hideObjectGlobal is server only execution you are executing it on client

  • Thanks 1

Share this post


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

:face_palm:
hideObjectGlobal is server only execution you are executing it on client

Hi Killzone_kid! Ahh yes, the face palm, my signature 😁. If I understand what you are getting at I should use remoteExec ?

 

this is what I have been able to work out. a partial success. It hides the objects, but it does so as soon as I place the charge.

player addEventHandler 
["fired", 
	{
		if ("SatchelCharge_remote_ammo"== _this select 4) then 
		{  
			"Tree Cutter Charge Placed, Effective range 15m!" remoteExec ["hint"];
			_charge = _this select 6;
			[_charge, { waitUntil {!isNull _this}; { _x hideObjectGlobal true } foreach (nearestTerrainObjects [_this,[],50]); }] remoteExec ["spawn", 0, true];
		}
	}
];

Then when I change,  !isNull to !alive, It hides the objects after detonation but does not work on the dedicated server. Please help me solve this. I keep hitting the same dead end with different approaches. I really appreciate your help. 

 

Edited by Twiznak
made a bit of progress

Share this post


Link to post
Share on other sites

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

 

jepSorK.png

 

Here we see that hideObjectGlobal "must be executed on the server to work properly in multiplayer." Using the correct remoteExec arguments will possibly achieve the desired result. As KK pointed out, executing it on any client is pointless. You also might want to set the JIP flag to "true" so your trees are "cut" for JIP players.

  • Thanks 1

Share this post


Link to post
Share on other sites

Sorry, I didn't see your post before.

Yes, you need to remoteExec on server only (so, 2) this kind of global command as mentioned in BIKI (SE). As you can see,  and read, "arguments don't have to be local" doesn't mean, sometimes, you can use them from anywhere. Here, BI added an extra condition for MP: on server only.

Same for all these commands.

Just a point : I'm no more on armaholic for a while, so 5 year old scripts are not updated. You can PM me if you want. Furthermore, I'd rather point at new command/function than bashing anyone for an old work.

 

player addEventHandler ["fired", { 
  if ("SatchelCharge_remote_ammo"== _this select 4) then {    
    "Tree Cutter Charge Placed, Effective range 25m!" remoteExec ["hint"]; 
      _charge = _this select 6; 
      _charge spawn { 
        private _pad = createVehicle ["Land_HelipadEmpty_F", _this, [], 0, "CAN_COLLIDE"]; 
        private _trees = nearestTerrainObjects [_pad,["Tree","Bush"],25];
        waitUntil {sleep 0.2; isNull _this};
        [_trees,{{_x hideObjectGlobal true} foreach _this}] remoteExec ["spawn",2]; 
        deleteVehicle _pad; 
      }; 
    }; 
 }];

 

CORRECTED: it's better to grab all trees in an array before remote execution. You can wipe a larger area.

Note: Never ever use a JIP param when you remoteExec on server only (i.e. something like remoteExec ["spawn",2,TRUE]) . The code will simply not work.

As written in the code above, the JIP player will see an updated situation (the command works for JIP).

 

  • Like 1
  • Thanks 1

Share this post


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

Sorry, I didn't see your post before.

Yes, you need to remoteExec on server only (so, 2) this kind of global command as mentioned in BIKI (SE). As you can see,  and read, "arguments don't have to be local" doesn't mean, sometimes, you can use them from anywhere. Here, BI added an extra condition for MP: on server only.

Same for all these commands.

Just a point : I'm no more on armaholic for a while, so 5 year old scripts are not updated. You can PM me if you want. Furthermore, I'd rather point at new command/function than bashing anyone for an old work.

 


player addEventHandler ["fired", { 
  if ("SatchelCharge_remote_ammo"== _this select 4) then {    
    "Tree Cutter Charge Placed, Effective range 25m!" remoteExec ["hint"]; 
      _charge = _this select 6; 
      _charge spawn { 
        private _pad = createVehicle ["Land_HelipadEmpty_F", _this, [], 0, "CAN_COLLIDE"]; 
        private _trees = nearestTerrainObjects [_pad,["Tree","Bush"],25];
        waitUntil {sleep 0.2; isNull _this};
        [_trees,{{_x hideObjectGlobal true} foreach _this}] remoteExec ["spawn",2]; 
        deleteVehicle _pad; 
      }; 
    }; 
 }];

 

CORRECTED: it's better to grab all trees in an array before remote execution. You can wipe a larger area.

Note: Never ever use a JIP param when you remoteExec on server only (i.e. something like remoteExec ["spawn",2,TRUE]) . The code will simply not work.

As written in the code above, the JIP player will see an updated situation (the command works for JIP).

 

Hello Sir! This is the solution. It comes as no surprise that the man who authored the original eventHandler, would be the man who authors the new. Thank you Killzone_Kid and Harzach! You, again, gave me reliable and accurate information that pointed me in the right direction. I will forever be in the shadow of you, the giants of Arma script. I stand upon your shoulders with every step I take in mission making. I am truly grateful for everything you and the rest of the giants do for all of us who come here to the forums seeking help.

 

  To reach a deeper level of understanding with the command spawn, I would like to ask some questions about its implementation here. First off, I just want to state that I would have NEVER figured this out on my own. Using a remoteExec "spawn", inside of another spawn, blows my mind. SO, I have two questions:

1.  Using multiples of spawn, inside a spawn. Allow me to rephrase, can I compile multiple sets of instructions, into one compiled set of instructions?

Hypothetical multiple spawn scenario:

_hints spawn {
_h1 = [] spawn {player globalChat "One for the money!"};
sleep 2;
_h2 = [] spawn {player globalChat "Two for the show!"};
sleep 2;
_h3 = [] spawn {player globalChat "Three to get ready. Now go, cat, go!"};
};

Is this valid syntax? How would one go about doing this correctly?

 

2. the variable "_this" is passed unto the code or script that is executed within the compiled set of instructions. If I were to call a script.sqf from the instructions, would I be able to operate with "_this", as it retained it's definition from the instructions that called it. OR would I need to create a private variable and then define that variable with  the variable, "_this",  that was passed to the script from the instructions?

Hypothetical variable passing from _handle spawn {0 = execVM "someScript.sqf";}; 

someScript.sqf

_myVar = (_this select 0);   //...

Is this valid syntax? How would one go about doing this correctly?

 

I feel like a crazy person. I barley make sense to myself. But yet still, I have to ask because I want to become better at mission scripting. Thank you for your time gentlemen!

Share this post


Link to post
Share on other sites

You can spawn or call or event execVM from a code... if you mind on the syntax.

On BIKI, you can read:

private _handle = _args execVM "someFile.sqf"; // is practically identical to private _handle = _args spawn compile preprocessFileLineNumbers "someFile.sqf";

The _handle is usually optional inside another code, but mandatory in 3den (init field of units for example, which is waiting for "nothing". The reason why you can read some 0 = [] spawn {...}   which works in 3den, as [] spawn {...} throws an error. It's an exception, coming from the ages of editor.

 

spawn is far more recommended for loops (or when you want to run the code several times), because you don't have to recompile the code like you do with execVM.

spawn opens a scheduled scope, and the code will run in parallel. The main limitation is that you share the time by a scheduler. So, some scripts could never run in very heavy context (no time during the 3ms slot and that can be repetitive!) On the other hand unscheduled code (called from unscheduled scope) don't have the limit from scheduler but can produce lags and little freezes.

 

Sometimes the handle is useful. I take your example:

_hints spawn {

_h1 = [] spawn {player globalChat "One for the money!"};

sleep 2;

_h2 = [] spawn {player globalChat "Two for the show!"};

sleep 2;

_h3 = [] spawn {player globalChat "Three to get ready. Now go, cat, go!"};

};

with such 2 sec. sleep, from a simple scenario, I guess everything seems clear (I don't know if _hints is defined somewhere but it's not the subject).

In reality, with heavier codes than globalChat, smaller sleep and in game context, you don't have the guarantee that these 3 codes will end in the right order!

They are running in parallel and that seems fine, but as said , in heavier context and codes, _h2 or _h3 can end before _h1.

The way to avoid such bad order (don't focus on globalChat but think about greater codes), is:

0 = [] spawn {

_h1 = [] spawn {player globalChat "One for the money!"};

waitUntil {sleep 2; scriptDone _h1};

_h2 = [] spawn {player globalChat "Two for the show!"};

waitUntil {sleep 2; scriptDone _h2};

_h3 = [] spawn {player globalChat "Three to get ready. Now go, cat, go!"};

};

NOTE: of course, if you call the codes instead of spawning them, there is no such problem (inside the same scope):

Spoiler

0 = [] spawn { // start of a scheduled scope (for sleep)
  call {player globalChat "One for the money!"};
  sleep 2;
  call {player globalChat "Two for the show!"};
  sleep 2;
  call {player globalChat "Three to get ready. Now go, cat, go!"};
};

The variable _this is said "magic variable", passing argument(s) from a scope to another scope. That can be [anArrayOfArgs] spawn { a code in which _this will be the arrayOfArgs. Usually you don't use _this, but params [definedElementsFromTheArgs,...];

This (non local, so non _underscored variable) is also a magic one, referring to the object in which you want to write a code (in its init field).

 

so:

 2 spawn {hint str _this}; // will hint: 2

[2] spawn {hint str _this}; // will hint: [2]

[2,3] spawn {hint str (_this select 1) };  // will hint:  3

You can test these codes in the init field of the player:

this addEventHandler ["FiredMan", {

  params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle"];

  hint str [_unit, _weapon,_projectile];

}];

and:

this addEventHandler ["FiredMan", {

  hint str [_this #0, _this #1,_this #6];

}];

 

 

  • Like 1

Share this post


Link to post
Share on other sites

Pierre, Thank you so much for sharing this knowledge with me. I got to work with this new information so quickly that I forgot to say thank you. So many mission possibilities have opened up , thank very much sir!

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

×