1
votes

I am using Unity3D. Here is my Asynchronous method:

private void Receive(IAsyncResult ar)
{
    try
    {
        IPEndPoint ipEndPoint = null;
        byte[] data = udpClient.EndReceive(ar, ref ipEndPoint);
        string receivedMessage = Encoding.UTF8.GetString(data);

        JsonData json = JsonConvert.DeserializeObject<JsonData>(receivedMessage);
        string prefix = json.header.Substring(0, 2);

        Debug.Log("UDP World: " + receivedMessage);

        if (prefix != "3x")
        {
            Debug.Log("Unknown packet: " + receivedMessage + "\n");
        }
        else
        {
            string header = json.header.Substring(2);
            int conId = json.connectionId;
            switch (header)
            {
                default:
                    Debug.Log("Unknown packet: " + receivedMessage + "\n");
                    break;
                case "001":
                    Debug.Log("Data received: " + receivedMessage + "\n");
                    break;
                case "002":
                    CharacterPosition position = new CharacterPosition();
                    position.x = float.Parse(json.data["position.x"].ToString());
                    position.y = float.Parse(json.data["position.y"].ToString());
                    position.z = float.Parse(json.data["position.z"].ToString());
                    Character.updateCharacterPosition(position, Convert.ToInt32(json.data["characterId"].ToString()), conId);
                    break;
                case "003":
                    ClientWorldServer.character.updateCharacterRotation(json.data, conId);
                    break;
            }
        }
    } catch (SocketException e)
    {
        Debug.Log("UDP Socket Exception: " + e);
    }
    udpClient.BeginReceive(Receive, null);
}

Here is the function which is not working corectly when called from Receive() :

public static void updateCharacterPosition(CharacterPosition position, int characterId, int cnnId)
{
    if (Character.SceneLoaded != true)
        return;
        Debug.Log("Position 2: X: " + position.x + " Y: " + position.y + " Z: " + position.z);
        Debug.Log("GameObject FIND: " + GameObject.Find("CharactersOnline").name);

    if (cnnId != ClientWorldServer.connectionId)
    {
        GameObject startPoint = GameObject.Find("CharactersOnline/" + characterId.ToString());
        GameObject endPoint = new GameObject();
        endPoint.transform.position = new Vector3(position.x, position.y, position.z);
        GameObject.Find("CharactersOnline/" + characterId.ToString()).transform.position = Vector3.Lerp(startPoint.transform.position, endPoint.transform.position, Time.deltaTime);

        //Updating Clients ram of the character's position
        Character.characterDetails[int.Parse(characterId.ToString())].characterPosition.x = position.x;
        Character.characterDetails[int.Parse(characterId.ToString())].characterPosition.y = position.y;
        Character.characterDetails[int.Parse(characterId.ToString())].characterPosition.z = position.z;
        //Destroy(endPoint);
    }
}

All I see in Unity's console is the output from:

Debug.Log("Position 2: X: " + position.x + " Y: " + position.y + " Z: " + position.z + " Character: " + characterId + " CnnID: " + cnnId);

With the Debug.Log shown above I can see that i have all the information needed. Everything in the Debug.Log is there. The next line:

Debug.Log("GameObject FIND: " + GameObject.Find("CharactersOnline").name);

seems to be the place where everything brakes. I do not receive any output from that line neither error whatsoever. It just looks like it stays there not giving any output or error.

When updateCharacterPosition is called from another method which is not Asynchronous everything inside updateCharacterPosition is working as indented.

Any idea why this strange behavior is occurring. How can I fix that so i can call updateCharacterPosition from Receive which is Async function?

1
Could be a null reference exception and then unity is grouping all the null reference exeptions together so they are hard to pick out from the log. I trip over the collapse errors feature all the time. - Leo Bartkus
Yes and it's not working. Any idea why ? The Gameobject is there. - Venelin
Is this called before Start completes? GameObjects that are not enabled and haven't started yet can't be found with GameObject.Find - Leo Bartkus
It's called way after Start is completed. - Venelin
@LeoBartkus also I do not receive error that the GameObject is not found. Any idea how to debug that ? - Venelin

1 Answers

1
votes

Try this: /* Attach this to any object in your scene, to make it work */

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MainThread : MonoBehaviour {

   class CallInfo
   {
     public Function func;
     public object parameter;
     public CallInfo(Function Func, object Parameter)
     {
       func = Func;
       parameter = Parameter;
     }
     public void Execute()
     {
       func(parameter);
     }
   }

   public delegate void Function(object parameter);
   public delegate void Func();

   static List<CallInfo> calls = new List<CallInfo>();
   static List<Func> functions = new List<Func>();

   static Object callsLock = new Object();
   static Object functionsLock = new Object();

   void Start()
   {
     calls = new List<CallInfo>();
     functions = new List<Func>();

     StartCoroutine(Executer());
   }

   public static void Call(Function Func, object Parameter)
   {
     lock(callsLock)
     {
       calls.Add(new CallInfo(Func, Parameter));
     }
   }
   public static void Call(Func func)
   {
     lock(functionsLock)
     {
       functions.Add(func);
     }
   }

   IEnumerator Executer()
   {
     while(true)
     {
       yield return new WaitForSeconds(0.01f);

       while(calls.Count > 0)
       {
         calls[0].Execute();
         lock(callsLock)
         {
           calls.RemoveAt(0);
         }
       }

       while(functions.Count > 0)
       {
         functions[0]();
         lock(functionsLock)
         {
           functions.RemoveAt(0);
         }
       }
     }
   }
}

Call Like This

MainThread.Call(YourFunction);
MainThread.Call(YourFunction, parameters);

I think your problem is that you are calling Unity method from another thread which is not allowed