浏览代码

Client.cs: socket & websocket

Rimmon 5 年之前
父节点
当前提交
7875b8c669

+ 3 - 0
.gitignore

@@ -347,3 +347,6 @@ healthchecksdb
 /ProjectSettings/ProjectVersion.txt
 /*.csproj
 /*.sln
+/Builds/Build
+/Builds/TemplateData
+/Builds

+ 36 - 0
Assets/Plugins/Websocket/EchoTest.cs

@@ -0,0 +1,36 @@
+using UnityEngine;
+using System.Collections;
+using System;
+
+//example of websockets
+/*
+public class EchoTest : MonoBehaviour {
+
+	private void Log(String str)
+	{
+		Debug.Log(str);
+	}
+		
+	// Use this for initialization
+	IEnumerator Start () {
+		WebSocket w = new WebSocket(new Uri("ws://localhost/WebSocketsTest"));
+		yield return StartCoroutine(w.Connect());
+		w.SendString("Hi!");
+		int i=0;
+		while (true)
+		{
+			string reply = w.RecvString();
+			if (reply != null) {
+				w.SendString ("Hi:" + i++);
+			}
+			if (w.error != null)
+			{
+				//Log ("Error: "+w.error);
+				break;
+			}
+			yield return 0;
+		}
+		w.Close();
+	}
+}
+*/

+ 143 - 0
Assets/Plugins/Websocket/WebSocket.cs

@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Collections;
+using UnityEngine;
+using System.Runtime.InteropServices;
+
+public class WebSocket
+{
+	private Uri mUrl;
+
+	public WebSocket(Uri url)
+	{
+		mUrl = url;
+
+		string protocol = mUrl.Scheme;
+		if (!protocol.Equals("ws") && !protocol.Equals("wss"))
+			throw new ArgumentException("Unsupported protocol: " + protocol);
+	}
+
+	public void SendString(string str)
+	{
+		Send(Encoding.UTF8.GetBytes (str));
+	}
+
+	public string RecvString()
+	{
+		byte[] retval = Recv();
+		if (retval == null)
+			return null;
+		return Encoding.UTF8.GetString (retval);
+	}
+
+#if UNITY_WEBGL && !UNITY_EDITOR
+	[DllImport("__Internal")]
+	private static extern int SocketCreate (string url);
+
+	[DllImport("__Internal")]
+	private static extern int SocketState (int socketInstance);
+
+	[DllImport("__Internal")]
+	private static extern void SocketSend (int socketInstance, byte[] ptr, int length);
+
+	[DllImport("__Internal")]
+	private static extern void SocketRecv (int socketInstance, byte[] ptr, int length);
+
+	[DllImport("__Internal")]
+	private static extern int SocketRecvLength (int socketInstance);
+
+	[DllImport("__Internal")]
+	private static extern void SocketClose (int socketInstance);
+
+	[DllImport("__Internal")]
+	private static extern int SocketError (int socketInstance, byte[] ptr, int length);
+
+	int m_NativeRef = 0;
+
+	public void Send(byte[] buffer)
+	{
+		SocketSend (m_NativeRef, buffer, buffer.Length);
+	}
+
+	public byte[] Recv()
+	{
+		int length = SocketRecvLength (m_NativeRef);
+		if (length == 0)
+			return null;
+		byte[] buffer = new byte[length];
+		SocketRecv (m_NativeRef, buffer, length);
+		return buffer;
+	}
+
+	public IEnumerator Connect()
+	{
+		m_NativeRef = SocketCreate (mUrl.ToString());
+
+		while (SocketState(m_NativeRef) == 0)
+			yield return 0;
+	}
+ 
+	public void Close()
+	{
+		SocketClose(m_NativeRef);
+	}
+
+	public string error
+	{
+		get {
+			const int bufsize = 1024;
+			byte[] buffer = new byte[bufsize];
+			int result = SocketError (m_NativeRef, buffer, bufsize);
+
+			if (result == 0)
+				return null;
+
+			return Encoding.UTF8.GetString (buffer);				
+		}
+	}
+#else
+	WebSocketSharp.WebSocket m_Socket;
+	Queue<byte[]> m_Messages = new Queue<byte[]>();
+	bool m_IsConnected = false;
+	string m_Error = null;
+
+	public IEnumerator Connect()
+	{
+		m_Socket = new WebSocketSharp.WebSocket(mUrl.ToString());
+		m_Socket.OnMessage += (sender, e) => m_Messages.Enqueue (e.RawData);
+		m_Socket.OnOpen += (sender, e) => m_IsConnected = true;
+		m_Socket.OnError += (sender, e) => m_Error = e.Message;
+		m_Socket.ConnectAsync();
+		while (!m_IsConnected && m_Error == null)
+			yield return 0;
+	}
+
+	public void Send(byte[] buffer)
+	{
+		m_Socket.Send(buffer);
+	}
+
+	public byte[] Recv()
+	{
+		if (m_Messages.Count == 0)
+			return null;
+		return m_Messages.Dequeue();
+	}
+
+	public void Close()
+	{
+		m_Socket.Close();
+	}
+
+	public string error
+	{
+		get {
+			return m_Error;
+		}
+	}
+#endif 
+}

+ 130 - 0
Assets/Plugins/Websocket/WebSocket.jslib

@@ -0,0 +1,130 @@
+var LibraryWebSockets = {
+$webSocketInstances: [],
+
+SocketCreate: function(url)
+{
+	var str = Pointer_stringify(url);
+	var socket = {
+		socket: new WebSocket(str),
+		buffer: new Uint8Array(0),
+		error: null,
+		messages: []
+	}
+
+	socket.socket.binaryType = 'arraybuffer';
+
+	socket.socket.onmessage = function (e) {
+		// Todo: handle other data types?
+		if (e.data instanceof Blob)
+		{
+			var reader = new FileReader();
+			reader.addEventListener("loadend", function() {
+				var array = new Uint8Array(reader.result);
+				socket.messages.push(array);
+			});
+			reader.readAsArrayBuffer(e.data);
+		}
+		else if (e.data instanceof ArrayBuffer)
+		{
+			var array = new Uint8Array(e.data);
+			socket.messages.push(array);
+		}
+		else if(typeof e.data === "string") 
+		{
+			var reader = new FileReader();
+			reader.addEventListener("loadend", function() {
+				var array = new Uint8Array(reader.result);
+				socket.messages.push(array);
+			});
+			var blob = new Blob([e.data]);
+			reader.readAsArrayBuffer(blob);
+		}
+	};
+
+	socket.socket.onclose = function (e) {
+		if (e.code != 1000)
+		{
+			if (e.reason != null && e.reason.length > 0)
+				socket.error = e.reason;
+			else
+			{
+				switch (e.code)
+				{
+					case 1001: 
+						socket.error = "Endpoint going away.";
+						break;
+					case 1002: 
+						socket.error = "Protocol error.";
+						break;
+					case 1003: 
+						socket.error = "Unsupported message.";
+						break;
+					case 1005: 
+						socket.error = "No status.";
+						break;
+					case 1006: 
+						socket.error = "Abnormal disconnection.";
+						break;
+					case 1009: 
+						socket.error = "Data frame too large.";
+						break;
+					default:
+						socket.error = "Error "+e.code;
+				}
+			}
+		}
+	}
+	var instance = webSocketInstances.push(socket) - 1;
+	return instance;
+},
+
+SocketState: function (socketInstance)
+{
+	var socket = webSocketInstances[socketInstance];
+	return socket.socket.readyState;
+},
+
+SocketError: function (socketInstance, ptr, bufsize)
+{
+ 	var socket = webSocketInstances[socketInstance];
+ 	if (socket.error == null)
+ 		return 0;
+    var str = socket.error.slice(0, Math.max(0, bufsize - 1));
+    writeStringToMemory(str, ptr, false);
+	return 1;
+},
+
+SocketSend: function (socketInstance, ptr, length)
+{
+	var socket = webSocketInstances[socketInstance];
+	socket.socket.send (HEAPU8.buffer.slice(ptr, ptr+length));
+},
+
+SocketRecvLength: function(socketInstance)
+{
+	var socket = webSocketInstances[socketInstance];
+	if (socket.messages.length == 0)
+		return 0;
+	return socket.messages[0].length;
+},
+
+SocketRecv: function (socketInstance, ptr, length)
+{
+	var socket = webSocketInstances[socketInstance];
+	if (socket.messages.length == 0)
+		return 0;
+	if (socket.messages[0].length > length)
+		return 0;
+	HEAPU8.set(socket.messages[0], ptr);
+	socket.messages = socket.messages.slice(1);
+},
+
+SocketClose: function (socketInstance)
+{
+	var socket = webSocketInstances[socketInstance];
+	socket.socket.close();
+}
+};
+
+autoAddDeps(LibraryWebSockets, '$webSocketInstances');
+mergeInto(LibraryManager.library, LibraryWebSockets);

二进制
Assets/Plugins/Websocket/websocket-sharp.dll


+ 113 - 1
Assets/Scenes/Location.unity

@@ -38,7 +38,7 @@ RenderSettings:
   m_ReflectionIntensity: 1
   m_CustomReflection: {fileID: 0}
   m_Sun: {fileID: 170076734}
-  m_IndirectSpecularColor: {r: 0.43667555, g: 0.48427123, b: 0.5645229, a: 1}
+  m_IndirectSpecularColor: {r: 0.4366756, g: 0.48427194, b: 0.5645252, a: 1}
   m_UseRadianceAmbientProbe: 0
 --- !u!157 &3
 LightmapSettings:
@@ -874,6 +874,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 0}
   m_Type: 0
   m_PreserveAspect: 0
@@ -1584,6 +1586,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Scrollbar+ScrollEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &234121889
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -1602,6 +1606,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -1994,6 +2000,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_FontData:
     m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
     m_FontSize: 14
@@ -2114,6 +2122,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 0}
   m_Type: 0
   m_PreserveAspect: 0
@@ -2405,6 +2415,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -2794,6 +2806,7 @@ GameObject:
   - component: {fileID: 534669904}
   - component: {fileID: 534669903}
   - component: {fileID: 534669906}
+  - component: {fileID: 534669907}
   m_Layer: 0
   m_Name: Main Camera
   m_TagString: MainCamera
@@ -2896,6 +2909,29 @@ MonoBehaviour:
   zoom: 0.5
   zoomMax: 50
   zoomMin: 0.5
+--- !u!114 &534669907
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 534669902}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: ce05d46980f5e314781de197aef49c96, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  account_id: 0
+  login_sent: 0
+  entered: 0
+  dc: 0
+  connected: 0
+  lag: 0
+  last_ping_time: 0
+  initial_timer: 0
+  internal_timer: 0
+  spacebox: {fileID: 0}
+  _dataPath: 
 --- !u!1 &545978266 stripped
 GameObject:
   m_CorrespondingSourceObject: {fileID: 6099118876963798654, guid: 04e9dfc406038d741b31aeebae5c71cb,
@@ -2992,6 +3028,8 @@ MonoBehaviour:
           m_StringArgument: 
           m_BoolArgument: 0
         m_CallState: 2
+    m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &577460076
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -3010,6 +3048,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -3344,6 +3384,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -3416,6 +3458,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_FontData:
     m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
     m_FontSize: 14
@@ -3596,6 +3640,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Scrollbar+ScrollEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &755215651
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -3614,6 +3660,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -4183,6 +4231,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_FontData:
     m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
     m_FontSize: 14
@@ -4393,6 +4443,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -4686,6 +4738,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -4758,6 +4812,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10915, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 0
   m_PreserveAspect: 0
@@ -4859,6 +4915,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Scrollbar+ScrollEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &1043834003
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -4877,6 +4935,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -5190,6 +5250,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.ScrollRect+ScrollRectEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &1096579875
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -5208,6 +5270,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -5750,6 +5814,8 @@ MonoBehaviour:
   onValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Toggle+ToggleEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
   m_IsOn: 1
 --- !u!1 &1263077295
 GameObject:
@@ -6195,6 +6261,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_FontData:
     m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
     m_FontSize: 14
@@ -6792,6 +6860,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -6839,6 +6909,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.ScrollRect+ScrollRectEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!1 &1490867757
 GameObject:
   m_ObjectHideFlags: 0
@@ -6894,6 +6966,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -6972,6 +7046,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10915, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 0
   m_PreserveAspect: 0
@@ -7073,6 +7149,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Scrollbar+ScrollEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &1526369941
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -7091,6 +7169,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -7243,6 +7323,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_FontData:
     m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
     m_FontSize: 14
@@ -7334,6 +7416,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -7512,6 +7596,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -7795,6 +7881,8 @@ MonoBehaviour:
   onValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Toggle+ToggleEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
   m_IsOn: 1
 --- !u!1 &1637274590
 GameObject:
@@ -8512,6 +8600,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.ScrollRect+ScrollRectEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &1800600955
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -8530,6 +8620,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -8636,6 +8728,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Dropdown+DropdownEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &1806286240
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -8654,6 +8748,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -8994,6 +9090,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10901, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 0
   m_PreserveAspect: 0
@@ -9581,6 +9679,8 @@ MonoBehaviour:
   m_OnValueChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.Dropdown+DropdownEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &1917842947
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -9599,6 +9699,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -9970,6 +10072,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_FontData:
     m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
     m_FontSize: 14
@@ -10372,6 +10476,8 @@ MonoBehaviour:
           m_StringArgument: 
           m_BoolArgument: 0
         m_CallState: 2
+    m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
+      Culture=neutral, PublicKeyToken=null
 --- !u!114 &2059615927
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -10390,6 +10496,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -10462,6 +10570,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
@@ -10656,6 +10766,8 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
+    m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
+      Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
   m_Sprite: {fileID: 10901, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 0
   m_PreserveAspect: 0

+ 1 - 1
Assets/Scripts/Controllers/WorkerController.cs

@@ -116,7 +116,7 @@ public class WorkerController : MonoBehaviour
     {
         yield return new WaitForSeconds(pause);
 
-        if (worker_marker.active == true && start)
+        if (worker_marker.activeSelf == true && start)
         {
             //float smoothTime = 0.2f;
             //float yVelocity = 0.5f;

+ 772 - 0
Assets/Scripts/Net/Client.cs

@@ -0,0 +1,772 @@
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Networking;
+using System.Collections;
+using System.Collections.Generic;
+using System.Net.Sockets;
+using System.Net;
+using System.Text;
+using System;
+
+
+public class Client : MonoBehaviour
+{
+    public const int socketPort = 87;
+    public const int webglPort = 86;
+    public uint account_id = 0; //id акка
+    string ACCOUNT_NAME = "";
+
+    bool login_sent;
+    bool entered = false;
+    bool dc = false;    
+    bool connected = false;    
+    int lag = 0;
+    double last_ping_time = 0;
+    static string[] Servers = { "dev.prmsys.net", "localhost", "corp.prmsys.net" };
+    static bool ShowPacketsSent = true;
+    //private const bool ShowPacketsSent = false;
+
+    // private const bool ShowPackets = true; //ставится только в редакторе
+    static bool ShowPackets = true; //ставится только в редакторе
+    double initial_timer;
+    int internal_timer = 0;
+    public double timer
+    {
+        get
+        {
+            return DateTime.Now.Ticks / 10000000.0;    //секунды
+        }
+    }
+    public static Client instance;
+    public static string ServerName;
+    public static bool StartConnectFlag = false;
+#if UNITY_WEBGL
+    public static WebSocket Mysocket;
+#else
+    public static Socket Mysocket;
+#endif
+    Dictionary<int, int> PacketLength = new Dictionary<int, int>();
+    public delegate void OnReceive(byte[] bytedata);
+    public static OnReceive[] packets = new OnReceive[255];
+    private static Dictionary<string, UnityEngine.Object> loaded_models = new Dictionary<string, UnityEngine.Object>();
+    private static Dictionary<string, UnityEngine.Object> loaded_icons = new Dictionary<string, UnityEngine.Object>();
+    public string _dataPath = "";
+    GameObject drone;
+    public static ClientType clientType;
+    public enum ClientType
+    {
+        Desktop,
+        Web
+    }
+
+    public static void SendEnqueue(byte[] bytedata)
+    {
+        SendQueue.Enqueue(bytedata);
+    }
+
+    private void Awake()
+    {
+        instance = this;
+        ServerName = PlayerPrefs.GetString("server");
+        if (ServerName == "")
+            ServerName = Servers[0];
+
+        Register(1, Disconnect, 5);
+        Register(2, Login, 5);
+        Register(30, Myping, 3);
+
+        //set data path
+        //if (Application.platform == RuntimePlatform.WindowsWebPlayer ||
+        //    Application.platform == RuntimePlatform.OSXWebPlayer)
+        if (Application.platform == RuntimePlatform.WebGLPlayer)
+        {
+            _dataPath = Application.dataPath + "/StreamingAssets";
+            clientType = ClientType.Web;
+        }
+        else if (Application.platform == RuntimePlatform.Android)
+        {
+            _dataPath = "jar:file://" + Application.dataPath + "!/assets";
+            clientType = ClientType.Web;
+        }
+        else
+        {
+            _dataPath = "file://" + Application.dataPath + "/StreamingAssets"; ;
+            clientType = ClientType.Desktop;
+        }
+        _dataPath = Application.streamingAssetsPath;
+        //Debug.Log("_dataPath " + _dataPath);
+    }
+    public int LagCount
+    {
+        get
+        {
+            return lagpoints.Count;
+        }
+    }
+
+    int totallag
+    {
+        get
+        {
+            int q = 0;
+            foreach (var g in lagpoints)
+            {
+                q += g;
+            }
+            return q;
+        }
+    }
+
+    Queue<int> lagpoints = new Queue<int>();
+
+    public int Averagelag
+    {
+        get
+        {
+            if (lagpoints.Count > 0)
+                return totallag / lagpoints.Count;
+            return 0;
+        }
+    }
+    public void Myping(byte[] bytedata)
+    {
+        last_ping_time = timer;
+        int lag = BitConverter.ToUInt16(bytedata, 1);
+        //print("Myping " + lag);
+        this.lag = lag;
+        if (lagpoints.Count > 5)
+            lagpoints.Dequeue();
+
+        lagpoints.Enqueue(lag);
+
+        List<byte> list = new List<byte>();
+        list.Add(30);
+        list.Add((byte)1);
+        SendEnqueue(list.ToArray());
+    }
+
+    public void Disconnect(byte[] bytedata)
+    {
+        uint bid = BitConverter.ToUInt32(bytedata, 1);
+        if (bid == account_id)
+            Exit();
+        else
+        {
+            print("disc id " + bid);
+        }
+    }
+
+
+    public void Exit()
+    {
+        print("Client Exit");
+        connected = false;
+        login_sent = false;
+        if (Mysocket != null)
+        {
+            Mysocket.Close();
+            Mysocket = null;
+        }
+        connect_started = new DateTime();
+        totalbytes = 0;
+        account_id = 0;
+        ACCOUNT_NAME = "";
+        connected = false;
+        sendDone = false;
+        receiveDone = false;
+        connectDone = false;
+        StartConnectFlag = false;
+        UnityEngine.SceneManagement.SceneManager.LoadScene(0);
+    }
+
+    //пакет с 1 параметром = 1
+    public static void SendOneBytePacket(int num)
+    {
+        SendOneByteParamPacket(num, 1);
+    }
+
+    public static void SendOneByteTwoParamsPacket(int num, int param1, int param2)
+    {
+        byte[] data = { (Byte)num, (Byte)param1, (byte)param2 };
+        SendEnqueue(data);
+    }
+
+    public static void SendThreeParamsIntPacket(int num, int param1, int param2, int param3)
+    {
+        List<byte> list = new List<byte>();
+        list.Add((Byte)num);
+        list.AddRange(BitConverter.GetBytes(param1));
+        list.AddRange(BitConverter.GetBytes(param2));
+        list.AddRange(BitConverter.GetBytes(param3));
+        SendEnqueue(list.ToArray());
+    }
+
+    //пакет с 1 1-байтовым параметром
+    public static void SendOneByteParamPacket(int num, int param)
+    {
+        byte[] data = { (Byte)num, (Byte)param };
+        byteSend(data);
+    }
+
+    //пакет с 1 4-байтовым параметром
+    public static void SendTwoByteParamPacket(int num, ushort param)
+    {
+        List<byte> list = new List<byte>();
+        list.Add((Byte)num);
+        list.AddRange(BitConverter.GetBytes(param));
+        SendEnqueue(list.ToArray());
+    }
+
+    //пакет с 1 4-байтовым параметром
+    public static void SendFourByteParamPacket(int num, int param)
+    {
+        List<byte> list = new List<byte>();
+        list.Add((Byte)num);
+        list.AddRange(BitConverter.GetBytes(param));
+        SendEnqueue(list.ToArray());
+    }
+
+    public static DateTime connect_started;
+    public void Login(byte[] bytedata)
+    {
+        uint accid = BitConverter.ToUInt32(bytedata, 1);
+        if (accid == 0xFFFFFFFF)
+        {
+            Debug.LogError("Login or password incorrect");
+            return;
+        }
+        else if (accid == 0xFFFFFFFE)
+        {
+            Debug.LogError("Account was already connected");
+            return;
+        }
+        else if (accid == 0xFFFFFFFD)
+        {
+            Debug.LogError("Incorrect client version");
+            return;
+        }
+
+        account_id = accid;
+        var ts = DateTime.Now.Ticks-100000000000;
+        var te = DateTime.Now.Ticks;
+        SendRequestCoordinates(ts, te, 1, 1);
+    }
+
+    #region system functions
+
+    public void Register(int packnum, OnReceive func)
+    {
+        packets[packnum] = func;
+    }
+
+    private void Register(int packnum, OnReceive func, int len)
+    {
+        packets[packnum] = func;
+        if (len > 1)
+            PacketLength[packnum] = len;
+    }
+
+    public int GetLength(byte[] data, int num, int offset)
+    {
+        int leng;
+        if (!PacketLength.ContainsKey(num))
+        {
+            var rest = data.Length - offset;
+            //packet not full
+            if (rest < 3)
+                return 1;
+            leng = BitConverter.ToInt16(data, offset + 1);
+        }
+        else
+            leng = PacketLength[num];
+        return leng;
+    }
+
+    int maximumPacketsPerUpdate = 50;
+
+    public void Start()
+    {
+        entered = true;
+    }
+
+    public void Update()
+    {     
+#if UNITY_WEBGL
+        Receive();
+#endif
+        if (instance == null || !entered)    //вход не нажат, ждем
+        {
+            return;
+        }
+        else
+        {
+            if (!StartConnectFlag)
+            {
+                StartCoroutine(Connect());
+                StartConnectFlag = true;
+            }
+        }
+        SendLogin();
+        int from_connect = DateTime.Now.Subtract(connect_started).Seconds;
+
+        if (from_connect > 7 && from_connect != DateTime.Now.Second && account_id == 0)
+        {
+            Exit();
+        }
+        var processedCount = 0;
+        while (PacketQueue.Count > 0 && processedCount < maximumPacketsPerUpdate)   //если длина очереди с пакетами ==0
+        {
+            byte[] packetbytes;
+            lock (packetqueuelock)
+            {
+                packetbytes = PacketQueue.Dequeue();
+            }
+            int offset = 0;
+            int totallen = 0;
+            int num = (int)packetbytes[0];
+            int leng = GetLength(packetbytes, packetbytes[0], 0);
+
+            if (leng <= packetbytes.Length)
+            {
+                while (offset < packetbytes.Length)
+                {
+                    num = (int)packetbytes[offset];
+                    leng = GetLength(packetbytes, num, offset);
+                    totallen += leng;
+                    print("num " + num + " leng " + leng);
+                    byte[] newpack = new byte[leng];
+                    Array.Copy(packetbytes, offset, newpack, 0, leng);
+                    offset += leng;
+                    if (ShowPackets)
+                    {
+                        if (num != 30)    //не пакет пинга
+                        {
+                            //string mygg = packets[num].Method.Name + " ";       //Печатаем принятые байты!
+                            string mygg = "";
+                            foreach (byte b in newpack)
+                            {
+                                mygg += b + " ";
+                            }
+                            //Debug.Log("ticks " + DateTime.Now.Ticks / 10000 + " timesince " + Time.timeSinceLevelLoad +" "+ newpack.Length + " bytes packet: " + mygg);
+                            Debug.Log(newpack.Length + " bytes packet: " + mygg);
+                        }
+                    }
+                    processedCount++;
+                    packets[num](newpack);//запустить OnReceive функцию
+                    //print("copy "+num);
+                }
+            }
+        }
+        //Debug.Log("Update End");
+    }
+
+    public void LateUpdate()
+    {
+        while (SendQueue.Count > 0)
+        {
+            //print("SendQueue.Count " + SendQueue.Count);
+            byte[] sendstring = SendQueue.Dequeue();
+            //print("sendstring len " + sendstring.Length);
+            byteSend(sendstring);
+        }
+    }
+
+    public class StateObject
+    {
+        // Client socket.
+
+        // Size of receive buffer.
+        public const int BufferSize = 128000;
+        // Receive buffer.
+        public byte[] buffer = new byte[BufferSize];
+        // Received data string.
+    }
+
+    public static Queue<byte[]> PacketQueue = new Queue<byte[]>();
+    static Queue<byte[]> SendQueue = new Queue<byte[]>();
+    public static bool receiveDone, connectDone, sendDone = false;
+
+    public static StateObject state = new StateObject();
+    private IEnumerator Connect()
+    {
+        Debug.Log("Connect");
+        // Connect to a remote server.
+#if UNITY_WEBGL
+        var uristring = $"ws://{ServerName}:{webglPort}/ws";
+        Debug.Log($"WebSocket tryconnect: {uristring}");
+        WebSocket client = new WebSocket(new Uri(uristring));
+        Mysocket = client;
+        yield return StartCoroutine(Mysocket.Connect());
+        connectDone = (Mysocket.error == null);
+        if (!connectDone)
+        {
+            Debug.Log("WebSocket error: " + Mysocket.error);
+            yield break;
+        }
+#else
+        // Establish the remote endpoint for the socket.
+        /*IPAddress ip = */
+        new IPAddress(new byte[] { 127, 0, 0, 1 });
+        IPHostEntry ipHostInfo = Dns.GetHostEntry(ServerName);
+        //string localHost = Dns.GetHostName();
+        //print("localHost " + ipHostInfo.AddressList[0]);
+        //IPHostEntry ipHostInfo = Dns.GetHostEntry(localHost);
+
+        IPAddress[] ipv4Addresses = Array.FindAll(ipHostInfo.AddressList, a => a.AddressFamily == AddressFamily.InterNetwork);
+        //print("localHost v4 " + ipv4Addresses[0]);
+        // IPAddress ipAddress = ipHostInfo.AddressList[0];
+        IPAddress ipAddress = ipv4Addresses[0];
+
+        //IPEndPoint remoteEP = new IPEndPoint(ip, socketPort);
+        IPEndPoint remoteEP = new IPEndPoint(ipAddress, socketPort);
+
+        // Create a TCP/IP socket.
+        Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+        //Socket client = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+        print("remoteEP.AddressFamily " + AddressFamily.InterNetwork);
+        print("client " + client.AddressFamily);
+        Mysocket = client;
+        // Connect to the remote endpoint.
+        try
+        {
+            client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
+        }
+        catch (Exception e)
+        {
+            print(e.Message);
+        }
+        int num = 0;
+        while (!connectDone && num < 10)
+        {
+            num++;
+            yield return new WaitForSeconds(0.2f);
+        }
+
+        if (!connectDone)
+        {
+            print(port + " port failed");
+            yield break;
+        }
+#endif
+        print("connected");
+        connected = true;
+        while (true)
+        {
+            if (!entered)
+                break;
+
+            while (!sendDone && connected)
+            {
+                yield return 1;
+            }
+
+            Receive();
+
+            while (!receiveDone && connected)
+            {
+                yield return 1;
+            }
+            receiveDone = false;
+            break;
+        }
+        yield break;
+    }
+
+    private static void ConnectCallback(IAsyncResult ar)
+    {
+        // Retrieve the socket from the state object.
+        Socket client = (Socket)ar.AsyncState;
+        connect_started = DateTime.Now;
+        // Complete the connection.
+        try
+        {
+            client.EndConnect(ar);
+        }
+        catch (Exception e)
+        {
+            print(e.Message);
+        }
+
+        // Signal that the connection has been made.
+        connectDone = true;
+    }
+
+    private void Receive()
+    {
+#if UNITY_WEBGL
+        CheckWebSocket();
+
+        if (Mysocket == null)
+            return;
+
+        byte[] packet = null;
+        do
+        {
+            packet = Mysocket.Recv();
+            if (packet != null)
+            {
+                lock (packetqueuelock)
+                {
+                    PacketQueue.Enqueue(packet);
+                }
+                receiveDone = true;
+                totalbytes += packet.Length;
+            }
+        }
+        while (packet != null);
+#else
+        Mysocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
+            new AsyncCallback(ReceiveCallback), state);
+#endif
+    }
+
+    public static object packetqueuelock = new object();
+    public static Queue<byte[]> tempqueue = new Queue<byte[]>();
+
+    public bool CheckLength(byte[] packetbytes)
+    {
+        if (packetbytes.Length > 0)   //если длина очереди с пакетами ==0
+        {
+            int offset = 0;
+            //TODO проверка на мусор
+            int num = packetbytes[0];
+            int leng = GetLength(packetbytes, packetbytes[0], 0);
+
+            if (leng <= packetbytes.Length)
+            {
+                while (offset < packetbytes.Length)
+                {
+                    num = packetbytes[offset];
+                    leng = GetLength(packetbytes, num, offset);
+                    if (leng == 1)
+                    {
+                        print("Error: CheckLength: packet not complete");
+                        return false;
+                    }
+                    //print("Checking Length of " + num + " len " + leng);
+                    if (leng == 0)
+                    {
+                        print("CheckLength2 break! length error " + num);
+                        dc = true;
+                        break;
+                    }
+                    offset += leng;
+                }
+            }
+            if (offset == packetbytes.Length)
+                return true;
+            return false;
+        }
+        return false;
+    }
+
+    public static int totalbytes = 0;
+
+#if !UNITY_WEBGL
+    private void ReceiveCallback(IAsyncResult ar)    //TODO если приходят данные больше длины буфера, пакеты режутся на части и складываются в обратном порядке - fix, пока что увеличим буфер
+    {
+        // Retrieve the state object and the client socket 
+        // from the asynchronous state object.
+        StateObject state = (StateObject)ar.AsyncState;
+
+        // Read data from the remote device.
+        int bytesRead = 0;
+        bytesRead = Mysocket.EndReceive(ar);
+
+        if (bytesRead > 0)
+        {
+            // All the data has arrived; put it in response.
+            byte[] newbuf = new Byte[bytesRead];
+            Array.Copy(state.buffer, newbuf, bytesRead);
+
+            //if (ShowPackets)
+            //{
+            //    if (newbuf[0] != 30)    //не пакет пинга
+            //    {
+            //        string mygg = "";       //Печатаем принятые байты!
+            //        foreach (byte b in newbuf)
+            //        {
+            //            mygg += b + " ";
+            //        }
+            //        print(newbuf.Length + " bytes: " + mygg);
+            //    }
+            //    totalbytes += bytesRead;
+            //}
+
+            byte[] tocheck = newbuf;
+            if (tempqueue.Count > 0)
+            {
+                Queue<byte[]> myqueue = new Queue<byte[]>(tempqueue);
+                List<byte> list = new List<byte>();
+                while (myqueue.Count > 0)
+                {
+                    list.AddRange(myqueue.Dequeue());
+                }
+                list.AddRange(newbuf);
+                tocheck = list.ToArray();
+            }
+            if (!CheckLength(tocheck))
+            {
+                tempqueue.Clear();
+                tempqueue.Enqueue(tocheck);
+            }
+            else
+            {
+                tempqueue.Clear();
+                lock (packetqueuelock)
+                {
+                    PacketQueue.Enqueue(tocheck);
+                }
+            }
+            receiveDone = true;
+            Receive();
+        }
+    }
+#endif
+
+#if UNITY_WEBGL
+    private static void CheckWebSocket()
+    {
+        if (Mysocket != null && Mysocket.error != null)
+        {
+            Debug.LogError(Mysocket.error);
+            instance.Exit();
+        }
+    }
+#endif
+
+    private static void byteSend(byte[] tosend)
+    {
+        if (tosend == null)
+        {
+            Debug.LogError("tosend null");
+            return;
+        }
+
+        if (ShowPacketsSent)
+        {
+            byte[] newbuf = new Byte[tosend.Length];
+            Array.Copy(tosend, newbuf, tosend.Length);
+            if (newbuf[0] != 30)    //не пакет пинга
+            {
+                string mygg = "sent: ";       //Печатаем отправленные байты!
+                foreach (byte b in newbuf)
+                {
+                    mygg += b + " ";
+                }
+                print(newbuf.Length + " bytes: " + mygg);
+            }
+        }
+
+#if UNITY_WEBGL
+        byte[] webglbuf = new Byte[tosend.Length];
+        Array.Copy(tosend, webglbuf, tosend.Length);
+        CheckWebSocket();
+        if (Mysocket != null)
+        {
+            Mysocket.Send(webglbuf);
+            sendDone = true;
+            Debug.Log("websocket sendDone");
+        }
+#else
+        try
+        {
+            //print("buffer size " + Mysocket.SendBufferSize + " tosend.Length " + tosend.Length);            
+            Mysocket.BeginSend(tosend, 0, tosend.Length, 0, SendCallback, Mysocket);
+        }
+        catch (Exception e)
+        {
+            if (instance != null)
+            {
+                print(e.Message);
+                instance.Exit();
+            }
+        }
+#endif
+    }
+
+#if !UNITY_WEBGL
+    private static void SendCallback(IAsyncResult ar)
+    {
+        // Retrieve the socket from the state object.
+        Socket client = (Socket)ar.AsyncState;
+
+        // Complete sending the data to the remote device.
+        /*int bytesSent = */
+        client.EndSend(ar);
+
+        //print("Sent " + bytesSent + " bytes to server.");
+
+        // Signal that all bytes have been sent.
+
+        sendDone = true;
+    }
+#endif
+
+    #endregion
+
+    public static string GetMD5Hash(string input)
+    {
+        System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
+        byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
+        bs = x.ComputeHash(bs);
+        System.Text.StringBuilder s = new System.Text.StringBuilder();
+        foreach (byte b in bs)
+        {
+            s.Append(b.ToString("x2").ToLower());
+        }
+        string password = s.ToString();
+        return password;
+    }
+
+    /// <summary>
+    /// Запрос координат с сервера, timeStart, timeEnd == DateTime.Ticks
+    /// </summary>
+    /// <param name="timeStart"></param>
+    /// <param name="timeEnd"></param>
+    /// <param name=""></param>
+    public void SendRequestCoordinates(long timeStart, long timeEnd, byte resolution, byte locationID)
+    {
+        login_sent = true;
+        Debug.Log("SendRequestCoordinates");
+        List<byte> list = new List<byte>();
+        list.Add(3);
+        list.AddRange(BitConverter.GetBytes(account_id));
+        list.AddRange(BitConverter.GetBytes(timeStart));
+        list.AddRange(BitConverter.GetBytes(timeEnd));
+        list.Add(resolution);
+        list.Add(locationID);
+        SendEnqueue(list.ToArray());
+    }
+    
+    public void SendLogin()
+    {
+        if (!connected)
+        {
+            //Debug.LogError("Couldn't connect");
+            //Exit();
+            return;
+        }
+        if (!login_sent)
+        {
+            login_sent = true;
+            Debug.Log("SendLogin");
+            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
+            string passwordToEdit = "123";
+            string login = "Admin12";
+            string pass = GetMD5Hash(passwordToEdit);
+
+            byte[] bpass = encoding.GetBytes(pass);
+            byte[] blogin = encoding.GetBytes(login);
+            List<byte> list = new List<byte>();
+            byte loginFlag = 1;
+            ushort leng = (ushort)(bpass.Length + blogin.Length + 4);   //+имя+длина        
+            list.Add(2);
+            list.AddRange(BitConverter.GetBytes(leng));
+            list.Add(loginFlag);
+            list.AddRange(bpass);
+            list.AddRange(blogin);
+            SendEnqueue(list.ToArray());
+        }
+    }
+}