NetManager.cs 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039
  1. #if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA_8_1
  2. #if DEBUG
  3. #define STATS_ENABLED
  4. #endif
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Text;
  8. using System.Threading;
  9. using FlyingWormConsole3.LiteNetLib.Utils;
  10. namespace FlyingWormConsole3.LiteNetLib
  11. {
  12. public sealed class NetManager
  13. {
  14. internal delegate void OnMessageReceived(byte[] data, int length, int errorCode, NetEndPoint remoteEndPoint);
  15. private struct FlowMode
  16. {
  17. public int PacketsPerSecond;
  18. public int StartRtt;
  19. }
  20. private enum NetEventType
  21. {
  22. Connect,
  23. Disconnect,
  24. Receive,
  25. ReceiveUnconnected,
  26. Error,
  27. ConnectionLatencyUpdated,
  28. DiscoveryRequest,
  29. DiscoveryResponse
  30. }
  31. private sealed class NetEvent
  32. {
  33. public NetPeer Peer;
  34. public readonly NetDataReader DataReader = new NetDataReader();
  35. public NetEventType Type;
  36. public NetEndPoint RemoteEndPoint;
  37. public int AdditionalData;
  38. public DisconnectReason DisconnectReason;
  39. }
  40. #if DEBUG
  41. private struct IncomingData
  42. {
  43. public byte[] Data;
  44. public NetEndPoint EndPoint;
  45. public DateTime TimeWhenGet;
  46. }
  47. private readonly List<IncomingData> _pingSimulationList = new List<IncomingData>();
  48. private readonly Random _randomGenerator = new Random();
  49. private const int MinLatencyTreshold = 5;
  50. #endif
  51. private readonly NetSocket _socket;
  52. private readonly List<FlowMode> _flowModes;
  53. private readonly NetThread _logicThread;
  54. private readonly Queue<NetEvent> _netEventsQueue;
  55. private readonly Stack<NetEvent> _netEventsPool;
  56. private readonly INetEventListener _netEventListener;
  57. private readonly NetPeerCollection _peers;
  58. private readonly int _maxConnections;
  59. private readonly string _connectKey;
  60. private readonly NetPacketPool _netPacketPool;
  61. //config section
  62. public bool UnconnectedMessagesEnabled = false;
  63. public bool NatPunchEnabled = false;
  64. public int UpdateTime { get { return _logicThread.SleepTime; } set { _logicThread.SleepTime = value; } }
  65. public int PingInterval = NetConstants.DefaultPingInterval;
  66. public long DisconnectTimeout = 5000;
  67. public bool SimulatePacketLoss = false;
  68. public bool SimulateLatency = false;
  69. public int SimulationPacketLossChance = 10;
  70. public int SimulationMinLatency = 30;
  71. public int SimulationMaxLatency = 100;
  72. public bool UnsyncedEvents = false;
  73. public bool DiscoveryEnabled = false;
  74. public bool MergeEnabled = false;
  75. public int ReconnectDelay = 500;
  76. public int MaxConnectAttempts = 10;
  77. public bool ReuseAddress = false;
  78. private const int DefaultUpdateTime = 15;
  79. //stats
  80. public ulong PacketsSent { get; private set; }
  81. public ulong PacketsReceived { get; private set; }
  82. public ulong BytesSent { get; private set; }
  83. public ulong BytesReceived { get; private set; }
  84. //modules
  85. public readonly NatPunchModule NatPunchModule;
  86. /// <summary>
  87. /// Returns true if socket listening and update thread is running
  88. /// </summary>
  89. public bool IsRunning
  90. {
  91. get { return _logicThread.IsRunning; }
  92. }
  93. /// <summary>
  94. /// Local EndPoint (host and port)
  95. /// </summary>
  96. public NetEndPoint LocalEndPoint
  97. {
  98. get { return _socket.LocalEndPoint; }
  99. }
  100. /// <summary>
  101. /// Connected peers count
  102. /// </summary>
  103. public int PeersCount
  104. {
  105. get { return _peers.Count; }
  106. }
  107. public string ConnectKey
  108. {
  109. get { return _connectKey; }
  110. }
  111. //Flow
  112. public void AddFlowMode(int startRtt, int packetsPerSecond)
  113. {
  114. var fm = new FlowMode {PacketsPerSecond = packetsPerSecond, StartRtt = startRtt};
  115. if (_flowModes.Count > 0 && startRtt < _flowModes[0].StartRtt)
  116. {
  117. _flowModes.Insert(0, fm);
  118. }
  119. else
  120. {
  121. _flowModes.Add(fm);
  122. }
  123. }
  124. internal int GetPacketsPerSecond(int flowMode)
  125. {
  126. if (flowMode < 0 || _flowModes.Count == 0)
  127. return 0;
  128. return _flowModes[flowMode].PacketsPerSecond;
  129. }
  130. internal int GetMaxFlowMode()
  131. {
  132. return _flowModes.Count - 1;
  133. }
  134. internal int GetStartRtt(int flowMode)
  135. {
  136. if (flowMode < 0 || _flowModes.Count == 0)
  137. return 0;
  138. return _flowModes[flowMode].StartRtt;
  139. }
  140. internal NetPacketPool PacketPool
  141. {
  142. get { return _netPacketPool; }
  143. }
  144. /// <summary>
  145. /// NetManager constructor with maxConnections = 1 (usable for client)
  146. /// </summary>
  147. /// <param name="listener">Network events listener</param>
  148. /// <param name="connectKey">Application key (must be same with remote host for establish connection)</param>
  149. public NetManager(INetEventListener listener, string connectKey) : this(listener, 1, connectKey)
  150. {
  151. }
  152. /// <summary>
  153. /// NetManager constructor
  154. /// </summary>
  155. /// <param name="listener">Network events listener</param>
  156. /// <param name="maxConnections">Maximum connections (incoming and outcoming)</param>
  157. /// <param name="connectKey">Application key (must be same with remote host for establish connection)</param>
  158. public NetManager(INetEventListener listener, int maxConnections, string connectKey)
  159. {
  160. _logicThread = new NetThread("LogicThread", DefaultUpdateTime, UpdateLogic);
  161. _socket = new NetSocket(ReceiveLogic);
  162. _netEventListener = listener;
  163. _flowModes = new List<FlowMode>();
  164. _netEventsQueue = new Queue<NetEvent>();
  165. _netEventsPool = new Stack<NetEvent>();
  166. _netPacketPool = new NetPacketPool();
  167. NatPunchModule = new NatPunchModule(this);
  168. _connectKey = connectKey;
  169. _peers = new NetPeerCollection(maxConnections);
  170. _maxConnections = maxConnections;
  171. _connectKey = connectKey;
  172. }
  173. internal void ConnectionLatencyUpdated(NetPeer fromPeer, int latency)
  174. {
  175. var evt = CreateEvent(NetEventType.ConnectionLatencyUpdated);
  176. evt.Peer = fromPeer;
  177. evt.AdditionalData = latency;
  178. EnqueueEvent(evt);
  179. }
  180. internal bool SendRawAndRecycle(NetPacket packet, NetEndPoint remoteEndPoint)
  181. {
  182. var result = SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint);
  183. _netPacketPool.Recycle(packet);
  184. return result;
  185. }
  186. internal bool SendRaw(byte[] message, int start, int length, NetEndPoint remoteEndPoint)
  187. {
  188. if (!IsRunning)
  189. return false;
  190. int errorCode = 0;
  191. bool result = _socket.SendTo(message, start, length, remoteEndPoint, ref errorCode) > 0;
  192. //10040 message to long... need to check
  193. //10065 no route to host
  194. if (errorCode != 0 && errorCode != 10040 && errorCode != 10065)
  195. {
  196. //Send error
  197. NetPeer fromPeer;
  198. if (_peers.TryGetValue(remoteEndPoint, out fromPeer))
  199. {
  200. DisconnectPeer(fromPeer, DisconnectReason.SocketSendError, errorCode, false, null, 0, 0);
  201. }
  202. var netEvent = CreateEvent(NetEventType.Error);
  203. netEvent.RemoteEndPoint = remoteEndPoint;
  204. netEvent.AdditionalData = errorCode;
  205. EnqueueEvent(netEvent);
  206. return false;
  207. }
  208. if (errorCode == 10040)
  209. {
  210. NetUtils.DebugWrite(ConsoleColor.Red, "[SRD] 10040, datalen: {0}", length);
  211. return false;
  212. }
  213. #if STATS_ENABLED
  214. PacketsSent++;
  215. BytesSent += (uint)length;
  216. #endif
  217. return result;
  218. }
  219. private void DisconnectPeer(
  220. NetPeer peer,
  221. DisconnectReason reason,
  222. int socketErrorCode,
  223. bool sendDisconnectPacket,
  224. byte[] data,
  225. int start,
  226. int count)
  227. {
  228. if (sendDisconnectPacket)
  229. {
  230. if (count + 8 >= peer.Mtu)
  231. {
  232. //Drop additional data
  233. data = null;
  234. count = 0;
  235. NetUtils.DebugWriteError("[NM] Disconnect additional data size more than MTU - 8!");
  236. }
  237. var disconnectPacket = _netPacketPool.Get(PacketProperty.Disconnect, 8 + count);
  238. FastBitConverter.GetBytes(disconnectPacket.RawData, 1, peer.ConnectId);
  239. if (data != null)
  240. {
  241. Buffer.BlockCopy(data, start, disconnectPacket.RawData, 9, count);
  242. }
  243. SendRawAndRecycle(disconnectPacket, peer.EndPoint);
  244. }
  245. var netEvent = CreateEvent(NetEventType.Disconnect);
  246. netEvent.Peer = peer;
  247. netEvent.AdditionalData = socketErrorCode;
  248. netEvent.DisconnectReason = reason;
  249. EnqueueEvent(netEvent);
  250. RemovePeer(peer.EndPoint);
  251. }
  252. private void ClearPeers()
  253. {
  254. lock (_peers)
  255. {
  256. #if WINRT && !UNITY_EDITOR
  257. _socket.ClearPeers();
  258. #endif
  259. _peers.Clear();
  260. }
  261. }
  262. private void RemovePeer(NetEndPoint endPoint)
  263. {
  264. _peers.Remove(endPoint);
  265. #if WINRT && !UNITY_EDITOR
  266. _socket.RemovePeer(endPoint);
  267. #endif
  268. }
  269. private void RemovePeerAt(int idx)
  270. {
  271. #if WINRT && !UNITY_EDITOR
  272. var endPoint = _peers[idx].EndPoint;
  273. _socket.RemovePeer(endPoint);
  274. #endif
  275. _peers.RemoveAt(idx);
  276. }
  277. private NetEvent CreateEvent(NetEventType type)
  278. {
  279. NetEvent evt = null;
  280. lock (_netEventsPool)
  281. {
  282. if (_netEventsPool.Count > 0)
  283. {
  284. evt = _netEventsPool.Pop();
  285. }
  286. }
  287. if(evt == null)
  288. {
  289. evt = new NetEvent();
  290. }
  291. evt.Type = type;
  292. return evt;
  293. }
  294. private void EnqueueEvent(NetEvent evt)
  295. {
  296. if (UnsyncedEvents)
  297. {
  298. ProcessEvent(evt);
  299. }
  300. else
  301. {
  302. lock (_netEventsQueue)
  303. {
  304. _netEventsQueue.Enqueue(evt);
  305. }
  306. }
  307. }
  308. private void ProcessEvent(NetEvent evt)
  309. {
  310. switch (evt.Type)
  311. {
  312. case NetEventType.Connect:
  313. _netEventListener.OnPeerConnected(evt.Peer);
  314. break;
  315. case NetEventType.Disconnect:
  316. var info = new DisconnectInfo
  317. {
  318. Reason = evt.DisconnectReason,
  319. AdditionalData = evt.DataReader,
  320. SocketErrorCode = evt.AdditionalData
  321. };
  322. _netEventListener.OnPeerDisconnected(evt.Peer, info);
  323. break;
  324. case NetEventType.Receive:
  325. _netEventListener.OnNetworkReceive(evt.Peer, evt.DataReader);
  326. break;
  327. case NetEventType.ReceiveUnconnected:
  328. _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.Default);
  329. break;
  330. case NetEventType.DiscoveryRequest:
  331. _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.DiscoveryRequest);
  332. break;
  333. case NetEventType.DiscoveryResponse:
  334. _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.DiscoveryResponse);
  335. break;
  336. case NetEventType.Error:
  337. _netEventListener.OnNetworkError(evt.RemoteEndPoint, evt.AdditionalData);
  338. break;
  339. case NetEventType.ConnectionLatencyUpdated:
  340. _netEventListener.OnNetworkLatencyUpdate(evt.Peer, evt.AdditionalData);
  341. break;
  342. }
  343. //Recycle
  344. evt.DataReader.Clear();
  345. evt.Peer = null;
  346. evt.AdditionalData = 0;
  347. evt.RemoteEndPoint = null;
  348. lock (_netEventsPool)
  349. {
  350. _netEventsPool.Push(evt);
  351. }
  352. }
  353. //Update function
  354. private void UpdateLogic()
  355. {
  356. #if DEBUG
  357. if (SimulateLatency)
  358. {
  359. var time = DateTime.UtcNow;
  360. lock (_pingSimulationList)
  361. {
  362. for (int i = 0; i < _pingSimulationList.Count; i++)
  363. {
  364. var incomingData = _pingSimulationList[i];
  365. if (incomingData.TimeWhenGet <= time)
  366. {
  367. DataReceived(incomingData.Data, incomingData.Data.Length, incomingData.EndPoint);
  368. _pingSimulationList.RemoveAt(i);
  369. i--;
  370. }
  371. }
  372. }
  373. }
  374. #endif
  375. //Process acks
  376. lock (_peers)
  377. {
  378. int delta = _logicThread.SleepTime;
  379. for(int i = 0; i < _peers.Count; i++)
  380. {
  381. var netPeer = _peers[i];
  382. if (netPeer.ConnectionState == ConnectionState.Connected && netPeer.TimeSinceLastPacket > DisconnectTimeout)
  383. {
  384. NetUtils.DebugWrite("[NM] Disconnect by timeout: {0} > {1}", netPeer.TimeSinceLastPacket, DisconnectTimeout);
  385. var netEvent = CreateEvent(NetEventType.Disconnect);
  386. netEvent.Peer = netPeer;
  387. netEvent.DisconnectReason = DisconnectReason.Timeout;
  388. EnqueueEvent(netEvent);
  389. RemovePeerAt(i);
  390. i--;
  391. }
  392. else if(netPeer.ConnectionState == ConnectionState.Disconnected)
  393. {
  394. var netEvent = CreateEvent(NetEventType.Disconnect);
  395. netEvent.Peer = netPeer;
  396. netEvent.DisconnectReason = DisconnectReason.ConnectionFailed;
  397. EnqueueEvent(netEvent);
  398. RemovePeerAt(i);
  399. i--;
  400. }
  401. else
  402. {
  403. netPeer.Update(delta);
  404. }
  405. }
  406. }
  407. }
  408. private void ReceiveLogic(byte[] data, int length, int errorCode, NetEndPoint remoteEndPoint)
  409. {
  410. //Receive some info
  411. if (errorCode == 0)
  412. {
  413. #if DEBUG
  414. bool receivePacket = true;
  415. if (SimulatePacketLoss && _randomGenerator.Next(100/SimulationPacketLossChance) == 0)
  416. {
  417. receivePacket = false;
  418. }
  419. else if (SimulateLatency)
  420. {
  421. int latency = _randomGenerator.Next(SimulationMinLatency, SimulationMaxLatency);
  422. if (latency > MinLatencyTreshold)
  423. {
  424. byte[] holdedData = new byte[length];
  425. Buffer.BlockCopy(data, 0, holdedData, 0, length);
  426. lock (_pingSimulationList)
  427. {
  428. _pingSimulationList.Add(new IncomingData
  429. {
  430. Data = holdedData,
  431. EndPoint = remoteEndPoint,
  432. TimeWhenGet = DateTime.UtcNow.AddMilliseconds(latency)
  433. });
  434. }
  435. receivePacket = false;
  436. }
  437. }
  438. if (receivePacket) //DataReceived
  439. #endif
  440. //ProcessEvents
  441. DataReceived(data, length, remoteEndPoint);
  442. }
  443. else //Error on receive
  444. {
  445. ClearPeers();
  446. var netEvent = CreateEvent(NetEventType.Error);
  447. netEvent.AdditionalData = errorCode;
  448. EnqueueEvent(netEvent);
  449. }
  450. }
  451. private void DataReceived(byte[] reusableBuffer, int count, NetEndPoint remoteEndPoint)
  452. {
  453. #if STATS_ENABLED
  454. PacketsReceived++;
  455. BytesReceived += (uint) count;
  456. #endif
  457. //Try read packet
  458. NetPacket packet = _netPacketPool.GetAndRead(reusableBuffer, 0, count);
  459. if (packet == null)
  460. {
  461. NetUtils.DebugWriteError("[NM] DataReceived: bad!");
  462. return;
  463. }
  464. //Check unconnected
  465. switch (packet.Property)
  466. {
  467. case PacketProperty.DiscoveryRequest:
  468. if(DiscoveryEnabled)
  469. {
  470. var netEvent = CreateEvent(NetEventType.DiscoveryRequest);
  471. netEvent.RemoteEndPoint = remoteEndPoint;
  472. netEvent.DataReader.SetSource(packet.RawData, NetConstants.HeaderSize);
  473. EnqueueEvent(netEvent);
  474. }
  475. return;
  476. case PacketProperty.DiscoveryResponse:
  477. {
  478. var netEvent = CreateEvent(NetEventType.DiscoveryResponse);
  479. netEvent.RemoteEndPoint = remoteEndPoint;
  480. netEvent.DataReader.SetSource(packet.RawData, NetConstants.HeaderSize);
  481. EnqueueEvent(netEvent);
  482. }
  483. return;
  484. case PacketProperty.UnconnectedMessage:
  485. if (UnconnectedMessagesEnabled)
  486. {
  487. var netEvent = CreateEvent(NetEventType.ReceiveUnconnected);
  488. netEvent.RemoteEndPoint = remoteEndPoint;
  489. netEvent.DataReader.SetSource(packet.RawData, NetConstants.HeaderSize);
  490. EnqueueEvent(netEvent);
  491. }
  492. return;
  493. case PacketProperty.NatIntroduction:
  494. case PacketProperty.NatIntroductionRequest:
  495. case PacketProperty.NatPunchMessage:
  496. {
  497. if (NatPunchEnabled)
  498. NatPunchModule.ProcessMessage(remoteEndPoint, packet);
  499. return;
  500. }
  501. }
  502. //Check normal packets
  503. NetPeer netPeer;
  504. //Check peers
  505. Monitor.Enter(_peers);
  506. int peersCount = _peers.Count;
  507. if (_peers.TryGetValue(remoteEndPoint, out netPeer))
  508. {
  509. Monitor.Exit(_peers);
  510. //Send
  511. if (packet.Property == PacketProperty.Disconnect)
  512. {
  513. if (BitConverter.ToInt64(packet.RawData, 1) != netPeer.ConnectId)
  514. {
  515. //Old or incorrect disconnect
  516. _netPacketPool.Recycle(packet);
  517. return;
  518. }
  519. var netEvent = CreateEvent(NetEventType.Disconnect);
  520. netEvent.Peer = netPeer;
  521. netEvent.DataReader.SetSource(packet.RawData, 5, packet.Size - 5);
  522. netEvent.DisconnectReason = DisconnectReason.RemoteConnectionClose;
  523. EnqueueEvent(netEvent);
  524. _peers.Remove(netPeer.EndPoint);
  525. //do not recycle because no sense)
  526. }
  527. else if (packet.Property == PacketProperty.ConnectAccept)
  528. {
  529. if (netPeer.ProcessConnectAccept(packet))
  530. {
  531. var connectEvent = CreateEvent(NetEventType.Connect);
  532. connectEvent.Peer = netPeer;
  533. EnqueueEvent(connectEvent);
  534. }
  535. _netPacketPool.Recycle(packet);
  536. }
  537. else
  538. {
  539. netPeer.ProcessPacket(packet);
  540. }
  541. return;
  542. }
  543. try
  544. {
  545. if (peersCount < _maxConnections && packet.Property == PacketProperty.ConnectRequest)
  546. {
  547. int protoId = BitConverter.ToInt32(packet.RawData, 1);
  548. if (protoId != NetConstants.ProtocolId)
  549. {
  550. NetUtils.DebugWrite(ConsoleColor.Cyan,
  551. "[NM] Peer connect reject. Invalid protocol ID: " + protoId);
  552. return;
  553. }
  554. string peerKey = Encoding.UTF8.GetString(packet.RawData, 13, packet.Size - 13);
  555. if (peerKey != _connectKey)
  556. {
  557. NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Peer connect reject. Invalid key: " + peerKey);
  558. return;
  559. }
  560. //Getting new id for peer
  561. long connectionId = BitConverter.ToInt64(packet.RawData, 5);
  562. //response with id
  563. netPeer = new NetPeer(this, remoteEndPoint, connectionId);
  564. NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Received peer connect request Id: {0}, EP: {1}",
  565. netPeer.ConnectId, remoteEndPoint);
  566. //clean incoming packet
  567. _netPacketPool.Recycle(packet);
  568. _peers.Add(remoteEndPoint, netPeer);
  569. var netEvent = CreateEvent(NetEventType.Connect);
  570. netEvent.Peer = netPeer;
  571. EnqueueEvent(netEvent);
  572. }
  573. }
  574. finally
  575. {
  576. Monitor.Exit(_peers);
  577. }
  578. }
  579. internal void ReceiveFromPeer(NetPacket packet, NetEndPoint remoteEndPoint)
  580. {
  581. NetPeer fromPeer;
  582. if (_peers.TryGetValue(remoteEndPoint, out fromPeer))
  583. {
  584. NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Received message");
  585. var netEvent = CreateEvent(NetEventType.Receive);
  586. netEvent.Peer = fromPeer;
  587. netEvent.RemoteEndPoint = fromPeer.EndPoint;
  588. netEvent.DataReader.SetSource(packet.GetPacketData());
  589. EnqueueEvent(netEvent);
  590. }
  591. }
  592. /// <summary>
  593. /// Send data to all connected peers
  594. /// </summary>
  595. /// <param name="writer">DataWriter with data</param>
  596. /// <param name="options">Send options (reliable, unreliable, etc.)</param>
  597. public void SendToAll(NetDataWriter writer, SendOptions options)
  598. {
  599. SendToAll(writer.Data, 0, writer.Length, options);
  600. }
  601. /// <summary>
  602. /// Send data to all connected peers
  603. /// </summary>
  604. /// <param name="data">Data</param>
  605. /// <param name="options">Send options (reliable, unreliable, etc.)</param>
  606. public void SendToAll(byte[] data, SendOptions options)
  607. {
  608. SendToAll(data, 0, data.Length, options);
  609. }
  610. /// <summary>
  611. /// Send data to all connected peers
  612. /// </summary>
  613. /// <param name="data">Data</param>
  614. /// <param name="start">Start of data</param>
  615. /// <param name="length">Length of data</param>
  616. /// <param name="options">Send options (reliable, unreliable, etc.)</param>
  617. public void SendToAll(byte[] data, int start, int length, SendOptions options)
  618. {
  619. lock (_peers)
  620. {
  621. for(int i = 0; i < _peers.Count; i++)
  622. {
  623. _peers[i].Send(data, start, length, options);
  624. }
  625. }
  626. }
  627. /// <summary>
  628. /// Send data to all connected peers
  629. /// </summary>
  630. /// <param name="writer">DataWriter with data</param>
  631. /// <param name="options">Send options (reliable, unreliable, etc.)</param>
  632. /// <param name="excludePeer">Excluded peer</param>
  633. public void SendToAll(NetDataWriter writer, SendOptions options, NetPeer excludePeer)
  634. {
  635. SendToAll(writer.Data, 0, writer.Length, options, excludePeer);
  636. }
  637. /// <summary>
  638. /// Send data to all connected peers
  639. /// </summary>
  640. /// <param name="data">Data</param>
  641. /// <param name="options">Send options (reliable, unreliable, etc.)</param>
  642. /// <param name="excludePeer">Excluded peer</param>
  643. public void SendToAll(byte[] data, SendOptions options, NetPeer excludePeer)
  644. {
  645. SendToAll(data, 0, data.Length, options, excludePeer);
  646. }
  647. /// <summary>
  648. /// Send data to all connected peers
  649. /// </summary>
  650. /// <param name="data">Data</param>
  651. /// <param name="start">Start of data</param>
  652. /// <param name="length">Length of data</param>
  653. /// <param name="options">Send options (reliable, unreliable, etc.)</param>
  654. /// <param name="excludePeer">Excluded peer</param>
  655. public void SendToAll(byte[] data, int start, int length, SendOptions options, NetPeer excludePeer)
  656. {
  657. lock (_peers)
  658. {
  659. for (int i = 0; i < _peers.Count; i++)
  660. {
  661. var netPeer = _peers[i];
  662. if (netPeer != excludePeer)
  663. {
  664. netPeer.Send(data, start, length, options);
  665. }
  666. }
  667. }
  668. }
  669. /// <summary>
  670. /// Start logic thread and listening on available port
  671. /// </summary>
  672. public bool Start()
  673. {
  674. return Start(0);
  675. }
  676. /// <summary>
  677. /// Start logic thread and listening on selected port
  678. /// </summary>
  679. /// <param name="port">port to listen</param>
  680. public bool Start(int port)
  681. {
  682. if (IsRunning)
  683. {
  684. return false;
  685. }
  686. _netEventsQueue.Clear();
  687. if (!_socket.Bind(port, ReuseAddress))
  688. return false;
  689. _logicThread.Start();
  690. return true;
  691. }
  692. /// <summary>
  693. /// Send message without connection
  694. /// </summary>
  695. /// <param name="message">Raw data</param>
  696. /// <param name="remoteEndPoint">Packet destination</param>
  697. /// <returns>Operation result</returns>
  698. public bool SendUnconnectedMessage(byte[] message, NetEndPoint remoteEndPoint)
  699. {
  700. return SendUnconnectedMessage(message, 0, message.Length, remoteEndPoint);
  701. }
  702. /// <summary>
  703. /// Send message without connection
  704. /// </summary>
  705. /// <param name="writer">Data serializer</param>
  706. /// <param name="remoteEndPoint">Packet destination</param>
  707. /// <returns>Operation result</returns>
  708. public bool SendUnconnectedMessage(NetDataWriter writer, NetEndPoint remoteEndPoint)
  709. {
  710. return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint);
  711. }
  712. /// <summary>
  713. /// Send message without connection
  714. /// </summary>
  715. /// <param name="message">Raw data</param>
  716. /// <param name="start">data start</param>
  717. /// <param name="length">data length</param>
  718. /// <param name="remoteEndPoint">Packet destination</param>
  719. /// <returns>Operation result</returns>
  720. public bool SendUnconnectedMessage(byte[] message, int start, int length, NetEndPoint remoteEndPoint)
  721. {
  722. if (!IsRunning)
  723. return false;
  724. var packet = _netPacketPool.GetWithData(PacketProperty.UnconnectedMessage, message, start, length);
  725. bool result = SendRawAndRecycle(packet, remoteEndPoint);
  726. return result;
  727. }
  728. public bool SendDiscoveryRequest(NetDataWriter writer, int port)
  729. {
  730. return SendDiscoveryRequest(writer.Data, 0, writer.Length, port);
  731. }
  732. public bool SendDiscoveryRequest(byte[] data, int port)
  733. {
  734. return SendDiscoveryRequest(data, 0, data.Length, port);
  735. }
  736. public bool SendDiscoveryRequest(byte[] data, int start, int length, int port)
  737. {
  738. if (!IsRunning)
  739. return false;
  740. var packet = _netPacketPool.GetWithData(PacketProperty.DiscoveryRequest, data, start, length);
  741. bool result = _socket.SendBroadcast(packet.RawData, 0, packet.Size, port);
  742. _netPacketPool.Recycle(packet);
  743. return result;
  744. }
  745. public bool SendDiscoveryResponse(NetDataWriter writer, NetEndPoint remoteEndPoint)
  746. {
  747. return SendDiscoveryResponse(writer.Data, 0, writer.Length, remoteEndPoint);
  748. }
  749. public bool SendDiscoveryResponse(byte[] data, NetEndPoint remoteEndPoint)
  750. {
  751. return SendDiscoveryResponse(data, 0, data.Length, remoteEndPoint);
  752. }
  753. public bool SendDiscoveryResponse(byte[] data, int start, int length, NetEndPoint remoteEndPoint)
  754. {
  755. if (!IsRunning)
  756. return false;
  757. var packet = _netPacketPool.GetWithData(PacketProperty.DiscoveryResponse, data, start, length);
  758. bool result = SendRawAndRecycle(packet, remoteEndPoint);
  759. return result;
  760. }
  761. /// <summary>
  762. /// Flush all queued packets of all peers
  763. /// </summary>
  764. public void Flush()
  765. {
  766. lock (_peers)
  767. {
  768. for (int i = 0; i < _peers.Count; i++)
  769. {
  770. _peers[i].Flush();
  771. }
  772. }
  773. }
  774. /// <summary>
  775. /// Receive all pending events. Call this in game update code
  776. /// </summary>
  777. public void PollEvents()
  778. {
  779. if (UnsyncedEvents)
  780. return;
  781. while (_netEventsQueue.Count > 0)
  782. {
  783. NetEvent evt;
  784. lock (_netEventsQueue)
  785. {
  786. evt = _netEventsQueue.Dequeue();
  787. }
  788. ProcessEvent(evt);
  789. }
  790. }
  791. /// <summary>
  792. /// Connect to remote host
  793. /// </summary>
  794. /// <param name="address">Server IP or hostname</param>
  795. /// <param name="port">Server Port</param>
  796. public void Connect(string address, int port)
  797. {
  798. //Create target endpoint
  799. NetEndPoint ep = new NetEndPoint(address, port);
  800. Connect(ep);
  801. }
  802. /// <summary>
  803. /// Connect to remote host
  804. /// </summary>
  805. /// <param name="target">Server end point (ip and port)</param>
  806. public void Connect(NetEndPoint target)
  807. {
  808. if (!IsRunning)
  809. {
  810. throw new Exception("Client is not running");
  811. }
  812. lock (_peers)
  813. {
  814. if (_peers.ContainsAddress(target) || _peers.Count >= _maxConnections)
  815. {
  816. //Already connected
  817. return;
  818. }
  819. //Create reliable connection
  820. //And request connection
  821. var newPeer = new NetPeer(this, target, 0);
  822. _peers.Add(target, newPeer);
  823. }
  824. }
  825. /// <summary>
  826. /// Force closes connection and stop all threads.
  827. /// </summary>
  828. public void Stop()
  829. {
  830. //Send disconnect packets
  831. lock (_peers)
  832. {
  833. for (int i = 0; i < _peers.Count; i++)
  834. {
  835. var disconnectPacket = _netPacketPool.Get(PacketProperty.Disconnect, 8);
  836. FastBitConverter.GetBytes(disconnectPacket.RawData, 1, _peers[i].ConnectId);
  837. SendRawAndRecycle(disconnectPacket, _peers[i].EndPoint);
  838. }
  839. }
  840. //Clear
  841. ClearPeers();
  842. //Stop
  843. if (IsRunning)
  844. {
  845. _logicThread.Stop();
  846. _socket.Close();
  847. }
  848. }
  849. /// <summary>
  850. /// Get first peer. Usefull for Client mode
  851. /// </summary>
  852. /// <returns></returns>
  853. public NetPeer GetFirstPeer()
  854. {
  855. lock (_peers)
  856. {
  857. if (_peers.Count > 0)
  858. {
  859. return _peers[0];
  860. }
  861. }
  862. return null;
  863. }
  864. /// <summary>
  865. /// Get copy of current connected peers
  866. /// </summary>
  867. /// <returns>Array with connected peers</returns>
  868. public NetPeer[] GetPeers()
  869. {
  870. NetPeer[] peers;
  871. lock (_peers)
  872. {
  873. peers = _peers.ToArray();
  874. }
  875. return peers;
  876. }
  877. /// <summary>
  878. /// Get copy of current connected peers (without allocations)
  879. /// </summary>
  880. /// <param name="peers">List that will contain result</param>
  881. public void GetPeersNonAlloc(List<NetPeer> peers)
  882. {
  883. peers.Clear();
  884. lock (_peers)
  885. {
  886. for(int i = 0; i < _peers.Count; i++)
  887. {
  888. peers.Add(_peers[i]);
  889. }
  890. }
  891. }
  892. /// <summary>
  893. /// Disconnect peer from server
  894. /// </summary>
  895. /// <param name="peer">peer to disconnect</param>
  896. public void DisconnectPeer(NetPeer peer)
  897. {
  898. DisconnectPeer(peer, null, 0, 0);
  899. }
  900. /// <summary>
  901. /// Disconnect peer from server and send additional data (Size must be less or equal MTU - 8)
  902. /// </summary>
  903. /// <param name="peer">peer to disconnect</param>
  904. /// <param name="data">additional data</param>
  905. public void DisconnectPeer(NetPeer peer, byte[] data)
  906. {
  907. DisconnectPeer(peer, data, 0, data.Length);
  908. }
  909. /// <summary>
  910. /// Disconnect peer from server and send additional data (Size must be less or equal MTU - 8)
  911. /// </summary>
  912. /// <param name="peer">peer to disconnect</param>
  913. /// <param name="writer">additional data</param>
  914. public void DisconnectPeer(NetPeer peer, NetDataWriter writer)
  915. {
  916. DisconnectPeer(peer, writer.Data, 0, writer.Length);
  917. }
  918. /// <summary>
  919. /// Disconnect peer from server and send additional data (Size must be less or equal MTU - 8)
  920. /// </summary>
  921. /// <param name="peer">peer to disconnect</param>
  922. /// <param name="data">additional data</param>
  923. /// <param name="start">data start</param>
  924. /// <param name="count">data length</param>
  925. public void DisconnectPeer(NetPeer peer, byte[] data, int start, int count)
  926. {
  927. if (peer != null && _peers.ContainsAddress(peer.EndPoint))
  928. {
  929. DisconnectPeer(peer, DisconnectReason.DisconnectPeerCalled, 0, true, data, start, count);
  930. }
  931. }
  932. }
  933. }
  934. #endif