Skip to content

Commit

Permalink
bi-directional WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
benkuper committed Oct 21, 2020
1 parent ffb7e4b commit 999999d
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 37 deletions.
2 changes: 1 addition & 1 deletion Runtime/OSC/OSCMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public override void Append<T> (T value)
break;

default:
throw new Exception("Unsupported data type.");
throw new Exception("Unsupported data type : "+type.Name);
}

_typeTag += typeTag;
Expand Down
228 changes: 196 additions & 32 deletions Runtime/OSCQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,37 @@ public enum InfoType { Property, Field, Method };
public MethodInfo methodInfo;
}

[ExecuteInEditMode]
public class OSCQuery : MonoBehaviour
{
[Header("Network settings")]
public int localPort = 9010;
public string zeroconfName = "Unity-OSCQuery";
public string serverName = "Unity-OSCQuery";

[Header("Setup & Filters")]
public GameObject rootObject;
public enum ObjectFilterMode { All, Include, Exclude }
public ObjectFilterMode objectFilterMode;
public enum FilterMode { All, Include, Exclude }
public FilterMode objectFilterMode = FilterMode.Exclude;
public List<GameObject> filteredObjects;

public FilterMode componentFilterMode = FilterMode.Exclude;
public List<String> filteredComponentNames;
public bool excludeInternalUnityParams;
String[] internalUnityParamsNames = { "name", "tag", "useGUILayout", "runInEditMode", "enabled", "hideFlags" };
String[] internalUnityTransformNames = { "localEulerAngles", "right", "up", "forward", "hasChanged", "hierarchyCapacity" };
String[] acceptedParamTypes = { "System.String", "System.Char", "System.Boolean", "System.Int32", "System.Int64", "System.Int16", "System.UInt16", "System.Byte", "System.SByte", "System.Double", "System.Single", "UnityEngine.Vector2", "UnityEngine.Vector3", "UnityEngine.Quaternion", "UnityEngine.Color" };

HttpServer httpServer;

JSONObject queryData;
bool dataIsReady;

OSCReceiver receiver;

Dictionary<string, CompInfo> compInfoMap;

Dictionary<string, WSQuery> propQueryMap;
bool propQueryMapLock;

RegisterService zeroconfService;
RegisterService oscService;

Expand All @@ -80,13 +89,23 @@ void Awake()

private void OnEnable()
{
if (propQueryMap == null) propQueryMap = new Dictionary<string, WSQuery>();

if (filteredComponentNames.Count == 0)
{
filteredComponentNames.Add("MeshRenderer");
filteredComponentNames.Add("MeshFilter");
filteredComponentNames.Add("BoxCollider");
filteredComponentNames.Add("MeshCollider");
}

if (Application.isPlaying)
{
httpServer = new HttpServer(localPort);
httpServer.OnGet += handleHTTPRequest;

httpServer.Start();
if (httpServer.IsListening) Debug.Log("OSCQuery Server started on port " + localPort);
if (httpServer.IsListening) Debug.Log("OSCQuery Server started on port " + localPort);
else Debug.LogWarning("OSCQuery could not start on port " + localPort);

httpServer.AddWebSocketService("/", createWSQuery);
Expand All @@ -95,14 +114,14 @@ private void OnEnable()
receiver.Open(localPort);

oscService = new RegisterService();
oscService.Name = zeroconfName;
oscService.Name = serverName;
oscService.RegType = "_osc._udp";
oscService.ReplyDomain = "local.";
oscService.UPort = (ushort)localPort;
oscService.Register();

zeroconfService = new RegisterService();
zeroconfService.Name = zeroconfName;
zeroconfService.Name = serverName;
zeroconfService.RegType = "_oscjson._tcp";
zeroconfService.ReplyDomain = "local.";
zeroconfService.UPort = (ushort)localPort;
Expand All @@ -124,28 +143,67 @@ private void OnDisable()
// Update is called once per frame
void Update()
{
if (!dataIsReady)
if (Application.isPlaying)
{
rebuildDataTree();
dataIsReady = true;
if (!dataIsReady)
{
rebuildDataTree();
dataIsReady = true;
}

ProcessIncomingMessages();
}

//while(propQueryMapLock)
//{
//wait
//}
propQueryMapLock = true;
foreach (KeyValuePair<string, WSQuery> aqm in propQueryMap)
{
sendFeedback(aqm.Key, aqm.Value);
}
propQueryMapLock = false;

ProcessIncomingMessages();
}

private void handleHTTPRequest(object sender, HttpRequestEventArgs e)
{
var req = e.Request;
var response = e.Response;


dataIsReady = false;
while (!dataIsReady) { /* wait until data is rebuild */ }
JSONObject responseData = new JSONObject();

if (req.RawUrl.Contains("HOST_INFO"))
{
JSONObject extensions = new JSONObject();
extensions.SetField("ACCESS", true);
extensions.SetField("CLIPMODE", false);
extensions.SetField("CRITICAL", false);
extensions.SetField("RANGE", true);
extensions.SetField("TAGS", false);
extensions.SetField("TYPE", true);
extensions.SetField("UNIT", false);
extensions.SetField("VALUE", true);
extensions.SetField("LISTEN", true);

responseData.SetField("EXTENSIONS", extensions);
responseData.SetField("NAME", serverName);
responseData.SetField("OSC_PORT", localPort);
responseData.SetField("OSC_TRANSPORT", "UDP");
}
else
{
dataIsReady = false;
while (!dataIsReady) { /* wait until data is rebuild */ }
responseData = queryData;
}

byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryData.ToString(true));
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseData.ToString());
response.ContentType = "application/json";
response.ContentLength64 = buffer.Length;
response.Close(buffer, true);

}

WSQuery createWSQuery()
Expand All @@ -156,12 +214,37 @@ WSQuery createWSQuery()
return q;
}

private void wsMessageReceived(string message)
private void wsMessageReceived(WSQuery query, string message)
{
Debug.Log("Message received " + message);
JSONObject o = new JSONObject(message);
if (o.IsObject)
{
String command = o["COMMAND"].str;
String data = o["DATA"].str;
Debug.Log("Received Command " + command + " > " + data);

while (propQueryMapLock)
{
//wait
}
propQueryMapLock = true;

if (command == "LISTEN")
{
propQueryMap.Add(data, query);
}
else if (command == "IGNORE")
{
propQueryMap.Remove(data);
}

propQueryMapLock = false;
}

}

private void wsDataReceived(byte[] data)
private void wsDataReceived(WSQuery query, byte[] data)
{
Debug.Log("Data received " + data.Length + " bytes");
}
Expand Down Expand Up @@ -206,11 +289,12 @@ JSONObject getObjectData(GameObject go, string baseAddress = "")

foreach (Component comp in comps)
{
if (!checkFilteredComp(comp.GetType())) continue;

int dotIndex = comp.GetType().ToString().LastIndexOf(".");
string compType = comp.GetType().ToString().Substring(Mathf.Max(dotIndex + 1, 0));

if (!checkFilteredComp(compType)) continue;


string compAddress = baseAddress + "/" + compType;

JSONObject cco = new JSONObject();
Expand Down Expand Up @@ -241,11 +325,18 @@ JSONObject getObjectData(GameObject go, string baseAddress = "")
{
if (!info.CanWrite) continue;
string propType = info.PropertyType.ToString();
if (propType == "UnityEngine.Component") continue; //fix deprecation error
if (propType == "UnityEngine.GameObject") continue; //fix deprecation error
if (propType == "UnityEngine.Matrix4x4") continue; //fix deprecation error
if (propType == "UnityEngine.Transform") continue; //fix deprecation error
if (info.Name == "name" || info.Name == "tag") continue;
if (!acceptedParamTypes.Contains(propType)) continue;//
//if (propType == "UnityEngine.Component") continue; //fix deprecation error
//if (propType == "UnityEngine.GameObject") continue; //fix deprecation error
//if (propType == "UnityEngine.Matrix4x4") continue; //fix deprecation error
//if (propType == "UnityEngine.Transform") continue; //fix deprecation error
//if (propType == "UnityEngine.Mesh") continue; //fix deprecation error
if (excludeInternalUnityParams)
{
if (internalUnityParamsNames.Contains(info.Name)) continue;
if (compType == "Transform" && internalUnityTransformNames.Contains(info.Name)) continue;
}


RangeAttribute rangeAttribute = info.GetCustomAttribute<RangeAttribute>();
JSONObject io = getPropObject(info.PropertyType, info.GetValue(comp), rangeAttribute, false);
Expand Down Expand Up @@ -440,14 +531,16 @@ string SanitizeName(string niceName)

bool checkFilteredObject(GameObject go)
{
return objectFilterMode == ObjectFilterMode.All
|| (objectFilterMode == ObjectFilterMode.Include && filteredObjects.Contains(go))
|| (objectFilterMode == ObjectFilterMode.Exclude && !filteredObjects.Contains(go));
return objectFilterMode == FilterMode.All
|| (objectFilterMode == FilterMode.Include && filteredObjects.Contains(go))
|| (objectFilterMode == FilterMode.Exclude && !filteredObjects.Contains(go));
}

bool checkFilteredComp(Type type)
bool checkFilteredComp(String typeString)
{
return true;
return componentFilterMode == FilterMode.All
|| (componentFilterMode == FilterMode.Include && filteredComponentNames.Contains(typeString))
|| (componentFilterMode == FilterMode.Exclude && !filteredComponentNames.Contains(typeString));
}

void ProcessIncomingMessages()
Expand Down Expand Up @@ -520,8 +613,8 @@ void ProcessIncomingMessages()

case "UnityEngine.Color":
{
if(msg.Data.Count == 1) data = (Color)msg.Data[0];
else if(msg.Data.Count >= 3) data = new Color((float)msg.Data[0], (float)msg.Data[1], (float)msg.Data[2], msg.Data.Count > 3 ? (float)msg.Data[2] : 1.0f);
if (msg.Data.Count == 1) data = (Color)msg.Data[0];
else if (msg.Data.Count >= 3) data = new Color((float)msg.Data[0], (float)msg.Data[1], (float)msg.Data[2], msg.Data.Count > 3 ? (float)msg.Data[2] : 1.0f);
}
break;

Expand Down Expand Up @@ -570,5 +663,76 @@ void ProcessIncomingMessages()
}
}
}



void sendFeedback(string address, WSQuery query)
{
CompInfo info = compInfoMap[address];

object data = null;
if (info.propInfo != null) data = info.propInfo.GetValue(info.comp);
else if (info.fieldInfo != null) data = info.fieldInfo.GetValue(info.comp);

if (data != null)
{
OSCMessage m = new OSCMessage(address);

string dataType = data.GetType().Name;
switch (dataType)
{
case "Boolean":
{
bool val = (bool)data;
m.Append(val ? 1 : 0);
}
break;

case "Vector2":
{
Vector2 v = (Vector2)data;
m.Append(v.x);
m.Append(v.y);
}
break;

case "Vector3":
{
Vector3 v = (Vector3)data;
m.Append(v.x);
m.Append(v.y);
m.Append(v.z);
}
break;

case "Color":
{
Color color = (Color)data;
m.Append(color.r);
m.Append(color.g);
m.Append(color.b);
m.Append(color.a);
}
break;

case "Quaternion":
{
Vector3 v = ((Quaternion)data).eulerAngles;
m.Append(v.x);
m.Append(v.y);
m.Append(v.z);
}
break;

default:
if(info.type.IsEnum) m.Append(data.ToString());
else m.Append(data);
break;
}

Debug.Log("Send data here ! "+ m.BinaryData.Length+" bytes");
query.sendData(m.BinaryData);
}
}
}
}
20 changes: 16 additions & 4 deletions Runtime/WSQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,23 @@

public class WSQuery : WebSocketBehavior
{
public delegate void MessageEvent(string message);
public delegate void MessageEvent(WSQuery query,string message);
public MessageEvent messageReceived;

public delegate void DataEvent(byte[] data);
public delegate void DataEvent(WSQuery query, byte[] data);
public DataEvent dataReceived;


public void sendMessage(string message)
{
Send(message);
}

public void sendData(byte[] data)
{
Send(data);
}

protected override void OnOpen()
{
Debug.Log("Socket Opened ");
Expand All @@ -29,7 +40,8 @@ protected override void OnError(ErrorEventArgs e)
protected override void OnMessage(MessageEventArgs e)
{
var name = Context.QueryString["name"];
if (e.IsText) messageReceived?.Invoke(e.Data);
else if (e.IsBinary) dataReceived?.Invoke(e.RawData);
if (e.IsText) messageReceived?.Invoke(this, e.Data);
else if (e.IsBinary) dataReceived?.Invoke(this, e.RawData);
}

}

0 comments on commit 999999d

Please sign in to comment.