I have a module for client socketing, it’s written in c#, to send messages and handle messages. I need to call this C# send message from js file. and that’s fine. I have a reference of this C# object in the js file.
but my problem is when I received messages from remote and need to call some different js functions from C# to handle different messages, I don’t know how to do this.
I can’t have a reference of js file in my C# file.
I use GameObject.SendMessage to call some function I got a error:“ToString can only be called from the main thread” .
You can call JS from C# or you can call C# from JS but you can’t do both with the same script as you’ve realised - you can’t order the scripts to make both work, because of compiling order. (One of them has to be a plugin or a standard asset, the other has to be in a later compiled script - check out the compilation order.
Your socket reception appears to not be happening on the main thread - no idea what the ToString is about as I can’t see your code.
So the only answer is the to do something on the main thread, invoked from the socket thread.
I do that using the script below:
#Loom.cs#
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;
public class Loom : MonoBehaviour
{
private static Loom _current;
private int _count;
public static Loom Current
{
get
{
if (_current == null)
{
var g = new GameObject("Loom");
_current = g.AddComponent<Loom>();
}
return _current;
}
}
private List<Action> _actions = new List<Action>();
public class DelayedQueueItem
{
public float time;
public Action action;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
public static void QueueOnMainThread(Action action, float time = 0f)
{
if (time != 0)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action});
}
}
else
{
lock (Current._actions)
{
Current._actions.Add(action);
}
}
}
public static void RunAsync(Action a)
{
var t = new Thread(RunAction);
t.Priority = System.Threading.ThreadPriority.AboveNormal;
t.Start(a);
}
private static void RunAction(object action)
{
((Action)action)();
}
void OnDisable()
{
if (_current == this)
{
_current = null;
}
}
// Update is called once per frame
void Update()
{
var actions = new List<Action>();
lock (_actions)
{
actions.AddRange(_actions);
_actions.Clear();
}
foreach (var a in actions)
{
a();
}
var delayList = new List<DelayedQueueItem>();
lock (_delayed)
{
delayList.AddRange(_delayed);
}
foreach (var delayed in delayList.Where(d=>d.time <= Time.time).ToList())
{
lock (_delayed)
{
_delayed.Remove(delayed);
}
delayed.action();
}
}
}
And use it by calling this (you’d put it in your socket reception code):
Loom.QueueOnMainThread( ()=>{
//Your send message here
});
You are likely mixing classes that do not extends monobehavior and classes that do, and I had the same problem. the issue was the following
It turned in my case that I was debugging a class, and so the ToString() was called internaly, so I removed my debug.Log() and it was better. the other issue I had then ( it’s all related I feel), is that I can comparing a class against null to see if it existed ( myClass != null) and that was also an issue in the same “stack of call”, so removed that and it now all works fine.