unity C#客户端与服务器程序

客户端和服务器公共的脚本

OSC.cs

// This is version 1.01(2015.05.27)
// Tested in Unity 4
// Most of the code is based on a library for the Make Controller Kit1/*
using UnityEngine;
using System;
using System.Collections;
using System.Threading;
using System.Text;
using System.IO;
*/
using System;
using System.IO;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using UnityEngine;/// \mainpage
/// \section Overview
/// The .NET Visual C# library for the Make Controller Kit is designed 
/// to make it as simple as possible for developers to integrate the 
/// Make Controller Kit into their desktop applications, offering the 
/// transparency that makes open source software so rewarding to work with.  
/// You can communicate with the Make Controller Kit from your applications 
/// over either an Ethernet or USB connection, or both.  This library is 
/// supplied both in source form and built, as MakeControllerOsc.dll
/// This document is a reference for MakeControllerOsc.
/// 
/// \section Communication
/// Messages to and from the board conform to the OSC (Open Sound Control) protocol.  
/// OSC is an open, transport-independent standard supported by an increasing 
/// number of environments and devices. 
/// 
/// \subsection OSCmessages OSC Messages
/// OSC messages are represented by the class OscMessage, and consist of two elements:
/// - An address string for the device on the board you韗e dealing with.
/// - A list of value(s) being sent to or from that device. The list of values is optional.
/// 
/// From the perspective of OSC addresses, the Make Controller Kit is organized into a hierarchy of two or three layers:
/// - subsystems ?classes of device, such as analog inputs, servo controllers, and digital outputs.
/// - devices ?the index of a specific device within a subsystem.  
/// If there is only one device in a subsystem, the device is not included in the OSC address.
/// - properties ?different devices have different properties, such as the value of an analog input, 
/// the position of a servo motor, or the state of an LED. 
/// 
/// OSC messages always begin with a slash, and use a slash to delimit each element in the address, 
/// so an example OSC address string would look like:
/// \code /subsystem/device/property \endcode
/// 
/// The second part of an OscMessage is a list of values to be sent to the specified address. 
/// The OSC types that are used by the Make Controller Kit for these values are integers, 
/// floats, and strings.  The values in this list are simply separated by spaces, and the 
/// list can be arbitrarily long.  Most devices on the Make Controller Kit expect only one value.  
/// For example, to set the position of servo 1, you might send a message which 
/// in string form might look like:
/// \code /servo/1/position 512 \endcode
/// 
/// This addressing scheme allows interactions with the board's various subsystems 
/// and properties, and most importantly, accommodates the possibility of future or 
/// custom devices on the board that have not yet been implemented or imagined.  
/// If somebody creates, for example, a GPS extension to the board, communicating 
/// with that device from this library is the same as for any other.  More details 
/// about OSC can be found at http://www.opensoundcontrol.org.
/// 
/// \section sendingdata Sending Data
/// As previously mentioned, the Make Controller Kit can communicate over both 
/// Ethernet and USB.  Messages are sent as packets, both over USB and UDP, and 
/// corresponding structures are used ?UsbPacket and UdpPacket.  Once you韛e created 
/// a packet, you can simply call its Send() method, with the OscMessage you韉 like to send.  
/// There are helper methods to create an OscMessage from a string, or you can pass in the OscMessage itself. 
/// 
/// For example, you might set up your UsbSend() routine to look something like:
/// \code public void usbSend(string text)
/// {
///     OscMessage oscM = OSC.StringToOscMessage(text);
///     oscUsb is an Osc object, connected to a UsbPacket object 
///     oscUsb.Send(oscM);
/// } \endcode
/// If your data is already in the form of an OscMessage, you can call oscUsb.Send() directly.
/// 
/// \section readingdata Reading Data
/// The Make Controller Kit must be polled in order to read data from it.  To do this, 
/// send an OscMessage with the address of the device you韉 like to read, but omit 
/// the list of values.  When the board receives an OscMessage with no value, 
/// it interprets that as a read request, and sends back an OscMessage with the 
/// current value at the appropriate address.
/// 
/// The .NET Make Controller Kit library conveniently provides handlers that will 
/// call back a given function when an OscMessage with a given address string is received.  
/// Your implementation could look something like:
/// \code// Set the handler in the constructor for a particular address
/// MyConstructor()
/// {
///     udpPacket = new UdpPacket();
///     oscUdp = new Osc(udpPacket);
///     // A thread is started when the Osc object is created to read 
///     // incoming messages.
///     oscUdp.SetAddressHandler("/analogin/0/value", Ain0Message);
/// }
///
/// // The method you specified as the handler will be called back when a 
/// // message with a matching address string comes back from the board.
/// public void AIn0Message(OscMessage oscMessage)
/// {
///     // write the message to a console, for example
///     mct.WriteLine("AIn0 > " + oscMessage.ToString() );
/// } \endcode
/// You could alternatively set a handler for all incoming messages by calling 
/// the SetAllMessageHandler() method in your setup, instead of SetAddressHandler().
/// 
/// /// <summary>
/// UdpPacket provides packetIO over UDP
/// </summary>
public class UDPPacketIO 
{private UdpClient Sender;private UdpClient Receiver;private bool socketsOpen;private string remoteHostName;private int remotePort;private int localPort;public UDPPacketIO(string hostIP, int remotePort, int localPort){RemoteHostName = hostIP;RemotePort = remotePort;LocalPort = localPort;socketsOpen = false;}~UDPPacketIO(){// latest time for this socket to be closedif (IsOpen()) {Debug.Log("closing udpclient listener on port " + localPort);Close();}}/// <summary>/// Open a UDP socket and create a UDP sender./// /// </summary>/// <returns>True on success, false on failure.</returns>public bool Open(){try{Sender = new UdpClient();Debug.Log("Opening OSC listener on port " + localPort);IPEndPoint listenerIp = new IPEndPoint(IPAddress.Any, localPort);Receiver = new UdpClient(listenerIp);socketsOpen = true;return true;}catch (Exception e){Debug.LogWarning("cannot open udp client interface at port "+localPort);Debug.LogWarning(e);}return false;}/// <summary>/// Close the socket currently listening, and destroy the UDP sender device./// </summary>public void Close(){    if(Sender != null)Sender.Close();if (Receiver != null){Receiver.Close();// Debug.Log("UDP receiver closed");}Receiver = null;socketsOpen = false;}public void OnDisable(){Close();}/// <summary>/// Query the open state of the UDP socket./// </summary>/// <returns>True if open, false if closed.</returns>public bool IsOpen(){return socketsOpen;}/// <summary>/// Send a packet of bytes out via UDP./// </summary>/// <param name="packet">The packet of bytes to be sent.</param>/// <param name="length">The length of the packet of bytes to be sent.</param>public void SendPacket(byte[] packet, int length){   if (!IsOpen())Open();if (!IsOpen())return;Sender.Send(packet, length, remoteHostName, remotePort);//Debug.Log("osc message sent to "+remoteHostName+" port "+remotePort+" len="+length);}/// <summary>/// Receive a packet of bytes over UDP./// </summary>/// <param name="buffer">The buffer to be read into.</param>/// <returns>The number of bytes read, or 0 on failure.</returns>public int ReceivePacket(byte[] buffer){if (!IsOpen())Open();if (!IsOpen())return 0;IPEndPoint iep = new IPEndPoint(IPAddress.Any, localPort);byte[] incoming = Receiver.Receive( ref iep );int count = Math.Min(buffer.Length, incoming.Length);System.Array.Copy(incoming, buffer, count);return count;}/// <summary>/// The address of the board that you're sending to./// </summary>public string RemoteHostName{get{ return remoteHostName; }set{ remoteHostName = value; }}/// <summary>/// The remote port that you're sending to./// </summary>public int RemotePort{get{ return remotePort; }set{ remotePort = value; }}/// <summary>/// The local port you're listening on./// </summary>public int LocalPort{get{return localPort; }set{ localPort = value; }}
}//namespace MakingThings
//{/// <summary>/// The OscMessage class is a data structure that represents/// an OSC address and an arbitrary number of values to be sent to that address./// </summary>public class OscMessage{/// <summary>/// The OSC address of the message as a string./// </summary>public string address;/// <summary>/// The list of values to be delivered to the Address./// </summary>public ArrayList values;public OscMessage(){values = new ArrayList();}public override string ToString() {StringBuilder s = new StringBuilder();s.Append(address);foreach( object o in values ){s.Append(" ");s.Append(o.ToString());}return s.ToString();}public int GetInt(int index) {if (values [index].GetType() == typeof(int) ) {int data = (int)values[index];if (Double.IsNaN(data)) return 0;return data;}else if (values[index].GetType() == typeof(float)) {int data = (int)((float)values[index]);if (Double.IsNaN(data)) return 0;return data;} else {Debug.Log("Wrong type");return 0;}}public float GetFloat(int index) {if (values [index].GetType() == typeof(int)) {float data = (int)values [index];if (Double.IsNaN(data)) return 0f;return data;} else if (values [index].GetType() == typeof(float)) {float data = (float)values[index];if (Double.IsNaN(data)) return 0f;return data;} else {Debug.Log("Wrong type");return 0f;}}public Vector3 GetVector3(int index){if (values[index].GetType() == typeof(Vector3)){Vector3 data = (Vector3)values[index];return data;}else{Debug.Log("Wrong type:" + values[index].GetType());Debug.Log(values[index]);return Vector3.zero;}}public string GetString(int index){if (values[index].GetType() == typeof(string)){string data = (string)values[index];return data;}else{Debug.Log("Wrong type");return null;}}}public delegate void OscMessageHandler( OscMessage oscM );/// <summary>/// The Osc class provides the methods required to send, receive, and manipulate OSC messages./// Several of the helper methods are static since a running Osc instance is not required for /// their use./// /// When instanciated, the Osc class opens the PacketIO instance that's handed to it and /// begins to run a reader thread.  The instance is then ready to service Send OscMessage requests /// and to start supplying OscMessages as received back./// /// The Osc class can be called to Send either individual messages or collections of messages/// in an Osc Bundle.  Receiving is done by delegate.  There are two ways: either submit a method/// to receive all incoming messages or submit a method to handle only one particular address./// /// Messages can be encoded and decoded from Strings via the static methods on this class, or/// can be hand assembled / disassembled since they're just a string (the address) and a list /// of other parameters in Object form. /// /// </summary>public class OSC : MonoBehaviour{public int inPort  = 6969;public string outIP = "127.0.0.1";public int outPort  = 6161;private UDPPacketIO OscPacketIO;Thread ReadThread;private bool ReaderRunning;private OscMessageHandler AllMessageHandler;Hashtable AddressTable;ArrayList messagesReceived;private object ReadThreadLock = new object();byte[] buffer;bool paused = false;#if UNITY_EDITORprivate void HandleOnPlayModeChanged(UnityEditor.PlayModeStateChange state) //FIX FOR UNITY POST 2017{// This method is run whenever the playmode state is changed.paused = UnityEditor.EditorApplication.isPaused;//print ("editor paused "+paused);// do stuff when the editor is paused.}
#endifvoid Awake() {//print("Opening OSC listener on port " + inPort);OscPacketIO = new UDPPacketIO(outIP, outPort, inPort);AddressTable = new Hashtable();messagesReceived = new ArrayList();buffer = new byte[1000];ReadThread = new Thread(Read);ReaderRunning = true;ReadThread.IsBackground = true;      ReadThread.Start();#if UNITY_EDITOR//UnityEditor.EditorApplication.playmodeStateChanged = HandleOnPlayModeChanged;UnityEditor.EditorApplication.playModeStateChanged += HandleOnPlayModeChanged;  //FIX FOR UNITY POST 2017
#endif}void OnDestroy() {Close();}/// <summary>/// Set the method to call back on when a message with the specified/// address is received.  The method needs to have the OscMessageHandler signature - i.e. /// void amh( OscMessage oscM )/// </summary>/// <param name="key">Address string to be matched</param>   /// <param name="ah">The method to call back on.</param>   public void SetAddressHandler(string key, OscMessageHandler ah){ArrayList al = (ArrayList)Hashtable.Synchronized(AddressTable)[key];if ( al == null) {al = new ArrayList();al.Add(ah);Hashtable.Synchronized(AddressTable).Add(key, al);} else {al.Add(ah);}/*OscMessageHandler h = (OscMessageHandler)Hashtable.Synchronized(AddressTable)[key];if (h == null)  Hashtable.Synchronized(AddressTable).Add(key, ah);else print ("there");*/}void OnApplicationPause(bool pauseStatus) {#if !UNITY_EDITORpaused = pauseStatus;print ("Application paused : " + pauseStatus);
#endif}void Update() {if ( messagesReceived.Count > 0 ) {//Debug.Log("received " + messagesReceived.Count + " messages");lock(ReadThreadLock) {foreach (OscMessage om in messagesReceived){if (AllMessageHandler != null)AllMessageHandler(om);ArrayList al = (ArrayList)Hashtable.Synchronized(AddressTable)[om.address];if ( al != null) {foreach (OscMessageHandler h in al) {h(om);}}}messagesReceived.Clear();}}}/// <summary>/// Make sure the PacketExchange is closed./// </summary>/// /*~OSC(){           Cancel();//Debug.LogError("~Osc");}*/public void Close(){//Debug.Log("Osc Cancel start");if (ReaderRunning){ReaderRunning = false;ReadThread.Abort();}if (OscPacketIO != null && OscPacketIO.IsOpen()){OscPacketIO.Close();OscPacketIO = null;print("Closed OSC listener");}}/// <summary>/// Read Thread.  Loops waiting for packets.  When a packet is received, it is /// dispatched to any waiting All Message Handler.  Also, the address is looked up and/// any matching handler is called./// </summary>private void Read(){try{while (ReaderRunning){int length = OscPacketIO.ReceivePacket(buffer);if (length > 0){lock(ReadThreadLock) {if ( paused == false ) {ArrayList newMessages = OSC.PacketToOscMessages(buffer, length);messagesReceived.AddRange(newMessages);}}}elseThread.Sleep(5);}}catch (Exception e){Debug.Log("ThreadAbortException"+e);}finally{}}/// <summary>/// Send an individual OSC message.  Internally takes the OscMessage object and /// serializes it into a byte[] suitable for sending to the PacketIO./// </summary>/// <param name="oscMessage">The OSC Message to send.</param>   public void Send( OscMessage oscMessage ){byte[] packet = new byte[1024];int length = OSC.OscMessageToPacket( oscMessage, packet, 1000 );OscPacketIO.SendPacket( packet, length);}/// <summary>/// Sends a list of OSC Messages.  Internally takes the OscMessage objects and /// serializes them into a byte[] suitable for sending to the PacketExchange./// </summary>/// <param name="oms">The OSC Message to send.</param>   public void Send(ArrayList oms){byte[] packet = new byte[1000];int length = OSC.OscMessagesToPacket(oms, packet, 1000);OscPacketIO.SendPacket(packet, length);}/// <summary>/// Set the method to call back on when any message is received./// The method needs to have the OscMessageHandler signature - i.e. void amh( OscMessage oscM )/// </summary>/// <param name="amh">The method to call back on.</param>   public void SetAllMessageHandler(OscMessageHandler amh){AllMessageHandler = amh;}/// <summary>/// Creates an OscMessage from a string - extracts the address and determines each of the values. /// </summary>/// <param name="message">The string to be turned into an OscMessage</param>/// <returns>The OscMessage.</returns>public static OscMessage StringToOscMessage(string message){OscMessage oM = new OscMessage();Console.WriteLine("Splitting " + message);string[] ss = message.Split(new char[] { ' ' });IEnumerator sE = ss.GetEnumerator();if (sE.MoveNext())oM.address = (string)sE.Current;while ( sE.MoveNext() ){string s = (string)sE.Current;// Console.WriteLine("  <" + s + ">");if (s.StartsWith("\"")){StringBuilder quoted = new StringBuilder();bool looped = false;if (s.Length > 1)quoted.Append(s.Substring(1));elselooped = true;while (sE.MoveNext()){string a = (string)sE.Current;// Console.WriteLine("    q:<" + a + ">");if (looped)quoted.Append(" ");if (a.EndsWith("\"")){quoted.Append(a.Substring(0, a.Length - 1));break;}else{if (a.Length == 0)quoted.Append(" ");elsequoted.Append(a);}looped = true;}oM.values.Add(quoted.ToString());}else{if (s.Length > 0){try{int i = int.Parse(s);// Console.WriteLine("  i:" + i);oM.values.Add(i);}catch{try{float f = float.Parse(s);// Console.WriteLine("  f:" + f);oM.values.Add(f);}catch{// Console.WriteLine("  s:" + s);oM.values.Add(s);}}}}}return oM;}/// <summary>/// Takes a packet (byte[]) and turns it into a list of OscMessages./// </summary>/// <param name="packet">The packet to be parsed.</param>/// <param name="length">The length of the packet.</param>/// <returns>An ArrayList of OscMessages.</returns>public static ArrayList PacketToOscMessages(byte[] packet, int length){ArrayList messages = new ArrayList();ExtractMessages(messages, packet, 0, length);return messages;}/// <summary>/// Puts an array of OscMessages into a packet (byte[])./// </summary>/// <param name="messages">An ArrayList of OscMessages.</param>/// <param name="packet">An array of bytes to be populated with the OscMessages.</param>/// <param name="length">The size of the array of bytes.</param>/// <returns>The length of the packet</returns>public static int OscMessagesToPacket(ArrayList messages, byte[] packet, int length){int index = 0;if (messages.Count == 1)index = OscMessageToPacket((OscMessage)messages[0], packet, 0, length);else{// Write the first bundle bitindex = InsertString("#bundle", packet, index, length);// Write a null timestamp (another 8bytes)int c = 8;while (( c-- )>0)packet[index++]++;// Now, put each message preceded by it's lengthforeach (OscMessage oscM in messages){int lengthIndex = index;index += 4;int packetStart = index;index = OscMessageToPacket(oscM, packet, index, length);int packetSize = index - packetStart;packet[lengthIndex++] = (byte)((packetSize >> 24) & 0xFF);packet[lengthIndex++] = (byte)((packetSize >> 16) & 0xFF);packet[lengthIndex++] = (byte)((packetSize >> 8) & 0xFF);packet[lengthIndex++] = (byte)((packetSize) & 0xFF);}}return index;}/// <summary>/// Creates a packet (an array of bytes) from a single OscMessage./// </summary>/// <remarks>A convenience method, not requiring a start index.</remarks>/// <param name="oscM">The OscMessage to be returned as a packet.</param>/// <param name="packet">The packet to be populated with the OscMessage.</param>/// <param name="length">The usable size of the array of bytes.</param>/// <returns>The length of the packet</returns>public static int OscMessageToPacket(OscMessage oscM, byte[] packet, int length){return OscMessageToPacket(oscM, packet, 0, length);}/// <summary>/// Creates an array of bytes from a single OscMessage.  Used internally./// </summary>/// <remarks>Can specify where in the array of bytes the OscMessage should be put.</remarks>/// <param name="oscM">The OscMessage to be turned into an array of bytes.</param>/// <param name="packet">The array of bytes to be populated with the OscMessage.</param>/// <param name="start">The start index in the packet where the OscMessage should be put.</param>/// <param name="length">The length of the array of bytes.</param>/// <returns>The index into the packet after the last OscMessage.</returns>private static int OscMessageToPacket(OscMessage oscM, byte[] packet, int start, int length){int index = start;index = InsertString(oscM.address, packet, index, length);//if (oscM.values.Count > 0){StringBuilder tag = new StringBuilder();tag.Append(",");int tagIndex = index;index += PadSize(2 + oscM.values.Count);foreach (object o in oscM.values){if (o is int){int i = (int)o;tag.Append("i");packet[index++] = (byte)((i >> 24) & 0xFF);packet[index++] = (byte)((i >> 16) & 0xFF);packet[index++] = (byte)((i >> 8) & 0xFF);packet[index++] = (byte)((i) & 0xFF);}else{if (o is float){float f = (float)o;tag.Append("f");byte[] buffer = new byte[4];MemoryStream ms = new MemoryStream(buffer);BinaryWriter bw = new BinaryWriter(ms);bw.Write(f);packet[index++] = buffer[3];packet[index++] = buffer[2];packet[index++] = buffer[1];packet[index++] = buffer[0];}else{if (o is string){tag.Append("s");index = InsertString(o.ToString(), packet, index, length);}else{if (o is Vector3){Vector3 v = (Vector3)o;tag.Append("v");byte[] buff = new byte[sizeof(float) * 3];Buffer.BlockCopy(BitConverter.GetBytes(v.x), 0, buff, 0 * sizeof(float), sizeof(float));Buffer.BlockCopy(BitConverter.GetBytes(v.y), 0, buff, 1 * sizeof(float), sizeof(float));Buffer.BlockCopy(BitConverter.GetBytes(v.z), 0, buff, 2 * sizeof(float), sizeof(float));packet[index++] = buff[0];packet[index++] = buff[1];packet[index++] = buff[2];packet[index++] = buff[3];packet[index++] = buff[4];packet[index++] = buff[5];packet[index++] = buff[6];packet[index++] = buff[7];packet[index++] = buff[8];packet[index++] = buff[9];packet[index++] = buff[10];packet[index++] = buff[11];}else{tag.Append("?");}}}}}InsertString(tag.ToString(), packet, tagIndex, length);}return index;}/// <summary>/// Receive a raw packet of bytes and extract OscMessages from it.  Used internally./// </summary>/// <remarks>The packet may contain a OSC message or a bundle of messages.</remarks>/// <param name="messages">An ArrayList to be populated with the OscMessages.</param>/// <param name="packet">The packet of bytes to be parsed.</param>/// <param name="start">The index of where to start looking in the packet.</param>/// <param name="length">The length of the packet.</param>/// <returns>The index after the last OscMessage read.</returns>private static int ExtractMessages(ArrayList messages, byte[] packet, int start, int length){int index = start;switch ( (char)packet[ start ] ){case '/':index = ExtractMessage( messages, packet, index, length );break;case '#':string bundleString = ExtractString(packet, start, length);if ( bundleString == "#bundle" ){// skip the "bundle" and the timestampindex+=16;while ( index < length ){int messageSize = ( packet[index++] << 24 ) + ( packet[index++] << 16 ) + ( packet[index++] << 8 ) + packet[index++];/*int newIndex = */ExtractMessages( messages, packet, index, length ); index += messageSize;}            }break;}return index;}/// <summary>/// Extracts a messages from a packet./// </summary>/// <param name="messages">An ArrayList to be populated with the OscMessage.</param>/// <param name="packet">The packet of bytes to be parsed.</param>/// <param name="start">The index of where to start looking in the packet.</param>/// <param name="length">The length of the packet.</param>/// <returns>The index after the OscMessage is read.</returns>private static int ExtractMessage(ArrayList messages, byte[] packet, int start, int length){OscMessage oscM = new OscMessage();oscM.address = ExtractString(packet, start, length);int index = start + PadSize(oscM.address.Length+1);string typeTag = ExtractString(packet, index, length);index += PadSize(typeTag.Length + 1);//oscM.values.Add(typeTag);foreach (char c in typeTag){switch (c){case ',':break;case 's':{string s = ExtractString(packet, index, length);index += PadSize(s.Length + 1);oscM.values.Add(s);break;}case 'i':{int i = ( packet[index++] << 24 ) + ( packet[index++] << 16 ) + ( packet[index++] << 8 ) + packet[index++];oscM.values.Add(i);break;}case 'f':{byte[] buffer = new byte[4];buffer[3] = packet[index++];buffer[2] = packet[index++];buffer[1] = packet[index++];buffer[0] = packet[index++];MemoryStream ms = new MemoryStream(buffer);BinaryReader br = new BinaryReader(ms);float f = br.ReadSingle();oscM.values.Add(f);break;}case 'v':{byte[] buffer = new byte[sizeof(float) * 3];buffer[0] = packet[index++];buffer[1] = packet[index++];buffer[2] = packet[index++];buffer[3] = packet[index++];buffer[4] = packet[index++];buffer[5] = packet[index++];buffer[6] = packet[index++];buffer[7] = packet[index++];buffer[8] = packet[index++];buffer[9] = packet[index++];buffer[10] = packet[index++];buffer[11] = packet[index++];Vector3 vect = Vector3.zero;vect.x = BitConverter.ToSingle(buffer, 0 * sizeof(float));vect.y = BitConverter.ToSingle(buffer, 1 * sizeof(float));vect.z = BitConverter.ToSingle(buffer, 2 * sizeof(float));oscM.values.Add(vect);break;}}}messages.Add( oscM );return index;}/// <summary>/// Removes a string from a packet.  Used internally./// </summary>/// <param name="packet">The packet of bytes to be parsed.</param>/// <param name="start">The index of where to start looking in the packet.</param>/// <param name="length">The length of the packet.</param>/// <returns>The string</returns>private static string ExtractString(byte[] packet, int start, int length){StringBuilder sb = new StringBuilder();int index = start;while (packet[index] != 0 && index < length)sb.Append((char)packet[index++]);return sb.ToString();}private static string Dump(byte[] packet, int start, int length){StringBuilder sb = new StringBuilder();int index = start;while (index < length)sb.Append(packet[index++]+"|");return sb.ToString();}/// <summary>/// Inserts a string, correctly padded into a packet.  Used internally./// </summary>/// <param name="string">The string to be inserted</param>/// <param name="packet">The packet of bytes to be parsed.</param>/// <param name="start">The index of where to start looking in the packet.</param>/// <param name="length">The length of the packet.</param>/// <returns>An index to the next byte in the packet after the padded string.</returns>private static int InsertString(string s, byte[] packet, int start, int length){int index = start;foreach (char c in s){packet[index++] = (byte)c;if (index == length)return index;}packet[index++] = 0;int pad = (s.Length+1) % 4;if (pad != 0){pad = 4 - pad;while (pad-- > 0)packet[index++] = 0;}return index;}/// <summary>/// Takes a length and returns what it would be if padded to the nearest 4 bytes./// </summary>/// <param name="rawSize">Original size</param>/// <returns>padded size</returns>private static int PadSize(int rawSize){int pad = rawSize % 4;if (pad == 0)return rawSize;elsereturn rawSize + (4 - pad);}}
//}

客户端或服务器1设置

Sender.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class Sender : MonoBehaviour
{public OSC oscHandler;public GameObject cube;void Start(){Application.runInBackground = true;}void Update(){Hello();}public void Hello(){OscMessage msg = new OscMessage();msg.address = "/sayhello";msg.values.Add(1);msg.values.Add(2.0f);msg.values.Add(new Vector3(0.1f, 0.2f, 0.3f));msg.values.Add("hello");//将物体的位姿发送过去msg.values.Add(cube.transform.position);msg.values.Add(cube.transform.rotation.x);msg.values.Add(cube.transform.rotation.y);msg.values.Add(cube.transform.rotation.z);msg.values.Add(cube.transform.rotation.w);oscHandler.Send(msg);}}

客户端或服务器2设置

Receiver.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Receiver : MonoBehaviour
{public OSC oscHandler;public GameObject moveCube; void Start(){Application.runInBackground = true;oscHandler.SetAddressHandler("/sayhello", Hello);}void Update(){//oscHandler.SetAddressHandler("/sayhello", Hello);}void Hello(OscMessage msg){int x = msg.GetInt(0);float y = msg.GetFloat(1);Vector3 z = msg.GetVector3(2);string w = msg.GetString(3);//接收物体的位姿moveCube.transform.position =  msg.GetVector3(4);moveCube.transform.rotation = new Quaternion(msg.GetFloat(5), msg.GetFloat(6), msg.GetFloat(7), msg.GetFloat(8));Debug.Log(x);Debug.Log(y);Debug.Log(z);Debug.Log(w);//Debug.Log(moveCube.transform.rotation);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/78734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Furion api npm web vue混合开发

Furion api npm web vue混合开发 Furion-api项目获取swagger.json文件复制json制作ts包删除非.ts文件上传到npm获取npm包引用 Furion-api项目获取swagger.json文件 使用所有接口合并的配置文件 复制json制作ts包 https://editor.swagger.io 得到 typescript-axios-clien…

怎么科学管理固定资产呢

在当今的商业环境中&#xff0c;固定资产的管理是企业成功的关键因素之一。然而&#xff0c;传统的固定资产管理方法往往过于繁琐&#xff0c;缺乏创新&#xff0c;导致资源的浪费和效率的低下。因此&#xff0c;我们需要一种新的、更加科学的方法来管理我们的固定资产。本文将…

C++多线程的用法(包含线程池小项目)

一些小tips: 编译命令如下&#xff1a; g 7.thread_pool.cpp -lpthread 查看运行时间&#xff1a; time ./a.out 获得本进程的进程id&#xff1a; this_thread::get_id() 需要引入的库函数有&#xff1a; #include<thread> // 引入线程库 #include<mutex> //…

Ui自动化测试上传文件方法都在这里了 ~

前言 实施UI自动化测试的时候&#xff0c;经常会遇见上传文件的操作&#xff0c;那么对于上传文件你知道几种方法呢&#xff1f;今天我们就总结一下几种常用的上传文件的方法&#xff0c;并分析一下每个方法的优点和缺点以及哪种方法效率&#xff0c;稳定性更高 被测HTML代码…

睿趣科技:抖音开店前期需要准备什么

抖音作为全球最受欢迎的短视频平台之一&#xff0c;已经成为了许多年轻人的创业和赚钱的机会。如果你计划在抖音上开店&#xff0c;那么在正式开业之前&#xff0c;有一些重要的准备工作是必不可少的。下面就是抖音开店前期需要准备的关键步骤和注意事项。 确定你的目标和产品&…

Matlab图像处理-三原色

三原色 根据详细的实验结果&#xff0c;人眼中负责颜色感知的细胞中约有65%对红光敏感&#xff0c;33%对绿光敏感&#xff0c;只有2%对蓝光敏感。正是人眼的这些吸收特性决定了所看到的彩色是一般所谓的原色红&#xff08;R&#xff09;、绿&#xff08;G&#xff09;和蓝&…

动态渲染 echarts 饼图(vue 2 + axios + Springboot)

目录 前言1. 项目搭建1.1. 前端1.2. 后端 2. 后端数据渲染前端2.1 补充1&#xff1a;在 vue 中使用 axios2.2. 补充2&#xff1a;Springboot 处理跨域问题2.3. 修改前端代码2.3.1 修改饼图样式2.3.2 调用后台数据渲染饼图2.3.3 改造成内外两个圈 前言 因为上文中提到的需求就是…

内网隧道代理技术(二十五)之 ICMP隧道反弹SHELL

ICMP隧道反弹SHELL ICMP隧道原理 由于ICMP报文自身可以携带数据,而且ICMP报文是由系统内核处理的,不占用任何端口,因此具有很高的隐蔽性。把数据隐藏在ICMP数据包包头的data字段中,建立隐蔽通道,可以实现绕过防火墙和入侵检测系统的阻拦。 ICMP隧道有以下的优点: ICMP…

腾讯云4核8G服务器选CVM还是轻量比较好?价格对比

腾讯云4核8G云服务器可以选择轻量应用服务器或CVM云服务器标准型S5实例&#xff0c;轻量4核8G12M服务器446元一年&#xff0c;CVM S5云服务器935元一年&#xff0c;相对于云服务器CVM&#xff0c;轻量应用服务器性价比更高&#xff0c;轻量服务器CPU和CVM有区别吗&#xff1f;性…

博客系统(升级(Spring))(四)(完)基本功能(阅读,修改,添加,删除文章)(附带项目)

博客系统 (三&#xff09; 博客系统博客主页前端后端个人博客前端后端显示个人文章删除文章 修改文章前端后端提取文章修改文章 显示正文内容前端后端文章阅读量功能 添加文章前端后端 如何使用Redis项目地点&#xff1a; 博客系统 博客系统是干什么的&#xff1f; CSDN就是一…

数字化转型对企业有哪些优势?

数字化转型为企业提供了众多优势&#xff0c;帮助他们在日益数字化的世界中保持竞争力、敏捷性和响应能力。以下是一些主要优势&#xff1a; 1.提高效率和生产力&#xff1a; 重复性任务和流程的自动化可以减少人为错误&#xff0c;并使员工能够专注于更具战略性的任务。简化…

Apache Linki 1.3.1+DataSphereStudio+正常启动+微服务+端口号

我使用的是一键部署容器化版本&#xff0c;官方文章 默认会启动6个 Linkis 微服务&#xff0c;其中下图linkis-cg-engineconn服务为运行任务才会启动,一共七个 LINKIS-CG-ENGINECONN:38681 LINKIS-CG-ENGINECONNMANAGER:9102 引擎管理服务 LINKIS-CG-ENTRANCE:9104 计算治理入…

Vue开发小注意点

改bug 更改了配置项啥的&#xff0c;保存刷新发现没变&#xff0c;那就重启项目&#xff01;&#xff01;&#xff01;&#xff01; binding.value 和 e.target.value binding.value Day5 指令的值 e.target.value Day4 表单组件封装 binding.value 和 e.target.valu…

plt函数显示图片 在图片上画边界框 边界框坐标转换

一.读取图片并显示图片 %matplotlib inline import torch from d2l import torch as d2l读取图片 image_path ../data/images/cat_dog_new.jpg # 创建画板 figure d2l.set_figsize() image d2l.plt.imread(image_path) d2l.plt.imshow(image);二.给出一个(x左上角,y左上角,…

使用Git把项目上传到Gitee的详细步骤

1.到Git官网下载并安装 2.到Gitee官网进行注册&#xff0c;然后在Gitee中新建一个远程仓库 3.设置远程仓库的参数 4.返回Gitee查看仓库是否生成成功 5.新建一个文件夹作为你的本地仓库 6.将新建好的文件夹初始化成本地仓库 第一步&#xff1a;右键点击刚创建的本地仓库&#…

小程序实现一个 倒计时组件

小程序实现一个 倒计时组件 需求背景 要做一个倒计时&#xff0c;可能是天级别&#xff0c;也可能是日级别&#xff0c;时级别&#xff0c;而且每个有效订单都要用&#xff0c;就做成组件了 效果图 需求分析 需要一个未来的时间戳&#xff0c;或者在服务度直接下发一个未来…

NeuroFlash:AI文章写作与生成工具

【产品介绍 ​ 】 名称 NeuroFlash 上线时间 2015 具体描述 Neuroflash是一款基于人工智能的文本和图像生成器&#xff0c;可以帮助用户快速创建高质量的内容。Neuroflash拥有超过100种短文和长文的文本类型&#xff0c;涵盖了各种营销场景和需求。只需要输入简单的指示&#…

最新ChatGPT网站源码+支持GPT4.0+支持Midjourney绘画+支持国内全AI模型

一、智能创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&…

Debian12系统下LAMP环境中Nubuilder4.5的安装

一、环境搭建 按照官方的说法&#xff0c;Apache2和Nginx都可以的&#xff0c;实际上&#xff0c;你最好直接按照 Mariadb\Apache2\Php8.2 这个顺序&#xff0c;搭建LAMP环境较好。不然各种调试&#xff0c;还不一定能够成功。 相关搭建方法&#xff0c;属于一般操作&#xf…

js中如何判断一个变量是否为数字类型?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐使用Number.isNaN()方法⭐使用正则表达式⭐使用isNaN()函数⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个…