Threading

Scarpet allows to run threads of execution in parallel to the main script execution thread. In Minecraft, apps are executed on the main server thread. Since Minecraft is inherently NOT thread safe, it is not that beneficial to parallel execution in order to access world resources faster. Both getBlockState and setBlockState are not thread safe and require the execution to park on the server thread, where these requests can be executed in the off-tick time in between ticks that didn’t take all 50ms. There are however benefits of running things in parallel, like fine time control not relying on the tick clock, or running things independent on each other. You can still run your actions on tick-by-tick basis, either taking control of the execution using game_tick() API function (nasty solution), or scheduling tick using schedule() function (preferred solution), but threading gives much more control on the timings without impacting the main game and is the only solution to solve problems in parallel (see scarpet camera).

Due to limitations with the game, there are some limits to the threading as well. You cannot for instance join_task() at all from the main script and server thread, because any use of Minecraft specific function that require any world access, will require to park and join on the main thread to get world access, meaning that calling join on that task would inevitably lead to a typical deadlock. You can still join tasks from other threads, just because the only possibility of a deadlock in this case would come explicitly from your bad code, not the internal world access behaviour. Some things tough like players or entities manipulation, can be effectively parallelized.

If the app is shutting down, creating new tasks via task will not succeed. Instead the new task will do nothing and return null, so most threaded application should handle closing apps naturally. Keep in mind in case you rely on task return values, that they will return null regardless of anything in these situations. When app handles __on_close() event, new tasks cannot be submitted at this point, but current tasks are not terminated. Apps can use that opportunity to gracefully shutdown their tasks. Regardless if the app handles __on_close() event, or does anything with their tasks in it, all tasks will be terminated exceptionally within the next 1.5 seconds.