Seven is the number.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
11 KiB

4 years ago
  1. #if UNITY_WEBGL || WEBSOCKET || (UNITY_XBOXONE && UNITY_EDITOR)
  2. // --------------------------------------------------------------------------------------------------------------------
  3. // <copyright file="SocketWebTcp.cs" company="Exit Games GmbH">
  4. // Copyright (c) Exit Games GmbH. All rights reserved.
  5. // </copyright>
  6. // <summary>
  7. // Internal class to encapsulate the network i/o functionality for the realtime library.
  8. // </summary>
  9. // <author>developer@exitgames.com</author>
  10. // --------------------------------------------------------------------------------------------------------------------
  11. namespace ExitGames.Client.Photon
  12. {
  13. using System;
  14. using System.Collections;
  15. using UnityEngine;
  16. using SupportClassPun = ExitGames.Client.Photon.SupportClass;
  17. /// <summary>
  18. /// Yield Instruction to Wait for real seconds. Very important to keep connection working if Time.TimeScale is altered, we still want accurate network events
  19. /// </summary>
  20. public sealed class WaitForRealSeconds : CustomYieldInstruction
  21. {
  22. private readonly float _endTime;
  23. public override bool keepWaiting
  24. {
  25. get { return this._endTime > Time.realtimeSinceStartup; }
  26. }
  27. public WaitForRealSeconds(float seconds)
  28. {
  29. this._endTime = Time.realtimeSinceStartup + seconds;
  30. }
  31. }
  32. /// <summary>
  33. /// Internal class to encapsulate the network i/o functionality for the realtime libary.
  34. /// </summary>
  35. public class SocketWebTcp : IPhotonSocket, IDisposable
  36. {
  37. /// <summary>Defines the binary serialization protocol for all WebSocket connections. Defaults to "GpBinaryV18", a Photon protocol.</summary>
  38. /// <remarks>This is a temporary workaround, until the serialization protocol becomes available via the PeerBase.</remarks>
  39. public static string SerializationProtocol = "GpBinaryV18";
  40. private WebSocket sock;
  41. private readonly object syncer = new object();
  42. public SocketWebTcp(PeerBase npeer) : base(npeer)
  43. {
  44. this.ServerAddress = npeer.ServerAddress;
  45. if (this.ReportDebugOfLevel(DebugLevel.INFO))
  46. {
  47. this.Listener.DebugReturn(DebugLevel.INFO, "new SocketWebTcp() for Unity. Server: " + this.ServerAddress);
  48. }
  49. //this.Protocol = ConnectionProtocol.WebSocket;
  50. this.PollReceive = false;
  51. }
  52. public void Dispose()
  53. {
  54. this.State = PhotonSocketState.Disconnecting;
  55. if (this.sock != null)
  56. {
  57. try
  58. {
  59. if (this.sock.Connected) this.sock.Close();
  60. }
  61. catch (Exception ex)
  62. {
  63. this.EnqueueDebugReturn(DebugLevel.INFO, "Exception in Dispose(): " + ex);
  64. }
  65. }
  66. this.sock = null;
  67. this.State = PhotonSocketState.Disconnected;
  68. }
  69. GameObject websocketConnectionObject;
  70. public override bool Connect()
  71. {
  72. //bool baseOk = base.Connect();
  73. //if (!baseOk)
  74. //{
  75. // return false;
  76. //}
  77. this.State = PhotonSocketState.Connecting;
  78. if (this.websocketConnectionObject != null)
  79. {
  80. UnityEngine.Object.Destroy(this.websocketConnectionObject);
  81. }
  82. this.websocketConnectionObject = new GameObject("websocketConnectionObject");
  83. MonoBehaviour mb = this.websocketConnectionObject.AddComponent<MonoBehaviourExt>();
  84. this.websocketConnectionObject.hideFlags = HideFlags.HideInHierarchy;
  85. UnityEngine.Object.DontDestroyOnLoad(this.websocketConnectionObject);
  86. this.sock = new WebSocket(new Uri(this.ServerAddress), SerializationProtocol); // TODO: The protocol should be set based on current PeerBase value (but that's currently not accessible)
  87. this.sock.Connect();
  88. mb.StartCoroutine(this.ReceiveLoop());
  89. return true;
  90. }
  91. public override bool Disconnect()
  92. {
  93. if (this.ReportDebugOfLevel(DebugLevel.INFO))
  94. {
  95. this.Listener.DebugReturn(DebugLevel.INFO, "SocketWebTcp.Disconnect()");
  96. }
  97. this.State = PhotonSocketState.Disconnecting;
  98. lock (this.syncer)
  99. {
  100. if (this.sock != null)
  101. {
  102. try
  103. {
  104. this.sock.Close();
  105. }
  106. catch (Exception ex)
  107. {
  108. this.Listener.DebugReturn(DebugLevel.ERROR, "Exception in Disconnect(): " + ex);
  109. }
  110. this.sock = null;
  111. }
  112. }
  113. if (this.websocketConnectionObject != null)
  114. {
  115. UnityEngine.Object.Destroy(this.websocketConnectionObject);
  116. }
  117. this.State = PhotonSocketState.Disconnected;
  118. return true;
  119. }
  120. /// <summary>
  121. /// used by TPeer*
  122. /// </summary>
  123. public override PhotonSocketError Send(byte[] data, int length)
  124. {
  125. if (this.State != PhotonSocketState.Connected)
  126. {
  127. return PhotonSocketError.Skipped;
  128. }
  129. try
  130. {
  131. if (data.Length > length)
  132. {
  133. byte[] trimmedData = new byte[length];
  134. Buffer.BlockCopy(data, 0, trimmedData, 0, length);
  135. data = trimmedData;
  136. }
  137. if (this.ReportDebugOfLevel(DebugLevel.ALL))
  138. {
  139. this.Listener.DebugReturn(DebugLevel.ALL, "Sending: " + SupportClassPun.ByteArrayToString(data));
  140. }
  141. if (this.sock != null)
  142. {
  143. this.sock.Send(data);
  144. }
  145. }
  146. catch (Exception e)
  147. {
  148. this.Listener.DebugReturn(DebugLevel.ERROR, "Cannot send to: " + this.ServerAddress + ". " + e.Message);
  149. this.HandleException(StatusCode.Exception);
  150. return PhotonSocketError.Exception;
  151. }
  152. return PhotonSocketError.Success;
  153. }
  154. public override PhotonSocketError Receive(out byte[] data)
  155. {
  156. data = null;
  157. return PhotonSocketError.NoData;
  158. }
  159. internal const int ALL_HEADER_BYTES = 9;
  160. internal const int TCP_HEADER_BYTES = 7;
  161. internal const int MSG_HEADER_BYTES = 2;
  162. public IEnumerator ReceiveLoop()
  163. {
  164. //this.Listener.DebugReturn(DebugLevel.INFO, "ReceiveLoop()");
  165. if (this.sock != null)
  166. {
  167. while (this.sock != null && !this.sock.Connected && this.sock.Error == null)
  168. {
  169. yield return new WaitForRealSeconds(0.1f);
  170. }
  171. if (this.sock != null)
  172. {
  173. if (this.sock.Error != null)
  174. {
  175. this.Listener.DebugReturn(DebugLevel.ERROR, "Exiting receive thread. Server: " + this.ServerAddress + ":" + this.ServerPort + " Error: " + this.sock.Error);
  176. this.HandleException(StatusCode.ExceptionOnConnect);
  177. }
  178. else
  179. {
  180. // connected
  181. if (this.ReportDebugOfLevel(DebugLevel.ALL))
  182. {
  183. this.Listener.DebugReturn(DebugLevel.ALL, "Receiving by websocket. this.State: " + this.State);
  184. }
  185. this.State = PhotonSocketState.Connected;
  186. while (this.State == PhotonSocketState.Connected)
  187. {
  188. if (this.sock != null)
  189. {
  190. if (this.sock.Error != null)
  191. {
  192. this.Listener.DebugReturn(DebugLevel.ERROR, "Exiting receive thread (inside loop). Server: " + this.ServerAddress + ":" + this.ServerPort + " Error: " + this.sock.Error);
  193. this.HandleException(StatusCode.ExceptionOnReceive);
  194. break;
  195. }
  196. else
  197. {
  198. byte[] inBuff = this.sock.Recv();
  199. if (inBuff == null || inBuff.Length == 0)
  200. {
  201. // nothing received. wait a bit, try again
  202. yield return new WaitForRealSeconds(0.02f);
  203. continue;
  204. }
  205. if (this.ReportDebugOfLevel(DebugLevel.ALL))
  206. {
  207. this.Listener.DebugReturn(DebugLevel.ALL, "TCP << " + inBuff.Length + " = " + SupportClassPun.ByteArrayToString(inBuff));
  208. }
  209. if (inBuff.Length > 0)
  210. {
  211. try
  212. {
  213. this.HandleReceivedDatagram(inBuff, inBuff.Length, false);
  214. }
  215. catch (Exception e)
  216. {
  217. if (this.State != PhotonSocketState.Disconnecting && this.State != PhotonSocketState.Disconnected)
  218. {
  219. if (this.ReportDebugOfLevel(DebugLevel.ERROR))
  220. {
  221. this.EnqueueDebugReturn(DebugLevel.ERROR, "Receive issue. State: " + this.State + ". Server: '" + this.ServerAddress + "' Exception: " + e);
  222. }
  223. this.HandleException(StatusCode.ExceptionOnReceive);
  224. }
  225. }
  226. }
  227. }
  228. }
  229. }
  230. }
  231. }
  232. }
  233. this.Disconnect();
  234. }
  235. private class MonoBehaviourExt : MonoBehaviour { }
  236. }
  237. }
  238. #endif