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);
}
}
}