Programmatically control Unity Game loop to sync with external hardware/software

We would like to run the Unity Game Loop in sync with external hardware and applications running on a different computer. We want to arrive at something that work similar (but does not have to be identical to this).

  1. Receive remote TCP packet with a list of new locations (etc.) for GameObjects [For low latency, would we put this in a FixedUpdate loop, set at a high Hz?] [Is this best done in a Manager Singleton?]
  2. Send these updates from this “singleton” to all game objects [One way might be to just have the object pick up the data in the Update cycle, which would happen after the fixedUpdate is done]. [Is a better idea to forget about the gameloop, and just use C# events to broadcast the updates to the gameobject attached scripts?] Each GameObject will then update its location
  3. Once all is stable (i.e. step #2 is completely done by all objects), we need to do measurements (scene read only) (with Raycast and LineCast) from each object to each other to see what is occluded and what is visible [Can we rely on LateUpdate to run afterwards, or should we avoid the game loop] [How do we know that all gameobjects have finished updating?]
  4. Finally we need to post the visibility results back via a TCP packet.

The overall goal here is to make all four steps run as fast (back-to-back) as possible, Best would be to be able to speed up the frame rate (or slow it down) based on when each phase is done. But we can live with a fixed 60Hz if needed.

Other questions, have to do with the Async nature of TCP (or UDP) clients inside of Unity, and the issues of not being able to use the API from a separate thread (e.g. the async results of the TCP receive]. Has anyone pointers to solutions to that?

We need no help writing the code, but the internal execution model of Unity3D at this level of detail is not clear in the manuals.

We think this has wide applicability for VR, AR, and various robot co-sync with games.

I came up with a very elegant solution for this problem. Thanks to some help from @DMGregory

First, I learned the truth about FixedUpdate. I hightly recommend this thread:

http://forum.unity3d.com/threads/the-truth-about-fixedupdate.231637/

That led me to realize that I should stick to the standard Unity stages of Update(), CoRoutines, LastUpdate, etc. and do everything by spinning the FrameRate as fast as possible.

Read these excellent arctiles on CoRoutines:

http://gamedev.stackexchange.com/questions/113096/how-to-not-freeze-the-main-thread-in-unity/113098#113098

http://stackoverflow.com/questions/12932306/how-does-startcoroutine-yield-return-pattern-really-work-in-unity

The outline of my approach is to:

Use Update() [read] and waitForEndOfFrame() [write] for my tcp work and putting the rest in co-routines and lastDone, I can effecting seperate the 4 phases the computation and get about 1500FPS of externally clocked simulation, SWIL work done. I am impressed. It all works in lock step with the hardware. Sweet.

My insight came when I thought of the problem as using the UnityGameEngine GameLoop as a big Co-Routine that runs in lock-step with the “frame rate” of external software and hardware.

public class Tools
{
    public static string timeStamp()
    {
        return string.Format("{0} - {1:H:mm:ss.ffffff}", Time.time, System.DateTime.Now);
    }
}

public class TargetScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(CoDo());
    }
    void Update()
    {
        Debug.Log(string.Format("{0}: {1} update: {2}", Time.frameCount, gameObject.name, Tools.timeStamp()));
    }
    IEnumerator CoDo()
    {
        while (true)
        {
            yield return null;
            Debug.Log(string.Format("{0}: {1} codo: {2}", Time.frameCount, gameObject.name, Tools.timeStamp()));
        }

    }
    void LateUpdate()
    {
        Debug.Log(string.Format("{0}: {1} late:   {2}", Time.frameCount, gameObject.name, Tools.timeStamp()));
    }
    IEnumerator Done()
    {
        while (true)
        {
            yield return new WaitForEndOfFrame();
            Debug.Log(string.Format("{0}: {1} done: {2}", Time.frameCount, gameObject.name, Tools.timeStamp()));
        }
    }
}