0
votes

I cant instantiate a prefab from another script, it does nothing and gives me no errors. In the same "play" i can instantiate the same prefab from the same script multiple times but if i try to do it by executing the same method from another script it doesnt work.... i pass some variables and print them ( it work) but instatiation is doing nothing....please help!

I tried to solve it by:

public GameObject reference, UnityEvents and Ataching both scripts in one object

Script One

void OnEnable()
{
    EventSystemManager.StartListening("printMessage", AddMessage);     
}

public void AddMessage(string message ) 
{
    GameObject remoteMessage = Instantiate(localMessagePrefab, 
    chatTransform);
    remoteMessage.transform.GetChild(0).GetComponentInChildren<Text> 
    ().text = message;
}

Script Two

public IEnumerator StartWebSocket() 
{
    using (ws = new WebSocket(serveradress))
    {
        ws.OnOpen += (sender, e) =>
        onOpenHandler();
        ws.OnMessage += (sender, e) =>
        onMessageHandler(e.Data);
        ws.OnError += (sender, e) =>
        onErrorHandler(e);
        ws.OnClose += (sender, e) =>
        onCloseHandler(e);
        ws.Connect();
        for (; ; )
        {
            yield return null;
        }
    }
} 

private async void onMessageHandler(string e)
{
    serverMessage = JsonUtility.FromJson<serverMssg>(e);
    EventSystemManager.TriggerEvent("printMessage", 
    serverMessage.normmsg);
    await miaApi.queueAnim(serverMessage.normmsg);
}

The message is passed but instantiation do nothing.... The only thing i detect in debugging is that transform dissapears when tryng to do it from other script:

from the same script:

same script

from another script:

other script

Also there is a video (without sound) The video doesnt use events but is exactly the same behavior Video TIA!

1
After some tests I realize that I can instantiate from the other script using the start method, but if I do it from the onMessageHandler method doesnt work....Javier Santos
I think the problem is that the websocket onMessage is async.....but i dont find a way to make it work.....I thought the events would solve the problem....Javier Santos

1 Answers

0
votes

I don't know how the EventSystemManager works.

In case the issue is actually the async and multi-threading you could try a simple "dispatcher" for passing callbacks back to the main thread:

public class MainThreadDispatcher : MonoBehaviour
{
    private static MainThreadDispatcher _instance;
    public static MainThreadDispatcher Instance
    {
        get 
        {
            if(!_instance)
            {
                _instance = new GameObject("MainThreadDispatcher").AddComponent<MainThreadDispatcher>();

                DontDestroyOnLoad(_instance.gameObject);
            }

            return _instance;
        }
    }

    private ConcurrentQueue<Action> actions = new ConcurrentQueue<Action>();

    private void Update()
    {
        // work the queue in the main thread
        while(actions.TryDequeue(out var action))
        {
            action?.Invoke();
        }
    }

    public void Dispatch(Action action)
    {
        actions.Enqueue(action);
    }
}

and then use it to make sure the callback is done in the main thread

private MainThreadDispatcher mainThreadDispatcher;

void OnEnable()
{
    // before dispatching stuff make sure an instance reference is optained
    // or is created in the main thread
    mainThreadDispatcher = MainThreadDispatcher.Instance;

    EventSystemManager.StartListening("printMessage", AddMessage);   
}

// might be executed in a thread
public void AddMessage(string message ) 
{
    // instead of directly executing the code wait for the main thread
    // either using a lambda expression
    mainThreadDispatcher.Dispatch(() =>
        {
            GameObject remoteMessage = Instantiate(localMessagePrefab, 
            chatTransform);
            remoteMessage.transform.GetChild(0).GetComponentInChildren<Text> 
            ().text = message;
        });

    // or if you prefer a method
    //mainThreadDispatcher.Dispatch(HandleAddMessage);
}

// should be only executed in the main thread
private void HandleAddMessage()
{
    GameObject remoteMessage = Instantiate(localMessagePrefab, 
    chatTransform);
    remoteMessage.transform.GetChild(0).GetComponentInChildren<Text> 
    ().text = message;
}