Tanoda
TanodaServer.cs
Go to the documentation of this file.
1using GILES.Interface;
3using Newtonsoft.Json;
4using System;
5using System.Collections;
6using System.Collections.Generic;
7using System.IO;
8using System.Linq;
9using System.Net;
10using System.Net.Sockets;
11using System.Runtime.InteropServices;
12using System.Text;
13using System.Threading;
14#if DANA
15using TriLib;
16#endif
17using UnityEngine;
18using System.Diagnostics;
19using Debug = UnityEngine.Debug;
20
21public class TanodaServer : MonoBehaviour
22{
23#if DANA
24
25 public List<GameObject> SendPoseObjects;
26 public List<SendPose> SendPoseObjectsNoChildren;
27
28 [Serializable]
29 public struct SendPose
30 {
31 public bool AsLocal;
32 public GameObject GO;
33
34 }
35
36 const ushort PORT_NO = 42069;
37 private TcpListener listener;
38 private Thread worker;
39 private List<Socket> sockets;
40 private List<Thread> threads;
41
42 private object[] lastLoadedObjects;
43 private string modelName;
44 private HttpServer fileServer;
45 private string requestedFile;
46 private SerializePose sp;
47
48 [DllImport("kernel32.dll")]
49 [return: MarshalAs(UnmanagedType.Bool)]
50 static extern bool AllocConsole();
51
52 [DllImport("kernel32.dll", SetLastError = true)]
53 static extern bool AttachConsole(int pid);
54 [DllImport("kernel32", SetLastError = true)]
55 static extern bool FreeConsole();
56
57
58 void Start()
59 {
60 sp = gameObject.AddComponent<SerializePose>();
61#if DEVELOPMENT_BUILD
62 AllocConsole();
63#endif
64 var stdout = Console.OpenStandardOutput();
65 var sw = new System.IO.StreamWriter(stdout, Encoding.GetEncoding("ISO-8859-1"));
66 sw.AutoFlush = true;
67 Console.InputEncoding = Encoding.GetEncoding("ISO-8859-1");
68 Console.OutputEncoding = Encoding.GetEncoding("ISO-8859-1");
69 Console.SetOut(sw);
70 Console.SetError(sw);
71 DrawLogo();
72 sockets = new List<Socket>();
73 threads = new List<Thread>();
74 listener = new TcpListener(IPAddress.Any, PORT_NO);
75 listener.Start();
76 worker = new Thread(WaitingForClient);
77 worker.Start();
78
79 StartCoroutine(NetworkUpdate());
80
81 fileServer = new HttpServer();
82 fileServer.Run();
83 }
84
85 private IEnumerator NetworkUpdate()
86 {
87 while (true)
88 {
89 yield return new WaitForSeconds(0.1f);
90
91 foreach (var go in SendPoseObjects)
92 {
93 SendMsgToAllClients("{POSE}", sp.PoseToByteArray(go, false), go.name);
94 }
95 foreach (var go in SendPoseObjectsNoChildren)
96 {
97 SendMsgToAllClients("{POSE}", sp.TransformToByteArray(go.GO, go.AsLocal), go.GO.name);
98 }
99 }
100 }
101
102 private void OnDestroy()
103 {
104 FreeConsole();
105 foreach (var t in threads)
106 {
107 t.Abort();
108 }
109 }
110
111 public void WaitingForClient()
112 {
113 Console.WriteLine("WaitingForClient started");
114 while (true)
115 {
116 // Accept will block until someone connects
117 Socket sckt = listener.AcceptSocket();
118
119 Console.WriteLine("Client connected: " + sckt.RemoteEndPoint.ToString());
120
121 Thread td = new Thread(new ThreadStart(ReadSocket));
122
123 sockets.Add(sckt);
124 threads.Add(td);
125 td.Start();
126 }
127 }
128
129 public void SendMsgToAllClients(string msg)
130 {
131
132 var bytearray = Encoding.GetEncoding("ISO-8859-1").GetBytes(msg);
133 foreach (var s in sockets.ToArray())
134 {
135 try
136 {
137 if (s.Connected)
138 s.Send(bytearray);
139 }
140 catch (SocketException)
141 {
142 }
143 }
144 }
145 public void SendMsgToAllClients(string tag, string msg, string ID)
146 {
147
148 var bytearray = Encoding.GetEncoding("ISO-8859-1").GetBytes(tag + ID + ";" + msg + "{EOS}");
149
150 foreach (var s in sockets.ToArray())
151 {
152 try
153 {
154 if (s.Connected)
155 s.Send(bytearray);
156 }
157 catch (SocketException)
158 {
159 }
160 }
161 }
162 public void SendMsgToAllClients(string tag, byte[] array, string ID = "")
163 {
164 foreach (var s in sockets.ToArray())
165 {
166 var IDByte = (Encoding.GetEncoding("ISO-8859-1").GetBytes(ID));
167 var TagByte = (Encoding.GetEncoding("ISO-8859-1").GetBytes(tag));
168 var combinedArray = Combine(new byte[] { (byte)TagByte.Length }, TagByte, new byte[] { (byte)IDByte.Length }, IDByte, array);
169 var convertedArray = Convert.ToBase64String(combinedArray);
170
171 try
172 {
173 if (s.Connected)
174 s.Send(Encoding.GetEncoding("ISO-8859-1").GetBytes("{B64}" + convertedArray + "{EOS}"));
175 }
176 catch (SocketException)
177 {
178 }
179 }
180 }
181
182 [NaughtyAttributes.Button]
183 void requestJson()
184 {
185 ProcessResponse("{REQ}a1.json");
186 }
187
188 [NaughtyAttributes.Button]
189 void requestScene()
190 {
191 requestedFile = "pb_Scene";
192 ProcessResponse("{REQ}pb_Scene");
193 }
194
195 private byte[] Combine(params byte[][] arrays)
196 {
197 byte[] rv = new byte[arrays.Sum(a => a.Length)];
198 int offset = 0;
199 foreach (byte[] array in arrays)
200 {
201 System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
202 offset += array.Length;
203 }
204 return rv;
205 }
206 [NaughtyAttributes.Button]
207 void TesztLoadModel()
208 {
209 requestedFile = "cube.fbx";
210 LoadModel(@"D:\GIT\UNITY\vrtanoda\Assets\StreamingAssets\cube.fbx");
211 }
212 private void ProcessResponse(byte[] array)
213 {
214 var command = Encoding.GetEncoding("ISO-8859-1").GetString(array);
215
216 //Debug.Log("[ProcessResponse] " + command);
217
218 if (command.StartsWith("{REQ}"))
219 {
220#if DANA
221 var goName = command.Remove(0, 5);
222
223 if (goName.EndsWith(".json"))
224 {
225 Console.WriteLine("Client requested scene: " + goName);
226#if UNITY_EDITOR
227 var path = Application.streamingAssetsPath.Remove(Application.streamingAssetsPath.LastIndexOf('/'));
228 path = path.Remove(path.LastIndexOf('/'));
229#else
230 var path = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
231#endif
232 string[] filename = { goName };
233 var name = pb_FileDialog.GetFiles(path, filename);
234 var json = File.ReadAllText(name.First());
235 var loaded_array = (object[])JsonConvert.DeserializeObject<object[]>(json, pb_Serialization.ConverterSettings);
236 lastLoadedObjects = loaded_array;
237 var controller = (Controller)loaded_array[1];
238 var actions = controller.actions;
239 SendMsgToAllClients("{JSON}" + json + "{EOS}");
240 foreach (var action in actions)
241 {
242 VoiceAction voiceAct = null;
243 ShowHideAction sha = null;
244 if (action.Value is VoiceAction)
245 {
246 voiceAct = (VoiceAction)action.Value;
247
248 var proc = VoiceTTS.SpeakToFile(voiceAct.textToSpeak, voiceAct.ID, voiceAct.selectedLanguage)/*.WaitForExit()*/;
249 StartCoroutine(waiter(proc, voiceAct));
250
251 }
252 if (action.Value is ShowHideAction)
253 {
254 sha = (ShowHideAction)action.Value;
255 StartCoroutine(videoUpload(sha));
256 }
257 }
258
259 }
260 else
261 {
262 Console.WriteLine("Client requested GameObject: " + goName);
263 if (goName == "pb_Scene")
264 {
265 requestedFile = "pb_Scene";
266 OnLoadFinished(GILES.pb_Scene.instance.gameObject);
267 return;
268 }
269 if (lastLoadedObjects == null)
270 {
271 Console.WriteLine("Can't send, no JSON loaded!");
272 return;
273 }
274#if UNITY_EDITOR
275 var path = Application.streamingAssetsPath.Remove(Application.streamingAssetsPath.LastIndexOf('/'));
276 path = path.Remove(path.LastIndexOf('/'));
277#else
278 var path = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
279#endif
280 var scene = lastLoadedObjects[0] as pb_SceneNode;
281 string fn;
282 if (goName.Length == 64)
283 fn = Macro.GetFileNameForGameObject(scene, GetGONameFromHash(scene, goName), out modelName);
284 else
285 fn = Macro.GetFileNameForGameObject(scene, goName, out modelName);
286 string[] filename = { fn };
287 var filepath = pb_FileDialog.GetFiles(path, filename, SearchOption.AllDirectories);
288 Debug.Log(filepath.First());
289 requestedFile = Path.GetFileName(filepath.First());
290 LoadModel(filepath.First());
291 }
292#endif
293 }
294 #region DEPRECATED
295 //if (command.StartsWith("{POS}"))
296 //{
297 // var goName = command.Remove(0, 5).Split(';');
298 // //Console.WriteLine("Client sent transform update for: " + goName[0]);
299 // var index = Convert.ToInt32(goName[0]);
300 // RemotePos[index] = new Vector3(Macro.StoF(goName[1]), Macro.StoF(goName[2]), Macro.StoF(goName[3]));
301 //}
302 //if (command.StartsWith("{ROT}"))
303 //{
304 // var goName = command.Remove(0, 5).Split(';');
305 // //Console.WriteLine("Client sent transform update for: " + goName[0]);
306 // var index = Convert.ToInt32(goName[0]);
307 // RemoteRot[index] = new Vector3(Macro.StoF(goName[1]), Macro.StoF(goName[2]), Macro.StoF(goName[3]));
308 //}
309 //if (command.StartsWith("{POSL}"))
310 //{
311 // var goName = command.Remove(0, 6).Split(';');
312 // var index = Convert.ToInt32(goName[0]);
313 // RemoteLocalPos[index] = new Vector3(Macro.StoF(goName[1]), Macro.StoF(goName[2]), Macro.StoF(goName[3]));
314 //}
315 //if (command.StartsWith("{ROTL}"))
316 //{
317 // var goName = command.Remove(0, 6).Split(';');
318 // var index = Convert.ToInt32(goName[0]);
319 // RemoteLocalRot[index] = new Vector3(Macro.StoF(goName[1]), Macro.StoF(goName[2]), Macro.StoF(goName[3]));
320 //}
321 #endregion
322 }
323
324 private void ProcessResponse(string command)
325 {
326 ProcessResponse(Encoding.GetEncoding("ISO-8859-1").GetBytes(command));
327 }
328
329 string GetGONameFromHash(pb_SceneNode sn, string hash)
330 {
331 foreach (var node in sn.children)
332 {
333 if (node.hash == hash)
334 {
335 return node.name;
336 }
337 var retval = GetGONameFromHash(node, hash);
338 if (retval != "") return retval;
339 }
340 return "";
341 }
342
343 public IEnumerator waiter(Process p, VoiceAction voiceAct)
344 {
345
346 while (!p.HasExited)
347 {
348 yield return null;
349 }
350 string appPath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/')) /*- 1)*/;
351 var clipPath = System.IO.Path.Combine(appPath, voiceAct.ID);
352 var audioFile = File.ReadAllBytes(clipPath);
353 //audioFile.AddRange(File.ReadAllBytes(clipPath).ToList());
354 File.Delete(voiceAct.ID);
355 //SendMsgToAllClients("{VOI}", audioFile, voiceAct.ID); // DEPRECATED
356
357 if (fileServer.loadedFiles.ContainsKey(voiceAct.ID + ".wav"))
358 fileServer.loadedFiles[voiceAct.ID + ".wav"] = audioFile;
359 else
360 fileServer.loadedFiles.Add(voiceAct.ID + ".wav", audioFile);
361
362 SendMsgToAllClients("{FSR}", voiceAct.ID + ".wav", voiceAct.ID);
363 Console.WriteLine(voiceAct.ID + " sent");
364 yield return null;
365
366 }
367
368 public IEnumerator videoUpload(ShowHideAction sha)
369 {
370
371 string appPath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/')) /*- 1)*/;
372 var clipPath = System.IO.Path.Combine(appPath, sha.selectedGO.name);
373 var videoFile = File.ReadAllBytes(clipPath);
374
375 if (fileServer.loadedFiles.ContainsKey(sha.selectedGO.name))
376 fileServer.loadedFiles[sha.selectedGO.name] = videoFile;
377 else
378 fileServer.loadedFiles.Add(sha.selectedGO.name, videoFile);
379
380 SendMsgToAllClients("{FSR}", sha.selectedGO.name, sha.ID);
381 Console.WriteLine(sha.selectedGO.name + " sent");
382 yield return null;
383
384 }
385 public void ReadSocket()
386 {
387 var myindex = threads.Count - 1;
388 var s = sockets[myindex];
389 var remoteIP = s.RemoteEndPoint.ToString();
390
391 string end = "";
392 List<byte> receivedBytes = new List<byte>();
393
394 while (true)
395 {
396 if (s.Connected)
397 {
398 byte[] receive = new byte[1];
399 try
400 {
401 // Receive will block until data coming
402 // ret is 0 or Exception happen when Socket connection is broken
403 int ret = s.Receive(receive, receive.Length, 0);
404 if (ret > 0)
405 {
406 string recieved = Encoding.GetEncoding("ISO-8859-1").GetString(receive);
407 if (recieved == "{" && end == "" || recieved == "E" && end == "{" || recieved == "O" && end == "{E" || recieved == "S" && end == "{EO" || recieved == "}" && end == "{EOS")
408 {
409 end += recieved;
410 if (end == "{EOS}")
411 {
412 //var fullmsg = Encoding.GetEncoding("ISO-8859-1").GetString(receivedBytes.ToArray());
413 //System.IO.File.AppendAllText("pastcommands.txt", fullmsg + "\r\n");
414 //Console.WriteLine(fullmsg);
415#if DANA
416 var array = receivedBytes.ToArray();
417 Dispatcher.InvokeAsync(() =>
418 {
419 ProcessResponse(array);
420 });
421#endif
422 receivedBytes.Clear();
423 end = "";
424 }
425 continue;
426 }
427 if (end != "")
428 {
429 receivedBytes.AddRange(Encoding.GetEncoding("ISO-8859-1").GetBytes(end));
430 }
431 end = "";
432 receivedBytes.Add(receive[0]);
433 }
434 else
435 {
436 break;
437 }
438 }
439 catch (Exception)
440 {
441 Debug.Log("ReadSocket exception!");
442 if (!s.Connected)
443 {
444 break;
445 }
446 }
447 }
448 }
449 Console.WriteLine("Connection Closed with: {0}!", remoteIP);
450 }
451
452 private void OnDisable()
453 {
454 fileServer?.Stop();
455 listener?.Stop();
456 worker?.Abort();
457 }
458
459 private void LoadModel(string path)
460 {
461 using (var assetLoader = new AssetLoaderAsync())
462 {
463 var assetLoaderOptions = AssetLoaderOptions.CreateInstance();
464 assetLoaderOptions.MaterialTransparencyMode = MaterialTransparencyMode.Cutout;
465 assetLoaderOptions.AdvancedConfigs.Add(AssetAdvancedConfig.CreateConfig(AssetAdvancedPropertyClassNames.FBXImportPreservePivots, false));
466 var thread = assetLoader.LoadFromFile(path, assetLoaderOptions, null, progressCallback: ProgressCallback, onAssetLoaded: OnLoadFinished);
467 }
468 }
469
470 private void ProgressCallback(float progress)
471 {
472 Dispatcher.InvokeAsync(() =>
473 {
474 if (progress != 0f)
475 {
476 Console.CursorTop--;
477 }
478 Console.WriteLine("Loading model progress: {0}%", (progress * 100).ToString("F1"));
479 });
480 }
481
482 private void OnLoadFinished(GameObject go)
483 {
484 var goChildren = go.GetComponentsInChildren<Transform>();
485 GameObject goSelected = null;
486 foreach (var child in goChildren)
487 {
488 if (child.gameObject.name == modelName) goSelected = child.gameObject;
489 }
490 if (goSelected != null)
491 {
492 if (Macro.IsInChild(goSelected.transform, "ForceDoubleSided"))
493 {
494 ShaderChanger.Change(goSelected.GetComponentsInChildren<MeshRenderer>(), "Ciconia Studio/Double Sided/Standard/Diffuse Bump");
495 }
496 string hash = HashingManager.instance.GetHash4GameObject(goSelected);
497
498 //OLD: SendMsgToAllClients("{RGO}", GameObjectSerializer.SerializeGameObject(goSelected, true), hash);
499 if (fileServer.loadedFiles.ContainsKey(requestedFile))
500 fileServer.loadedFiles[requestedFile] = GameObjectSerializer.SerializeGameObject(goSelected, true);
501 else
502 fileServer.loadedFiles.Add(requestedFile, GameObjectSerializer.SerializeGameObject(goSelected, true));
503
504 SendMsgToAllClients("{FSR}", requestedFile, hash);
505 }
506 else
507 {
508 if (Macro.IsInChild(go.transform, "ForceDoubleSided"))
509 {
510 ShaderChanger.Change(go.GetComponentsInChildren<MeshRenderer>(), "Ciconia Studio/Double Sided/Standard/Diffuse Bump");
511 }
512 string hash = HashingManager.instance.GetHash4GameObject(go);
513 //SendMsgToAllClients("{RGO}", GameObjectSerializer.SerializeGameObject(go, true), hash);
514
515 if (fileServer.loadedFiles.ContainsKey(requestedFile))
516 fileServer.loadedFiles[requestedFile] = GameObjectSerializer.SerializeGameObject(go, true);
517 else
518 fileServer.loadedFiles.Add(requestedFile, GameObjectSerializer.SerializeGameObject(go, true));
519
520 SendMsgToAllClients("{FSR}", requestedFile, hash);
521 }
522
523 }
524
525 private void DrawLogo()
526 {
527 Console.Title = Application.productName + " - v" + Application.version + " Server";
528
529 Console.WriteLine(" ___ _ ");
530 Console.WriteLine(" / _ \\ | | ");
531 Console.WriteLine(" / /_\\ \\_ __ _ __ ___ _ __ | |_ _ _ _ __ ___ ");
532 Console.WriteLine(" | _ | '_ \\| '_ \\ / _ \\ '_ \\| __| | | | '_ ` _ \\ ");
533 Console.WriteLine(" | | | | |_) | |_) | __/ | | | |_| |_| | | | | | |");
534 Console.WriteLine(" \\_| |_/ .__/| .__/ \\___|_| |_|\\__|\\__,_|_| |_| |_|");
535 Console.WriteLine(" | | | | ");
536 Console.WriteLine(" |_| |_| v" + Application.version);
537 Console.WriteLine();
538 }
539#endif
540}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
TriLibCore.AssetLoaderOptions AssetLoaderOptions
Definition: TriLibLoader.cs:9
static IEnumerable< string > GetFiles(string path, string[] searchPatterns, SearchOption searchOption=SearchOption.TopDirectoryOnly)
List< pb_SceneNode > children
Definition: pb_SceneNode.cs:27
void Stop()
Definition: HttpServer.cs:25
Dictionary< string, byte[]> loadedFiles
Definition: HttpServer.cs:12
void Run()
Definition: HttpServer.cs:31
Definition: Macro.cs:12
static string GetFileNameForGameObject(GILES.Serialization.pb_SceneNode sn, string go, out string modelName)
Definition: Macro.cs:51
static bool IsInChild(Transform t, string childName)
Definition: Macro.cs:552
byte[] PoseToByteArray(GameObject go, bool limitToMixamoRig=true)
byte[] TransformToByteArray(GameObject go, bool local=true)
static void Change(Material mat, string shaderName)
Definition: ShaderChanger.cs:7