#Error to change scene in static function
1 messages · Page 1 of 1 (latest)
LoadScene will occur on the next frame, not immediately
(I'm not sure if that's the problem, just pointing that out)
Never change it
Also, LoadScene will only work if the scene has been added to the list in build settings
File -> Build Settings
Is added too if i change LoadScena to function not static work
swapScene isn't a static function in the example you posted above
It's an instance function on an object that you have stored in a static field
Not buy i call of a static reference of the class
Yeah
and i thing this is the problem
But cant find nothing
i try to make static swapScene() and call it direcly out statiic reference but same result
As in:
public static void SwapScene()
{
Debug.Log("A");
SceneManager.LoadScene("Lobby");
Debug.Log("B");
}
HomeManager.SwapScene();
?
And there are no errors?
That's... really strange, the B log should appear
If it doesn't, the game should hang
What does the code calling SwapScene look like?
using System.Net;
using UnityEngine;
using WebSocketSharp;
public class SockedManager
{
private static IPEndPoint server_endpoint = new IPEndPoint(ServerConfig.SERVER_IP, ServerConfig.SERVER_PORT);
private static WebSocket ws = new WebSocket("ws://" + server_endpoint.ToString());
public static void connect()
{
ws.Connect();
ws.OnMessage += (sender, e) =>
{
eventManager(e.Data);
};
}
public static void createRoom()
{
EventBase createRoom = new EventBase(ProtocolType.CreateRoom);
ws.Send(JsonUtility.ToJson(createRoom));
}
public static void joinRoom(string roomId)
{
EventBase joinRoom = new EventBase(ProtocolType.JoinRoom, roomId);
ws.Send(JsonUtility.ToJson(joinRoom));
}
private static void eventManager(string data)
{
EventBase eventIn = JsonUtility.FromJson<EventBase>(data);
Debug.Log(data);
switch (eventIn.type)
{
case ProtocolType.CreateRoom:
DataClass.ROOM_ID = eventIn.roomId;
DataClass.INSTANCE_HOME_MANAGER.swapScene();
DataClass.IS_OWNER = true;
break;
case ProtocolType.JoinRoom:
DataClass.ROOM_ID = eventIn.roomId;
if (eventIn.user.id.Equals(DataClass.USER_ID))
{
DataClass.INSTANCE_HOME_MANAGER.swapScene();
}
else
{
DataClass.INSTANCE_LOBBY_MANAGER.userConnect(eventIn.user.name);
}
break;
default:
break;
}
}
}
Like thiis xD
Okay yeah that is... really odd
my code or the problem?
The problem
xD
There doesn't seem to be any obvious cause
I hace same problem with DataClass.INSTANCE_LOBBY_MANAGER.userConnect(eventIn.user.name);
is called but dont work code in
xD
for this my focus is in static
im not sure
i restart unity and pc and nothing is not Unity bug
too
The strange part is that the B log doesn't appear. If LoadScene is failing you should get an error, if there's no error then the code should continue, but it seems to just... stop?
But this isn't a coroutine or an async function so it shouldn't be possible for that to happen
yhea
Just as a test, what if you do LoadSceneAsync?
I think your PC might be haunted lol
hahaha
i was working with sockets and they are the trigger off this calls
but i thing this is not a problem when logs apear
Hmm, maybe do you have errors hidden by accident?
no xD
Like these buttons
Hmm actually
Can you try this:
public void swapScene()
{
try
{
Debug.Log("A");
SceneManager.LoadScene(sceneName: "Lobby");
Debug.Log("B");
}
catch (Exception ex)
{
Debug.LogException(ex);
throw;
}
}
I think I know what's going on now
and if I'm right, you will get an error when you try that
Yes i get error 🙂
Okay, I know what's wrong then
So, you're calling this in a callback from a web socket right?
That means this function isn't being called on Unity's main thread, it's being called from a separate background thread
UnityException: LoadSceneAsyncNameIndexInternal can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
UnityEngine.SceneManagement.SceneManagerAPIInternal.LoadSceneAsyncNameIndexInternal (System.String sceneName, System.Int32 sceneBuildIndex, UnityEngine.SceneManagement.LoadSceneParameters parameters, System.Boolean mustCompleteNextFrame) (at <ab7de6937a4448b0a6ccd59e9820599a>:0)
UnityEngine.SceneManagement.SceneManagerAPI.LoadSceneAsyncByNameOrIndex (System.String sceneName, System.Int32 sceneBuildIndex, UnityEngine.SceneManagement.LoadSceneParameters parameters, System.Boolean mustCompleteNextFrame) (at <ab7de6937a4448b0a6ccd59e9820599a>:0)
UnityEngine.SceneManagement.SceneManager.LoadSceneAsyncNameIndexInternal (System.String sceneName, System.Int32 sceneBuildIndex, UnityEngine.SceneManagement.LoadSceneParameters parameters, System.Boolean mustCompleteNextFrame) (at <ab7de6937a4448b0a6ccd59e9820599a>:0)
UnityEngine.SceneManagement.SceneManager.LoadSceneAsync (System.String sceneName, UnityEngine.SceneManagement.LoadSceneParameters parameters) (at <ab7de6937a4448b0a6ccd59e9820599a>:0)
UnityEngine.SceneManagement.SceneManager.LoadSceneAsync (System.String sceneName) (at <ab7de6937a4448b0a6ccd59e9820599a>:0)
HomeManager.swapScene () (at Assets/Scrips/Managers/Scenes/HomeManager.cs:39)
UnityEngine.Debug:LogException(Exception)
HomeManager:swapScene() (at Assets/Scrips/Managers/Scenes/HomeManager.cs:44)
SockedManager:eventManager(String) (at Assets/Scrips/Connections/SockedManager.cs:37)
<>c:<connect>b__2_0(Object, MessageEventArgs) (at Assets/Scrips/Connections/SockedManager.cs:14)
You can only use the Unity API on the main thread
Yup
So you need to dispatch the function to the main thread
I have some code for this you can use
and then instead of DataClass.INSTANCE_HOME_MANAGER.swapScene();
you can do
MainThread.Send(_ =>
{
DataClass.INSTANCE_HOME_MANAGER.swapScene();
}, null);
You can also do MainThread.Send(_ => DataClass.INSTANCE_HOME_MANAGER.swapScene(), null); if you prefer one line
Awesome
So yeah, the problem was that the code wasn't running on the main thread
And Unity won't show errors from other threads in the console
Is there any way to know if I'm on the main thread?
if (Thread.CurrentThread == MainThread.Instance)
🙂
Hope that was helpful!
public abstract class ApplicationCommand
{
public abstract void Execute();
}
public class ApplicationCommandBuffer : MonoBeahviour
{
public static ApplicationCommandBuffer Instance { get; private set; }
private Queue<ApplicationCommand> _commands { get; } = new Queue<ApplicationCommand>();
private void Awake() => Instance = this;
public void Execute(ApplicacionCommand command) => _commands.Enqueu(command);
private void Update() => while(_commands.Count > 0) _commands.Dequeu().Execute();
}
public class SwapSceneApplicacionCommand : ApplicationCommand
{
private string _sceneName { get; }
public SwapSceneApplicacionCommand (string sceneName) => _sceneName = sceneName;
public override void Execute() => SceneManager.LoadScene(_sceneName);
}
in other thread tell me this too
You can also do if (Thread.CurrentThread.ManagedThreadId = MainThread.ManagedThreadId) which might work better
There's also if (Environment.CurrentManagedThreadId == MainThread.ManagedThreadId)
Which is probably the best way
and yeah that's another way to dispatch to the main thread, it's just more complicated