Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Unity Thread error

Discussion in 'Scripting' started by luckie12, Aug 16, 2018.

  1. luckie12

    luckie12

    Joined:
    Aug 17, 2014
    Posts:
    165
    Hello, i am trying to call a function in a MonoBehaviour script, from a script without monobehaviour. Ofcourse the error i am getting is

    'Find can only be called from the main thread.'

    So i was wondering how i would fix this,

    So this is the script without monobehaviour:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Parser {
    6.     /*
    7.     <!Lef-------
    8.     This script parses messages.
    9.     Sending and received messages.
    10.     Determine what function they need to run.
    11.     ---------!>
    12.     */
    13.     LeftandRight lr;
    14.    
    15.     public Parser(LeftandRight lr)
    16.     {
    17.         this.lr = lr;
    18.     }
    19.  
    20.     public void parseMessage(string message)
    21.     {
    22.         //Parse the message and send it to other functions executing on a client space
    23.         char[] parts = { ':' };
    24.         string[] words = message.Split(parts);
    25.  
    26.         if(words[0] == "UPDATE")
    27.         {
    28.             if(words[1] == "MOVEMENT")
    29.             {
    30.                 var user = words[2];
    31.                 var x = words[3];
    32.                 var y = words[4];
    33.                 var z = words[5];
    34.                 Debug.Log(user + x + y + z);
    35.                 lr.rotate(user, x, y, z);
    36.  
    37.             }
    38.             if(words[1] == "NAME")
    39.             {
    40.                 var oldName = words[2];
    41.                 var newName = words[3];
    42.             }
    43.         }
    44.     }
    45.  
    46.     public void printMessage(string color, string message)
    47.     {
    48.         Debug.Log("<color="+color+">" + message + "</color>");
    49.     }
    50.  
    51. }
    52.  
    and this is the script that uses MonoBehaviour

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Newtonsoft.Json;
    5.  
    6. public class LeftandRight : MonoBehaviour {
    7.  
    8.     Firrst fs;
    9.     Networking nw;
    10.  
    11.     void Start()
    12.     {
    13.         fs = GameObject.Find("UIControl").GetComponent<Firrst>();
    14.         nw = fs.getConnection();
    15.     }
    16.  
    17.     public void leftClick()
    18.     {
    19.         nw.SendMessages("UPDATE:MOVEMENT:jablor:1:1:8");
    20.     }
    21.  
    22.     public void rightClick()
    23.     {
    24.         nw.SendMessages("UPDATE:MOVEMENT:jablor:2:5:8");
    25.     }
    26.  
    27.     public void rotate(string user, string x, string y, string z)
    28.     {
    29.         Debug.Log("<color=yellow>" + user + "</color>");
    30.         GameObject player = GameObject.Find(user);
    31.         player.transform.Rotate(float.Parse(x), float.Parse(y), float.Parse(z));
    32.     }
    33.  

    NOTE: It goes wrong at the 'rotate' function, because its in another thread.

    Thanks for any help!
     
  2. FernandoHC

    FernandoHC

    Joined:
    Feb 6, 2018
    Posts:
    335
    Don't use Find, it's a bad way for referencing objects.
    Instead, have a reference for the objects you want to access.
     
  3. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Generally, you can only call Unity API's from the main thread. If you want to run background threads (other than using the ECS), then you could create a message passing mechanism to allow the background thread(s) to tell the main thread to do something using the Unity API.
     
  4. luckie12

    luckie12

    Joined:
    Aug 17, 2014
    Posts:
    165
    Well, i started to work on a Queue for messages, also, it kinda works, but it crashes as soon as it comes to the Lock:


    Code (CSharp):
    1.     public void ReadMessage(object sender, MessageEventArgs e)
    2.     {
    3.         string message = e.Data;
    4.         Debug.Log(message);
    5.         lock (Firrst.Instance.Queue)
    6.         {
    7.             Firrst.Instance.Queue.Enqueue(e.Data);
    8.         }
    9.         Debug.Log(message);
    10.     }
    So, the first debug.log is executed, but the last isnt, the Queue never gets filled as i debug it in the manager.
    The manager (Firrst) has a singleton.
     
  5. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Does it crash or deadlock?

    If the method is reading from the queue, should it not be peeking (outside the lock) with a view to dequeueing (inside the lock) rather than enqueueing?
     
  6. luckie12

    luckie12

    Joined:
    Aug 17, 2014
    Posts:
    165
    Well, i got help from someone, but on every example i see, they dequeue inside the lock, and im enqueing it..
     
  7. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Yes they would, but I was wondering if Dequeue would block if the queue was empty. But I think it throws rather than blocks so that is ok.

    Enqueue adds to the queue, yet the method is called "ReadMessage" which implies a Dequeue.

    So, to check, is it this message passing mechanism that is the stumbling point for you at the moment? If so, can you paste the code from the "WriteMessage" side as well.
     
  8. luckie12

    luckie12

    Joined:
    Aug 17, 2014
    Posts:
    165
    I'm sorry, its called ReadMessage because its reading the message gained from the network (web sockets) and then enqued into the queue:

    Code (CSharp):
    1.     public Networking(string protocol, string url, string port)
    2.     {
    3.         //ps = new Parser(lr);
    4.         ws = new WebSocket(protocol + "://" + url + ":" + port);
    5.         protocol = this.protocol;
    6.         url = this.url;
    7.         port = this.port;
    8.         ws.OnMessage += ReadMessage;
    9.     }
    Code (CSharp):
    1.     public void ReadMessage(object sender, MessageEventArgs e)
    2.     {
    3.         string message = e.Data;
    4.         Debug.Log(message);
    5.        lock (Firrst.Instance.Queue)
    6.         {
    7.             Firrst.Instance.Queue.Enqueue(e.Data);
    8.         }
    9.         Debug.Log(message);
    10.     }
     
  9. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
  10. luckie12

    luckie12

    Joined:
    Aug 17, 2014
    Posts:
    165
    i fixed the issue haha!, the problem was my singelton

    i did

    Code (CSharp):
    1.         if (Instance != null)
    2.         {
    3.             Instance = this;
    4.         }
    had to be
    Code (CSharp):
    1.         if (Instance == null)
    2.         {
    3.             Instance = this;
    4.         }
    Thanks for all yall help! ♥
     
    Doug_B likes this.