The scheduler is the part of the game engine that decides which thread runs at a certain point in time. It has the ability to pause a running thread, move it to the back of the running queue and start a new thread.
A new thread can be started in a script by using spawn, execVM and exec commands. A script or function started this way will run in a scheduled environment, where as a function which is started via call will retain the scheduling from the environment it was called from e.g a call from scheduled code will remain scheduled, a call from unscheduled code will remain unscheduled.
Running code in a scheduled environment starts a new thread. The executing instance will not wait for the result of scheduled code and will continue on with its execution, so it is not possible to return any values from code executed in this manner although a Script handle for started thread is provided.
As described below there is no way to predict when scheduled code will have finished, although you can use the command scriptDone with the provided Script handle to query if the thread execution has finished and there is also the command terminate to abort the thread.
The advantage of scheduled code is that it runs asynchonously in the background and that you are able to run code with a huge performance impact (nearly) without slowing down the game.
All scheduled scripts can run for a maximum of 3ms in a frame. (Except if inside loadingscreen where it's 50ms per frame)
Each Script that runs add's up to the total runtime and as soon as the total runtime of 3ms is reached the current script is paused and the game continues calculating everything else it needs to calculate that frame (For example sound and graphics rendering). On the next frame the scheduler again starts to run scripts for 3ms, starting with the script which hasn't been executed for the longest time.
This means any script that ran as the 3ms runtime was reached will be paused in the middle of it's execution and depending on how many scripts are spawned it might take several frames till it will run again. A while true loop with sleep started in scheduled environment therefore has little chance to follow with exact interval, because sleep only marks the script as done in the current frame and the next time the script is executed the engine will check if the sleep is over. This means at 20 FPS the time between one frame and the next is roughly 50ms. That would make a sleep 0.01 wait for atleast 0.05 seconds.This effect get's bigger when the fps get even lower and if the scheduler is so overfilled that your script only get's checked every few frames instead of every frame.
If you spawn a scheduled script it will only start to run in the next frame when the scheduler starts fresh again.
Where code starts scheduled
- functions with postInit attribute (although suspension is allowed any long term suspension will halt the mission loading until suspension has finished)
- code execution with spawn
- code execution with execVM
- code execution with exec
- code execution with call from a scheduled environment
Often also called non-scheduled environment but means the same and you will find both terms used in this wiki. The unscheduled environment runs (as described above) in the executing instance. The executing instance waits until the called function is finished. This ensures the execution order and is the fastest way for scripters to execute their code. The disadvantage is that a called function can halt or slow down the game if the function has a high performance consumption. Therefore those functions should be spawned and thereby run in a scheduled environment.
Where code starts unscheduled
- functions with preInit attribute
- Event handlers (on units and in GUI)
- object Init Event Handlers
- object initialization fields
- all pre-init code executions
- expressions of Eden Editor entity attributes
- code execution with call from a unscheduled environment
- code inside isNil
- sqf code which is called from sqs-code
A while do loop will be limited to 10,000 iteration in non-scheduled environment. In scheduled environment such limit does not apply.
Suspension is the process to wait a period of time or to wait for something to happen. Methods for suspension are sleep, uiSleep, waitUntil and all other kind of loops. Suspension with sleep and uiSleep is generally forbidden in an unscheduled environment. Loops will run for 10,000 iterations before breaking the loop and continuing with the following code. If you want to use suspension in your script then ensure that you are running your code in scheduled environment. You can test your current environment for the ability of suspension with canSuspend.