Jump to content
Robustcolor

RemoteExec and moveInDriver problem

Recommended Posts

Why won't this work _caller moveInDriver _veh in a dedicated enviroment.

 

I have an object that is placed in the editor and from the objects init i have this code.

this addAction [ "<t color ='#ffcc00'>Spawn Helicopter</t>", {[_this select 1] remoteExec["Helicopter",2];},[],1,true,true,"","_this distance _target <5"];}; 

 And this is the function

Helicopter =
{

params ["_caller"];

private _position = getMarkerPos "Helicopter";

private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"];

_veh setPos _position;

_caller moveInDriver _veh;

};

 

Share this post


Link to post
Share on other sites

Because _caller is not local.

 

No need to remoteExec. The action is executed on player’s machine already, but the Helicopter script is executed on server. And moving a player must be done by the player’s machine.

Share this post


Link to post
Share on other sites
8 hours ago, engima said:

Because _caller is not local.

 

No need to remoteExec. The action is executed on player’s machine already, but the Helicopter script is executed on server. And moving a player must be done by the player’s machine.

 

Thanks, How would the addAction look like? i added a "call" inside the addAction like below but it don't work on a dedicated server only.

this addAction ["<t color='#ffcc00'>Spawn Helicopter</t>",{[_this select 1] call Helicopter},[],1,true,true,"","_this distance _target <5"];
this addAction ["<t color ='#ffcc00'>Spawn Helicopter</t>",{Params ["_target","_caller"]; _caller call Helicopter}, [],1,true,true,"","_this distance _target <5"];}; 

 

One question also, if i don't use remoteexec and with a 2, is it still the server that creates the vehicle from a local addAction?

 

Share this post


Link to post
Share on other sites

Is the Helicopter script present on the client machine?

 

It will be the client creating the vehicle. Then if the control goes to the server I don’t know. However, as soon as the player enters it, its control will be transferred to the player anyway.

Share this post


Link to post
Share on other sites

You sure it is caller that has to be local and not vehicle?

EDIT: yes. Needs a note, vehicle could be remote, unit has to be local

 

  • Like 1

Share this post


Link to post
Share on other sites
On 9/24/2020 at 11:02 PM, engima said:

Is the Helicopter script present on the client machine?

I'm loading the function/s from initServer.sqf but it won't work when i need to fetch the _caller. So i made the helicopter function into one single sqf file instead and loaded it through cfgFunctions. Then addAction work when using _caller = _this select 1; inside the function.

this addAction ["<t color ='#ffcc00'>Spawn Helicopter</t>", My_fnc_Helicopter,[],1,true,true,"","_this distance _target <5"];    
private _caller = _this select 1;

private _position = getMarkerPos "Helicopter";

private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"];

_veh setPos _position;

_caller moveInDriver _veh;

Problem is, instead of having one sqf with all my functions i have to separate them into single sqf files.

Share this post


Link to post
Share on other sites

You can add a variable as parameter if you want a unique function in your cfgFunctions.

for example:

this addAction ["<t color ='#ffcc00'>Spawn Helicopter</t>", [_this #1, 0] call My_fnc_Helicopter,[],1,true,true,"","_this distance _target <5"];

 

and in your sqf

params ["_caller","_subFnc"];

call {

  if (_subFnc == 0) exitWith {

    private _position = getMarkerPos "Helicopter";

    private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"];

    _veh setPos _position;

    _caller moveInDriver _veh;

  };

  if (_subFnc == 1) exitwith {......};

};

 

  • Like 1

Share this post


Link to post
Share on other sites

Good idea @pierremgi.

 

Question, where is the best place to store/load several functions and open variables that are all inside one single sqf into the mission.

[] spawn {_this call compile preProcessFileLineNumbers "script.sqf"};

 

Is it by using a simple execVM or [] spawn {_this Call compileFinal preprocessFile "Functions\fn_functions.sqf"}; from example, initServer.sqf?

 

Or should i put them in cfgFunctions in Description.ext and use preInit to store them? That seems to make it easier to call/spawn them when need to use _caller with param etc.

class CfgFunctions
{
	class myTag
	{
		class myCategory
		{
			class functions {preInit = 1;};
		};
	};
};

Example of fn_functions.sqf

fn_functions.sqf;

Unitpatrol = ["B_Soldier_F","B_Soldier_SL_F"];

Ambushunits = ["B_Soldier_TL_F","B_medic_F"];

Examplepatrol = 
{
Params ["_pos"];
_grp01 = [_pos, west, [0,1] apply {selectRandom Unitpatrol},[],[],[1,1],[1,1],[]] call BIS_fnc_spawnGroup; 
};

Examplepatrol1 = 
{
Params ["_pos"];
_grp01 = [_pos, west, [0,1] apply {selectRandom Unitpatrol},[],[],[1,1],[1,1],[]] call BIS_fnc_spawnGroup; 
};

Examplepatrol2 = 
{
Params ["_pos"];
_grp01 = [_pos, west, [0,1] apply {selectRandom Unitpatrol},[],[],[1,1],[1,1],[]] call BIS_fnc_spawnGroup; 
};

Helicopter =
{

params ["_caller"];

private _position = getMarkerPos "Helicopter";

private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"];

_veh setPos _position;

_caller moveInDriver _veh;

};

 

Share this post


Link to post
Share on other sites

Why do you want everything in one single sqf? There are many good reasons to divide your code into several files. However, rule number one is: KISS = Keep It Stupid Simple.

 

In a SP mission you can most often use init.sqf and one other file (to achieve having one file containing all your functions). And what about one file (start_mission.sqf) that actually does something exiting:

 

init.sqf:

call compile preprocessFileLineNumbers "functions.sqf";
execVM "start_mission.sqf";

 

And functions.sqf:

myFirstFunction = {
    hint "this is my first function.";
};

mySecondFunction = {
    params ["_name"];
    hint "hello " + _name;
};

 

And to complete the example, here is and example of start_mission.sqf:

sleep 60;
call myFirstFunction;
sleep 40;
["Rambo"] call mySecondFunction;

 

In a MP mission I always use the following pattern for init.sqf:

// All functions that are to be present and callable on both clients and server
call compile preprocessFileLineNumbers "shared_functions.sqf";

if (isServer) then { // Server functions - executed on hosted and dedicated server
    call compile preprocessFileLineNumbers "server_functions.sqf";
};

if (!isDedicated) then { // Client functions - executed on hosted server and all clients
    call compile preprocessFileLineNumbers "client_functions.sqf";
};

if (isServer) then {
    execVM "start_mission.sqf";
};

 

The "xxx_functions.sqf" files do nothing but declare functions, which makes them present on the machines where they need to be after being called once like in these examples. The "start_mission.sqf" file may contain all mission service logic that makes things happen in the mission. I'd say that this pattern can be used in huge projects. There are good alternatives that makes the code more optimized and such, but if you are struggling with how to structure code in SQF then I'd recommend sticking to this pattern for a while.

 

EDIT: With this pattern, your fnc_AddAction goes into client_functions.sqf and is called from start_mission.sqf (if you don't write it in the init field in the editor, which is also fine). And your fnc_CreateAndMoveInHelicopter goes into client_functions.sqf, and will be reachable from the addAction since it will now exist on the client and addAction is executed on the client.

  • Like 1

Share this post


Link to post
Share on other sites

You cfgFunctions is fine. You don't need to preinit (or postInit) them for your aim. The sqf must be on all PC if you need to run it locally (that's the case from an addAction code). Usually your mission folder is OK for that. PBOed or not (preview) the files are loaded on each PC, ready to run.

 

Don't execVM sqf if you need to repeat them. It's better to compile it,  then call or spawn it several times.

Share this post


Link to post
Share on other sites

Thanks for the help!

Is it good to use [] spawn {_this call compileFinal vs [] spawn compile when not using a variable from initServer.sqf. I have a loop in one of my functions so i can't just execute it with a regular call compile.

[] spawn {_this call compileFinal preprocessFile "shared_functions.sqf"};
[] spawn compile preprocessFileLineNumbers "shared_functions.sqf";

 

Share this post


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

You cfgFunctions is fine. You don't need to preinit (or postInit) them for your aim

Seems like i need to atleast preInit my script which includes several functions inside of it otherwise it won't load them.

 

Or since my script only includes createVehicle fncs called with addAction from an object init inside editor i could call compile it from initPlayerLocal.sqf? Then it would store the fncs for every player?

 

Helicopter = { params ["_caller"]; private _position = getMarkerPos "Helicopter"; private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"]; _veh setPos _position; _caller moveInDriver _veh;  };

Share this post


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

Seems like i need to atleast preInit my script which includes several functions inside of it otherwise it won't load them.

 

 

If your 'all-in-one" function needs somewhere to be called (so run) upon start, OK, but in this case, you should split what must be preinit (run at start) and what must be loaded (standard fnc) then called (for example what you want to call from an addaction)

If you are not familiar with cfgFunctions, yes, you can compile them from an event sqf.

And yes initPlayerLocal is OK for every player. Not for dedicated server but that doesn't here for your codes above.
 

  • Like 1

Share this post


Link to post
Share on other sites
7 hours ago, Robustcolor said:

Thanks for the help!

Is it good to use [] spawn {_this call compileFinal vs [] spawn compile when not using a variable from initServer.sqf. I have a loop in one of my functions so i can't just execute it with a regular call compile.


[] spawn {_this call compileFinal preprocessFile "shared_functions.sqf"};

[] spawn compile preprocessFileLineNumbers "shared_functions.sqf";

 

 

No, it is not good. It is too complicated. You should ”call compile” to create the functions (what you actually do is assigning code to variables). You can do that even if they contain sleep commands. However, *later*, you execute the actual function, simply by using call (or spawn). You can use call even if your function contains sleep. At least from unscheduled environment. call simply means that you wait for a return value.

  • Like 1

Share this post


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

If you are not familiar with cfgFunctions, yes, you can compile them from an event sqf.

I'm not that familiar with how cfgFunctions work. It seems to compileFinal the functions making them global and being able to call/spawn the functions both for client and server. Is it good to make it available for both clients and server in this way, some of my functions are only meant for server and some for clients.

 

What if i would put every single function inside the cfgFunctions? Using preinit for my "all-in-one" functions and store the regular ones, good or bad practice?

 

As for now, i have separated the functions using call compile both from initServer.sqf and initPlayerLocal.sqf.

Share this post


Link to post
Share on other sites

You must understand that when you use cfgFunctions, you create a library as BI does for Arma. That doesn't mean you run them all (even if it's useless to load something for nuts). All these functions are ready to be used.

For preinit and postInit, I can't say because I don't know what you want to do with that. You barely need them.

Spoiler

I preinit an EH "loaded" for managing some keys handlers which are usually non persistent after a save/quit/load mission, and I postInit for a team switching stuff.

 

Usually, your functions are called/spawned by... triggers, event scripts, event handlers, addAction, other scripts....

Your all-in-one function stays a bad idea, even if it's possible.

local or global? in cfgFunctions the functions are ready on all PCs. Your script writing makes the difference on use. Call the server functions from initServer.sqf or from triggers "server only", or from local server scripts... or manage them at start: if !isServer exitWith {true}; 
 

 

 

 

  • Like 1

Share this post


Link to post
Share on other sites

I still have a problem in my function with client/server handling the vehicle. If a player spawns the helicopter and stays on the server and allPlayers is further away then < 1000 of it, it will delete the helicopter. But if the player who spawns it leaves the server, the helicopter will never get deleted. How do i solve that?

 

I'm spawning it with this addAction ["<t color ='#ffcc00'>Spawn Helicopter</t>", [0, _this #1] spawn My_fnc_Helicopter,[],1,true,true,"","_this distance _target <5"];

params ["_subFnc","_caller"];

call {

if (_subFnc == 0) exitWith { 

private _position = getMarkerPos "Helicopter";

private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"];

_veh setPos _position;

_caller moveInDriver _veh;

waitUntil {uiSleep 900;
(allPlayers findIf {_x distance2d _veh < 1000} isEqualTo -1)
};

deleteVehicle _veh;
};

 

Share this post


Link to post
Share on other sites

The script is running on the machine of the player who selected the action. So if that player leaves, the deleteVehicle command is never executed.

 

You solve it by adding the waitUntil and deleteVehicle to a function on the server and then remoteExec that function right after the moveInDriver command.

 

I think you will have to ”spawn” the function, since remoteExec is executing unscheduled and you use sleep. Like this:

 

Function in server_functions.sqf:

 

fnc_deleteChopperAfterAWhile = {

  [] spawn {

    waitUntil ...

    deleteVehicle ...

  };

};

Share this post


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

You solve it by adding the waitUntil and deleteVehicle to a function on the server and then remoteExec that function right after the moveInDriver command.

 

Not sure how to get it to work, i tried something like this without success. _veh will be undefined in my delete function.

params ["_subFnc","_caller"];

call {

if (_subFnc == 0) exitWith { 

private _position = getMarkerPos "Helicopter";

private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"];

_veh setPos _position;

_caller moveInDriver _veh;

[_veh] remoteExec ["fnc_deleteChopperAfterAWhile",2];

};
fnc_deleteVehicleDelay = {

Params ["_veh"];

[] spawn {

waitUntil {uiSleep 900;
(allPlayers findIf {_x distance2d _veh < 1000} isEqualTo -1)
};

deleteVehicle _veh;

};

}; 

 

 

Share this post


Link to post
Share on other sites

You also need to send _veh as a parameter to spawn:

 

[_veh] spawn {

    params [”_veh”];

    ....

};

Share this post


Link to post
Share on other sites
2 hours ago, engima said:

You also need to send _veh as a parameter to spawn:

 

[_veh] spawn {

    params [”_veh”];

    ....

}; 

Thanks, it works now.

Question, does not this spawn the function? [_veh] remoteExec ["fnc_deleteChopperAfterAWhile",2];

The [_veh] spawn {}; might not be necessary then?

 

 

This should spawn the function without the extra [_veh] spawn necessary right?

[_veh] remoteExec ["fnc_deleteChopperAfterAWhile",2];
fnc_deleteChopperAfterAwhile.sqf

Params ["_veh"];

waitUntil {uiSleep 900;
(allPlayers findIf {_x distance2d _veh < 1000} isEqualTo -1)
};

deleteVehicle _veh;

 

Share this post


Link to post
Share on other sites

No, I don’t think so. The function will be executed in unscheduled environment, so sleep and waitUntil will not work. Try and see what happens. Try also without sleep and waituntil and you should see the helicopter get deleted immediately.

 

Unscheduled execution is quicker, but cannot be halted (using sleep and waituntil). Triggers, eventhandlers and remoteExec executes unscheduled. You can always use spawn to move into scheduled execution.

 

At least this is what I can read out of the wiki:

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

Share this post


Link to post
Share on other sites

@Enigma This is what i found about RemoteExec https://community.bistudio.com/wiki/Arma_3_Remote_Execution

Quote

1. If your code includes any delays (commands like sleep or waitUntil) you MUST use remoteExec.

2. If your code contains more CPU demanding operations that will take some time for the game to process, you SHOULD use remoteExec, otherwise you might experience performance drops.

And this about RemoteExecCall

Quote

The code sent by remoteExecCall MUST NOT contain any delays and SHOULD NOT be too complex and CPU demanding.

 

Share this post


Link to post
Share on other sites
24 minutes ago, Robustcolor said:

@Enigma This is what i found about RemoteExec https://community.bistudio.com/wiki/Arma_3_Remote_Execution

And this about RemoteExecCall

 

Ok, this is what I read (on the link I posted above):

  • Scripted function - scheduled environment (suspension is allowed, i.e. spawn, execVM).
  • Script command - unscheduled environment (suspension is NOT allowed).

It seems a bit contradictory, but if it works without the spawn, then good!

Share this post


Link to post
Share on other sites

Question, as the code above shows that i'm creating the vehicle locally from an addAction that is placed inside a eden object, then sending it to the server that has a delete script with code [_veh] remoteExec ["DeleteVehicle",2];

 

If i would like to use an array instead on serverSide and send each vehicle created into it, do i need to remoteExec pushBack _veh or something else so the server can handle every vehicle that each player creates locally.

 

My idea was something like this, but how would i get each vehicle inside the array?

serverSide

allVehicles = [];

while {true} do

{
if (!alive _x) then {
deleteVehicle _x
playerVehicles deleteAt (playerVehicles find _x);
};
sleep 60;
};
} count allVehicles;

 

ClientSide from addAction

params ["_subFnc","_caller"];

call {
if (_subFnc == 0) exitWith { 
private _position = getMarkerPos "Helicopter";
private _veh = createVehicle ["B_Heli_Light_01_F", [0,0,0], [], 0, "FLY"];
_veh setPos _position;
_caller moveInDriver _veh;
allVehicles pushBack _veh;
};

 

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

×