Jump to content
Sign in to follow this  
yacobm8

Why use the spawn command?

Recommended Posts

I was looking at a script and noticed at the bottom it had this at the bottom of the script

[] spawn { sleep 300; life_use_atm = true; };

i read on the wiki that spawn "Starts running a new script" which i can understand but whats the need for it? In the example below why did they use spawn instead of just having sleep 300 and life use atm = true

while{true} do
{
// this code below is setting up a progress bar for robbing a store in altis life just ignore
sleep 1;
_cP = _cP + 0.003333;
_progress progressSetPosition _cP;
_pgText ctrlSetText format["%3 (%1%2)...",round(_cP * 100),"%",_upp];
if(_cP >= 1) exitWith {};
if(player distance _unit > 15) exitWith {};
if(!alive player) exitWith {};
if(vehicle player != player) exitWith {};
};

5 cutText ["","PLAIN"];

[] spawn { sleep 300; life_use_atm = true; };

wouldn't this just be the exact same?

while{true} do
{
// this code below is setting up a progress bar for robbing a store in altis life just ignore
sleep 1;
_cP = _cP + 0.003333;
_progress progressSetPosition _cP;
_pgText ctrlSetText format["%3 (%1%2)...",round(_cP * 100),"%",_upp];
if(_cP >= 1) exitWith {};
if(player distance _unit > 15) exitWith {};
if(!alive player) exitWith {};
if(vehicle player != player) exitWith {};
};

5 cutText ["","PLAIN"];

sleep 300; 
life_use_atm = true;

Share this post


Link to post
Share on other sites

I use it when I want something to run without the rest of the code waiting for that thread to finish.

An example is a simple timer:

_clock_expired = false;
[] spawn {
sleep 300;
_clock_expired = true;
};

loop = true;
while {loop} do {

if (_clock_expired) then { loop = false;  /* CODE */};

};

Loop will run until sleep finishes and variable changes.

Share this post


Link to post
Share on other sites

Because commands such as sleep only work in a scheduled environment created by spawn. Code ran by call is non-scheduled.

Share this post


Link to post
Share on other sites
Code ran by call is non-scheduled.

Are you sure? Because I use sleep all the time with call.

Unscheduled is code in things like event handlers - to my knowledge.

Share this post


Link to post
Share on other sites

You can sleep in called code, but it will pause the scope, while spawn will create a new virtual machine (VM).

call { sleep 5; };
hint "hello world."; // Hint will be shown after 5 sec.

[] spawn { sleep 5; };
hint "hello world."; // Hint will be shown without delay

Share this post


Link to post
Share on other sites

oh thats interesting and a clear example thanks guys

Share this post


Link to post
Share on other sites
...

wouldn't this just be the exact same?

...

In the second example the script will not return until the 300s sleep has finished. This may or may not make a difference based on how it is executed. For example there may be a different script waiting for the other one to finish.

You can sleep in called code, but it will pause the scope, while spawn will create a new virtual machine (VM).

Indeed, it is important to note though that if you cannot sleep within the statement you run the call from you won't be able to spawn in the called statement either. For example, you cannot sleep in an event handler nor in anything called from the event handler.

Share this post


Link to post
Share on other sites

Okay, it seems you cannot sleep in a function that is called from another called function. However, if calling from a function ran by spawn or a script ran by execVM, sleep works fine.

Odd.

Edited by Horner

Share this post


Link to post
Share on other sites

execVM is a compile followed by a spawn. Therefore it's already in a scheduled environment, and so sleep is fine.

Btw, avoid execVM.

Share this post


Link to post
Share on other sites

I wouldn't per se say that execVM must be avoided. It's perfectly fine with code which only runs once per mission and isn't time crucial since the memory which was occupied by the "execVM"-script gets released afterwards, while preprocessed code stays in the memory for the whole mission.

Share this post


Link to post
Share on other sites

Hi!

Regarding this I'm working on a mission, very complex (Arma 3 - Antistasi, check my signature), everything is dynamical, missions, assets, everything scripted. Only the intro is editor placed + lots of scripting too.

All the mission is execVM except third party scripts (UPSMon for example), because my lack of knowledge on functions and some features like setvariable... you won't see one of these on my scripts. Just arrays, common commands... old school. I'm not pro programmer, I'm an amateur mission maker with a big project indeed.

The question is, as it does not seem any serious fps drop present except when you get to an area with lot's of spawning units, which AFAIK the call / spawn / execVM does not matter. Would get the mission that better using call / spawn, converting scripts to functions etc????

execVM is very useful as is called newly everytime the script needs to run, so if you want to make any changes on the fly to the script, without restarting you may call the script again with the new changes. This, in a dynamic sandbox, is important, due you may need to run the script in certain stages of the game and restarting would be a pain in the ass.

I would appreciate if one of the performance gurus here would take a closer look to that mission unpboing it and check those scripts if he sees any mandatory need of doing things in another way.

Share this post


Link to post
Share on other sites
link down?

Works fine for me

Here's some similar stuff:

https://community.bistudio.com/wiki/Code_Optimisation#Threads

Hi!

Regarding this I'm working on a mission, very complex (Arma 3 - Antistasi, check my signature), everything is dynamical, missions, assets, everything scripted. Only the intro is editor placed + lots of scripting too.

All the mission is execVM except third party scripts (UPSMon for example), because my lack of knowledge on functions and some features like setvariable... you won't see one of these on my scripts. Just arrays, common commands... old school. I'm not pro programmer, I'm an amateur mission maker with a big project indeed.

The question is, as it does not seem any serious fps drop present except when you get to an area with lot's of spawning units, which AFAIK the call / spawn / execVM does not matter. Would get the mission that better using call / spawn, converting scripts to functions etc????

Assuming that you know the difference between scheduled and unscheduled environments (see earlier in this thread or the link I posted) and the difference between call and spawn:

These are pretty much the same:

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

Let’s take it backwards, â€compile preProcessFileLineNumbers†will preprocess the script (optimize, remove comments and linebreaks etc) and then compile it (as far as I know it does basic syntax checking, probably more).

That would return a compiled function ready to use. We could also do it like this in theory.

_prepped = preProcessFileLineNumbers “script.sqfâ€;
_compiled = compile _prepped;
// run it
call _compiled;

That compiled function will then be “callâ€ed with the “_this†parameters which in this example is the empty array ( [] )

Since we used spawn, that function would run as a new process (maybe not technichally, the script engine is single-threaded) in the scheduled environment and would be able to utilize “sleep†and waitUntil commands etc.

Now as you might be able to tell, everytime we use execVM we will compile and preprocess the file and save it into memory (likely cleaned up some time later since we have no more references)

Is this OK? Certainly if you have one script that is supposed to do one thing and never be used again.

However when you do execVM every single time (for example spawning an enemy group) the engine is doing unnecessary stuff that could have been avoided if the function was saved.

And that can be done by

TAG_spawnUnits = compile preProcessFileLineNumbers “spawn.sqfâ€;
// the function is now saved and we can use it later

// later, somewhere in another code or trigger
[getMarkerPos “a0â€] call TAG_spawnUnits;

So tl;dr preprocess and compile scripts into functions if they are to be used several times during the mission.

Also note that the script engine is really fast during mission load (non-scheduled environment)

What I would really recommend is using the new cfgFunctions utility:

https://community.bistudio.com/wiki/Functions_Library_(Arma_3)#Adding_a_Function

As for this:

execVM is very useful as is called newly everytime the script needs to run, so if you want to make any changes on the fly to the script, without restarting you may call the script again with the new changes. This, in a dynamic sandbox, is important, due you may need to run the script in certain stages of the game and restarting would be a pain in the ass.

Use execVM when testing and developing and then transfer it into a cfgFunction once you know that it works.

Edited by cuel

Share this post


Link to post
Share on other sites
I was looking at a script and noticed at the bottom it had this at the bottom of the script
[] spawn { sleep 300; life_use_atm = true; };

i read on the wiki that spawn "Starts running a new script" which i can understand but whats the need for it? In the example below why did they use spawn instead of just having sleep 300 and life use atm = true

wouldn't this just be the exact same?

Yes, in that exact case, it would be exactly the same, possibly a misunderstanding from the scripter.

So where would the use of Spawn make sense? Within event based environment or when you want a script to start in parallel.

When a script is started with execVM, execFSM or spawn, this script instance will run in parallel/independent from the previous, or caller instance.

Note that code within these non event based script threads is conditioned by the Script Scheduler, which makes sure such scripts do not slow down the simulation.

When executing code on a event based environment, the use of sleep is not allowed, and loops are limited to something like 10.000 iteration. This is because the Engine will execute this code within the same frame (What the above method avoids).

In the script you posted, we can see that it already should be running on a non event based environment (or scheduled env) because it already makes use of sleep command.

To give you a practical example, when you add an event handler to a unit, when that event is triggered, it is executed in a non scheduled environment, where you cannot use sleep (for example), so let's say you want to show a hint, 5 seconds after a unit dies:

_unit addEventHandler ["Killed", {
  _this spawn {
     sleep 5;
     hint format ["%1 has died 5 seconds ago", name (_this select 0)];
  };
}];

Share this post


Link to post
Share on other sites

Thank you very much cuel!

So. As more or less 99% of my scripts run more than once, you recommend me to compile all of them so they get stored in memory, and call them whenever I need in a faster way. Even more, the script itself won't have to be changed on anything.

Regarding the scheduled / non scheduled enviroment. Maybe this is the cause of one problem in the mission.

It has a script that checks distances to arrays containing markers, and checks if those markers are in one side or another (arrays too). After distance checks, it stores the markers in another two arrays, the "far" markers and the "near" markers. All this to spawn/despawn units, of one side or other.

Of course all this in a while loop.

The problem seems when, externally to that script, I change those arrays. For example: when you conquer a marker, you change the marker from the array which contains blufor owned markers to another. That's not made in the "checkdistances" script.

About 5% of times, script messes and no array marker movement is made, and you find the whole island empty :(

Maybe the thing is messing because two scripts are doing things on the same array at the same time. This makes me think about playing with this scheduling things, so one script has priority, and everything must wait until it has done it's commands before any other.

And a second question: I'm running the script once, but it will loop forever, should I still use execVM?

Thanks A LOT in advance.

Share this post


Link to post
Share on other sites

Yeah that sounds a bit sketchy. And there's of course several approaches to the problem

Have you thought about using triggers? You can store the marker on the trigger using setVariable, for changing its color etc.

Another approach for the loop problem could be one main loop calling your functions

while {true} do {
   []  call checkDistances;
   [] call despawnOrSpawnUnits;
   [] call changeMarkerColors; // or whatever
}

For the second question, it doesn't matter really

Share this post


Link to post
Share on other sites

Regarding triggers, yes, indeed EOS and COS which make something similar, use triggers. I didn't due to lack of scripting knowledge regarding triggers and because I was afraid of game saturation of triggers. I can control a script, how much time it takes to check all the markers, but I cannot control how much latency are generating let's say 40 triggers....

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  

×