After updating my game from 4.3 to 4.4, LoadThreadRequest occassionally stalls while trying to load a large scene. I’ve had it get stuck at 50%, 83%, etc…
However, it occasionally just works, which makes this whole situation a lot more complicated to debug. This doesn’t seem to happen on small simple scenes.
Has this happened to anybody else after updating to 4.4 and does anybody know a fix?
This is my code if needed:
private void StartLoad(bool syncLoad)
{
if(syncLoad)
{
waitingForSyncLoad = true;
announcedSuccessfulLoad = false;
syncLoadConfirmation = 0;
}
Error state = ResourceLoader.LoadThreadedRequest(incomingScenePath, "", useSubThread);
if(state == Error.Ok)
{
loadingScreen.SetLoadingScreenStatus(true);
GD.Print("=====================================================================");
GD.Print("Attempting to load the following scene: " + incomingScenePath);
GD.Print("=====================================================================");
SetProcess(true);
}
}
public override void _Process(double delta)
{
ResourceLoader.ThreadLoadStatus status = ResourceLoader.LoadThreadedGetStatus(incomingScenePath, progress);
if((int) status == 0 || (int) status == 2) // Load Fail.
{
GD.Print("=====================================================================");
GD.Print("ERROR: Failed to load the following scene: " + incomingScenePath);
GD.Print(status);
GD.Print("=====================================================================");
loadingScreen.SetLoadingScreenStatus(false);
SetProcess(false);
return;
}
else if((int) status == 1) // Loading...
{
GD.Print("LOADING: " + (float) progress[0] * 100f + "%");
}
else if((int) status == 3) // Load Success!
{
if(waitingForSyncLoad)
{
if(!announcedSuccessfulLoad)
{
Rpc("LoadConfirmation");
announcedSuccessfulLoad = true;
syncLoadConfirmation++;
GD.Print("Load was succesful!");
GD.Print("Waiting for all players to load...");
}
else
{
if(MultiplayerManager.instance.GetClientLobby().Count <= syncLoadConfirmation)
{
GD.Print("=====================================================================");
GD.Print("Switching to the following scene: " + incomingScenePath);
GD.Print("=====================================================================");
PackedScene scene = (PackedScene)ResourceLoader.LoadThreadedGet(incomingScenePath);
GetTree().ChangeSceneToPacked(scene);
loadingScreen.SetLoadingScreenStatus(false);
SetProcess(false);
}
}
}
else
{
GD.Print("=====================================================================");
GD.Print("Switching to the following scene: " + incomingScenePath);
GD.Print("=====================================================================");
PackedScene scene = (PackedScene)ResourceLoader.LoadThreadedGet(incomingScenePath);
GetTree().ChangeSceneToPacked(scene);
loadingScreen.SetLoadingScreenStatus(false);
SetProcess(false);
}
}
}
[Rpc(MultiplayerApi.RpcMode.AnyPeer, TransferMode = MultiplayerPeer.TransferModeEnum.Reliable)]
private void LoadConfirmation()
{
syncLoadConfirmation++;
}
Yup. I’ve got the same issue - my loading screen was working fine in 4.3. Now it’s stuck at 50%.
I’m unable to reproduce it using Visual Studio Code + its debugger. Issue occurs only when the Game is launched from Editor.
using Godot;
using System;
using System.Collections;
public partial class CLoadingScreen : Control
{
[Signal] public delegate void UnloadingFinishedEventHandler();
[Signal] public delegate void SceneLoadedEventHandler();
[Signal] public delegate void LoadingFinishedEventHandler();
[Export] public string LevelToLoad;
[Export] public float FadeOutLength = 0.1f;
[Export] public float FadeInLength = 0.1f;
[Export] public float FadeLengthMul = 10.0f;
public enum Mode
{
Fade,
Overlap,
};
[Export] public Mode LoadingMode = Mode.Fade;
enum State
{
None,
FadeOut,
Processing,
Loading,
};
State m_State = State.None;
Label m_PercentLabel;
Godot.Collections.Array m_PercentProgress = new Godot.Collections.Array();
float m_LoadingScreenOpacity = 0.0f;
float m_ScreenWidth = 0;
string m_CurrentlyLoadedLevel;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
m_PercentLabel = GetNode<Label>("Percent");
m_ScreenWidth = Size.X;
SetOpacity(0.0f);
m_State = State.FadeOut;
m_CurrentlyLoadedLevel = GetTree().CurrentScene.Name;
ResourceLoader.LoadThreadedRequest(LevelToLoad);
GD.Print("Loading " + LevelToLoad);
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
switch (m_State)
{
case State.None:
{
GD.Print("None");
m_LoadingScreenOpacity = 0.0f;
break;
}
case State.FadeOut:
{
GD.Print("FadeOut " + m_LoadingScreenOpacity);
if (FadeOutLength > 0.0f)
{
m_LoadingScreenOpacity += (float) delta / (FadeOutLength * FadeLengthMul);
}
else
{
m_LoadingScreenOpacity = 1.0f;
}
if (m_LoadingScreenOpacity >= 1.0f)
{
if (GetTree().CurrentScene != null)
GetTree().CurrentScene.QueueFree();
m_State = State.Processing;
EmitSignal(SignalName.UnloadingFinished);
if (CDebug.DbgLoadingScreen)
GD.Print("Unloading " + m_CurrentlyLoadedLevel + " completed " );
}
break;
}
case State.Processing:
{
ResourceLoader.ThreadLoadStatus status = ResourceLoader.LoadThreadedGetStatus(LevelToLoad, m_PercentProgress);
GD.Print("Processing " + (float)m_PercentProgress[0] * 100 + "%");
m_PercentLabel.Text = (float)m_PercentProgress[0] * 100 + "%";
switch (status)
{
case ResourceLoader.ThreadLoadStatus.Loaded:
m_State = State.Loading;
GetTree().ChangeSceneToPacked(ResourceLoader.LoadThreadedGet(LevelToLoad) as PackedScene);
EmitSignal(SignalName.SceneLoaded);
if (CDebug.DbgLoadingScreen)
GD.Print("Loaded " + LevelToLoad);
break;
default:
break;
}
break;
}
case State.Loading:
{
GD.Print("FadeOut " + m_LoadingScreenOpacity);
if (FadeInLength > 0.0f)
{
m_LoadingScreenOpacity -= (float) delta / (FadeInLength * FadeLengthMul);
}
else
{
m_LoadingScreenOpacity = 0.0f;
}
if (m_LoadingScreenOpacity <= 0.0f)
{
m_State = State.None;
if (CDebug.DbgLoadingScreen)
GD.Print("Loading " + LevelToLoad + " completed");
EmitSignal(SignalName.LoadingFinished);
}
break;
}
}
SetOpacity(m_LoadingScreenOpacity);
}
public void SetOpacity(float opacity)
{
opacity = Mathf.Clamp(opacity, 0.0f, 1.0f);
switch (LoadingMode)
{
case Mode.Fade:
{
if (opacity == 0.0f)
{
Visible = false;
}
else
{
Visible = true;
Color clr = new Color(1.0f, 1.0f, 1.0f, opacity);
Modulate = clr;
}
break;
}
case Mode.Overlap:
{
Vector2 p = Position;
p.X = -m_ScreenWidth * (1.0f - opacity);
Position = p;
break;
}
}
}
}