SendMessage ArgumentException error

Hello,
I am trying to use gameObject.SendMessage() when an event happens. However I get this message:

errorFound = true: System.ArgumentException: BroadcastMessage  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.

I am sending the SendMessage from a function within a C# script. A function (method) that is in JavaScript should be activated. It all works when it is inside Awake or Start… like it says it would… but I want it to be called when an event happens (button click, etc.). Please help.

Thanks in advance.

-Jake

Unity is not threadsafe. If it’s being called from an event, there’s a decent chance it’s in a background thread. You would have to manage that call and promote it to the main thread somehow.

For example, you could have a MonoBehaviour class that lets you queue up SendMessage calls (their targets, methods, and input parameters), and on its Update() method, you cycle through each queued SendMessage and invoke it.

EDIT: I whipped up a quick, untested example:

public class SendMessageContext
{
    public GameObject Target;
    public string MethodName;
    public object Value;
    public SendMessageOptions Options = SendMessageOptions.RequireReceiver;

    public SendMessageContext(GameObject target, string methodName, object value, SendMessageOptions options)
    {
        this.Target = target;
        this.MethodName = methodName;
        this.Value = value;
        this.Options = options;
    }
}

public class SendMessageHelper : MonoBehaviour
{
    private static Queue<SendMessageContext> QueuedMessages = new Queue<SendMessageContext>();
    public static void RegisterSendMessage(SendMessageContext context)
    {
        QueuedMessages.Enqueue(context);
    }

    private void Update()
    {
        while(QueuedMessages.Count > 0)
        {
            SendMessageContext context = QueuedMessages.Dequeue();
            context.Target.SendMessage(context.MethodName, context.Value, context.Options);
        }
    }
}

Which you would use like:

SendMessageContext context = new SendMessageContext(myTargetGameObject, "myMethod", "some data", SendMessageOptions.RequireReceiver);
SendMessageHelper.RegisterSendMessage(context);

Feel free to add more overloads to the various constructors/methods to make life easier (so you don’t have to keep sending a SendMessageOptions parameter). You’d also need to create a single instance of the SendMessageHelper in your scene and have it floating around.

EDITx2: better make it threadsafe since that was the whole point of this:

public class SendMessageHelper : MonoBehaviour
{
    private static Queue<SendMessageContext> QueuedMessages = new Queue<SendMessageContext>();
    public static void RegisterSendMessage(SendMessageContext context)
    {
        lock (QueuedMessages)
        {
            QueuedMessages.Enqueue(context);
        }
    }

    private void Update()
    {
        while(QueuedMessages.Count > 0)
        {
            SendMessageContext context = null;
            lock (QueuedMessages)
            {
                context = QueuedMessages.Dequeue();
            }

            context.Target.SendMessage(context.MethodName, context.Value, context.Options);
        }
    }
}

Thanks for the response. Could you explain (maybe show an example) of what you mean by “queue up SendMessage calls” in C#?
Thanks!
-Jake

I just did but it was an edit so I guess you missed it.

Thanks for the examples!

They helped out a LOT!