You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As discussed in #1593, one of the largest lag spikes in the game is loading a new world or save. Since this is not done asyncronously, the build appears to have crashed and prompts the user to force close the program. Fixing this is a complex task, So i'm putting together a place to create a solution.
The Problem
When the new world is loaded, a variety of slow operation all fire at once.
loading the save file/ generating a new world
Destroying everything in the current scene, and the resulting garbage collection
Instantiating every game object in the new scene, and the resulting memory allocation and unity lag that comes with Instanciating.
running the start method of every object in the _World, which then calls almost every constructor of every manager, controller, etc...
If its a save, the characters may all have a pathfinding call on top of that.
The Solution
I plan to focus on the fourth bullet, the constructors/start methods of every single manager and controller called when the game loads. These can be split into two categories: Unity centric and non Unity centric. The former interact with some aspect of unity that cannot be put in another thread, like Resource.Load or instanciating gameobjects. the latter only do calculations or can be tailored to do most of their work asyncronously and do the unity specific-work in a callback.
First every start method and constructor has to be analyzed to see what category it falls into. Next, a "master" object will be repsponsible for invoking all start/initialization related calls. Those that have no unity interaction can be run in another thread, while the unity centric ones are put into a queue inside the master object. The master object starts a couroutine where it cycles through the queue like so
//pseudo-code - inside a coroutine
start a timer
while ( timer < maxTimeAllowedPerFrame) {
nextItemInQueue();
}
yield return null;
so that the longest hang time is reduced to the time it takes one function to run/the maxTimeAllowed. Obviously this could take a very long time to complete, so it is important to thread as many calculations and split up large calls into smaller parts. While the queue is still full, the user simply gets a "loading..." dialog and the game will never lag long enough for the OS to report it as not working.
last note: any processes that need to happen in a specific order can hopefully be achieved by a series of callbacks, so that when the first one finishes it puts the next callback into the master queue.
This video is an implementation of a similar system. Its used for pathfinding but the general idea is the same.
The text was updated successfully, but these errors were encountered:
As discussed in #1593, one of the largest lag spikes in the game is loading a new world or save. Since this is not done asyncronously, the build appears to have crashed and prompts the user to force close the program. Fixing this is a complex task, So i'm putting together a place to create a solution.
The Problem
When the new world is loaded, a variety of slow operation all fire at once.
The Solution
I plan to focus on the fourth bullet, the constructors/start methods of every single manager and controller called when the game loads. These can be split into two categories: Unity centric and non Unity centric. The former interact with some aspect of unity that cannot be put in another thread, like Resource.Load or instanciating gameobjects. the latter only do calculations or can be tailored to do most of their work asyncronously and do the unity specific-work in a callback.
First every start method and constructor has to be analyzed to see what category it falls into. Next, a "master" object will be repsponsible for invoking all start/initialization related calls. Those that have no unity interaction can be run in another thread, while the unity centric ones are put into a queue inside the master object. The master object starts a couroutine where it cycles through the queue like so
so that the longest hang time is reduced to the time it takes one function to run/the maxTimeAllowed. Obviously this could take a very long time to complete, so it is important to thread as many calculations and split up large calls into smaller parts. While the queue is still full, the user simply gets a "loading..." dialog and the game will never lag long enough for the OS to report it as not working.
last note: any processes that need to happen in a specific order can hopefully be achieved by a series of callbacks, so that when the first one finishes it puts the next callback into the master queue.
This video is an implementation of a similar system. Its used for pathfinding but the general idea is the same.
The text was updated successfully, but these errors were encountered: