Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

UnityOSC and calling methods from the main thread

Discussion in 'Scripting' started by Alex__, Sep 17, 2015.

  1. Alex__

    Alex__

    Joined:
    Mar 23, 2015
    Posts:
    5
    Hi,
    I want to control the 3D environment within Unity through OSC messages. I'm using this library: https://github.com/jorgegarcia/UnityOSC

    Connecting, sending and receiving works fine, but the example included in the TestScene is not the behavior I'm looking for. oscControl.cs is just updating the cube's size every frame by checking the value in the last received message.

    Basically, what I'll be doing is sending commands to trigger certain events. So I just need a simple eventhandler that checks for incoming messages, does some conditional logic and calls the right methods. The only method I've found so far is in OSCHandler.cs namely:
    void OnPacketReceived(OSCServer server, OSCPacket packet)
    Which can output the message's data just fine to the Debug.Log

    This is exactly what I need. The problem I have is that I don't know how to trigger the code from other gameobjects from within this method. I've tried using gameobject.find or making a public field for the corresponding object, but it keeps giving me errors that 'x can only be called from the main thread'.

    I don't understand Unity's scripting engine well enough yet to figure this out (or rather, how this library works?). So any help is appreciated.
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Put the data in a Queue and then process it in Update. Basically, Unity isn't thread safe so you can't manipulate things in the world from outside the main thread. Update always runs in the main thread so using a Queue or List allows you to marshal the data from the worker thread back to the main thread for processing.
     
  3. Alex__

    Alex__

    Joined:
    Mar 23, 2015
    Posts:
    5
    Ahh I had a hunch I'd need something like this. Kind of a pain but I guess it makes sense.
    I'm assuming this is the thing I need? http://www.codeproject.com/Articles/16838/The-Use-of-Queues-in-C

    My only question is: where do I declare this queue, inside oscHandler or oscControl ? And what's the best way to access it from the other script?
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I'd make it globally accessible.

    Code (csharp):
    1.  
    2. public class PacketProcessor : MonoBehaviour
    3. {
    4.     Queue<OSCPacket> packets = new Queue<OSCPacket>();
    5.  
    6.     static PacketProcessor instance;
    7.     public static PacketProcessor Instance
    8.     {
    9.         get
    10.         {
    11.              if (instance == null)
    12.              {
    13.                  var g = new GameObject("PacketProcessor");
    14.                   instance = g.AddComponent<PacketProcessor>();
    15.              }
    16.              return instance;
    17.         }
    18.     }
    19.  
    20.     public void EnqueuePacket(OSCPacket packet)
    21.     {
    22.         packets.Enqueue(packet);
    23.     }
    24.  
    25.     void Update()
    26.     {
    27.         while (packets.Peek() != null)
    28.         {
    29.             var packet = packets.Dequeue();
    30.             // do something with the packet
    31.         }
    32.     }
    33. }
    34.  
    Code (csharp):
    1.  
    2. void OnPacketReceived(OSCServer server, OSCPacket packet)
    3. {
    4.     PacketProcessor.Instance.EnqueuePacket(packet);
    5. }
    6.  
    Keep in mind nothing here would stop concurrent modification of the packets Queue so you may have to lock it in the EnqueuePacket and Update methods.