We are making a unity game that uses commands received at a tcp socket to handle actions at a certain calibration state of the game. A statemanager handles events raised by a socketmanager when new strings are received. This statemanager then has to fire a method on a gameobject that has been referenced to in a field at the start.
The problem we are facing now is that this object cannot be accessed by the thread handling these events. We get the following error:
ToString can only be called from the main thread. Constructors and field initializers will be executed from the loading thread when loading a scene.
At the line marked with THIS LINE GIVES THE ERROR
How does Unity handle threading with EventHandlers and how do we access this object?
Thanks in advance!
public class StateManager : MonoBehaviour {
private bool initialized;
private GameObject calibrationController;
void Start(){
InitializeEventHandler ();
}
void OnLevelWasLoaded(int level) {
if (level == 3) {
calibrationController = GameObject.FindGameObjectWithTag("CalibrationController");
Debug.Log ("calibrationController 1: " + calibrationController);
calibrationController.GetComponent<CalibrationController> ().NewState += NewCalibrationState;
calibrationController.GetComponent<CalibrationController>().setupCalibration();
}
}
private void InitializeEventHandler(){
GetComponent<GameSocket> ().NewCommand += NewCommandReceived;
}
private void NewCommandReceived(object sender, NewCommandEventArgs e){
HandleCommandReceived (e.Command);
}
private void NewCalibrationState(object sender, NewCalibrationStateEventArgs e)
{
HandleNewCalibrationState (e.State);
}
private void HandleCommandReceived(string command){
switch (command) {
case "startcalibrationcomplete":
Debug.Log ("startcalibrationcomplete");
Debug.Log ("calibrationController 2: " + calibrationController); THIS LINE GIVES THE ERROR !!!
Debug.Log(GameObject.FindGameObjectWithTag("CalibrationController"));
break;
default:
Debug.Log ("state10");
break;
}
}
private void HandleNewCalibrationState(string state){
switch (state) {
case "startcalibration":
GetComponent<GameSocket>().MySend("startcalibration");
// ...
break;
case "animationdone":
GetComponent<GameSocket>().MySend("animationdone");
break;
default:
Debug.Log ("state10");
break;
}
}
For future readers: It is impossible to call methods on gameobjects from the event handlers due to Unity's poor threading. I found a workaround by letting the event handlers set properties of a data script on an empty gameobject. The data on this script can be accessed from whichever gameobject i.e. in an update cycle.
UnityEvent
(which is marvellous) - Fattie