- Home /
SOLVED: Problem with SendMessage -- silently failing
I have this function in a JS script attached to my object:
function OnLoginFailed(reason:String){
Debug.Log("In on login failed");
_messageText = reason;
currentState = STATE.LoginFailed;
}
If I do a SendMessage on gameObject in my Awake it functions perfectly.
In my awake am putting a reference to the gameObject in a static list held by a C# class like this:
function Awake(){
NPHOS.registerListener(gameObject);
}
When the NPHOS object sees this particualr event it calls this code:
public void LoginFailed(string reason){
Debug.Log("Login failed");
fireEvent("OnLoginFailed",reason);
}
...
private static void fireEvent(string evt, object param = null){
foreach (GameObject gameObject in eventListeners){
if (param == null){
gameObject.SendMessage(evt);
} else {
Debug.Log("SendingMessage "+evt+" with "+param);
gameObject.SendMessage(evt,param);
}
}
}
I've traced through it and all that works, but the SendMessage seems to silently fail as the Javascript method never gets called.
Help?
Edit:
I seme to have tracked the issue down to something very bizarre occurring in my list handling where what comes back out of the list is not the same as what went in.
Can anyone see anything wrong with this list handling code?
private static List<GameObject> ListEventListeners(string evt){ List<GameObject> goList=null; if(!eventListenerDictionary.TryGetValue(evt,out goList)){ goList= new List<GameObject>(); eventListenerDictionary.Add(evt,goList); } return goList; }
public static void AddListener(string evt,GameObject obj){ ListEventListeners(evt).Add(obj);
Debug.Log("Object "+obj.name+" listening for "+evt); }
This is how I access the list later:
public static void Notify(string evt, object value = null){
Debug.Log("Sending notifications for "+evt);
List<GameObject> listeners = ListEventListeners(evt);
Debug.Log("Listeners list length="+listeners.Count);
foreach (GameObject gobj in listeners){
Debug.Log("here "+gobj.name);
gobj.SendMessage(evt,value, SendMessageOptions.RequireReceiver);
}
}
It appears to be hanging or otherwise silently blowing up on gobj.name. Im going to put in a null check to see if somehow gobj is null...
Edit: Nope not null. This is REALLY beginning to look like a race condition. Do I need to queue my messages and only deliver them at a specific point in time or on a specific thread?
Answer by Jeff-Kesselman · Dec 06, 2010 at 01:41 AM
I'm pretty sure this is the answer...
http://entitycrisis.blogspot.com/2010/08/safe-multithreading-in-unity3d.html
I'm going to have to re-architect a bit so there is a headless object in the world that queues and handles sending events only during Update()
YUP, Thats the answer. Have it working now.
Short story is that you pretty much can't touch ANY Unity GameObject or MonoBehaviour in ANY way from another thread. You need to queue any interraction and then pick it up and deal with it in that behaviour's Update() callback.
I'm about half way to a generic framework for taking asynchronous events and turning them into Unity messages. At some point maybe I'll clean it up and post it to the wiki.
Answer by pyro · Dec 06, 2010 at 12:11 AM
I've had some issues with Javascript picking up message sent by C#, try writing the receiver in C# too..
Ocuh. Iw as trying to avoid that as the receiver is on the app side whereas the rest is on the plugin side and I really wanted my plugin code to be app language agnostic :(
But ill try it just to prove thats the problem. If that IS the problem, its a serious Unity bug.
I'm not sure if this is good news or bad news, but re-writing the receiving object in C# evidenced exactly the same behavior.
Is it possible there is something about ti$$anonymous$$g here? The login event is asynchronous, are there times during which Send$$anonymous$$essage cannot be successfully called?
ins$$anonymous$$d of using Send$$anonymous$$essage couldn't you use GetComponent() and call the function directly?
the only thing I can think of is to be 100% sure you are sending it to the right gameobject, also try using the RequireReceiver option so it will give an error if nothing picked up the message
No because this is intended to be loosely coupled. When it starts receiving data there will likely be many different objects all listening. The caller wont know the names of those components.