ENet.cs 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  1. /*
  2. * Managed C# wrapper for an extended version of ENet
  3. * Copyright (c) 2019 Matt Coburn (SoftwareGuy/Coburn64), Chris Burns (c6burns)
  4. * Copyright (c) 2013 - 2018 James Bellinger, Nate Shoffner, Stanislav Denisov
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. using System;
  25. using System.Runtime.InteropServices;
  26. using System.Security;
  27. using System.Text;
  28. namespace ENet
  29. {
  30. [Flags]
  31. public enum PacketFlags
  32. {
  33. None = 0,
  34. Reliable = 1 << 0,
  35. Unsequenced = 1 << 1,
  36. NoAllocate = 1 << 2,
  37. UnreliableFragmented = 1 << 3,
  38. Instant = 1 << 4
  39. }
  40. public enum EventType
  41. {
  42. None = 0,
  43. Connect = 1,
  44. Disconnect = 2,
  45. Receive = 3,
  46. Timeout = 4
  47. }
  48. public enum PeerState
  49. {
  50. Uninitialized = -1,
  51. Disconnected = 0,
  52. Connecting = 1,
  53. AcknowledgingConnect = 2,
  54. ConnectionPending = 3,
  55. ConnectionSucceeded = 4,
  56. Connected = 5,
  57. DisconnectLater = 6,
  58. Disconnecting = 7,
  59. AcknowledgingDisconnect = 8,
  60. Zombie = 9
  61. }
  62. [StructLayout(LayoutKind.Explicit, Size = 18)]
  63. internal struct ENetAddress
  64. {
  65. [FieldOffset(16)]
  66. public ushort port;
  67. }
  68. [StructLayout(LayoutKind.Sequential)]
  69. internal struct ENetEvent
  70. {
  71. public EventType type;
  72. public IntPtr peer;
  73. public byte channelID;
  74. public uint data;
  75. public IntPtr packet;
  76. }
  77. [StructLayout(LayoutKind.Sequential)]
  78. internal struct ENetCallbacks
  79. {
  80. public AllocCallback malloc;
  81. public FreeCallback free;
  82. public NoMemoryCallback noMemory;
  83. }
  84. public delegate IntPtr AllocCallback(IntPtr size);
  85. public delegate void FreeCallback(IntPtr memory);
  86. public delegate void NoMemoryCallback();
  87. public delegate void PacketFreeCallback(Packet packet);
  88. internal static class ArrayPool
  89. {
  90. [ThreadStatic]
  91. private static byte[] byteBuffer;
  92. [ThreadStatic]
  93. private static IntPtr[] pointerBuffer;
  94. public static byte[] GetByteBuffer()
  95. {
  96. if (byteBuffer == null)
  97. byteBuffer = new byte[64];
  98. return byteBuffer;
  99. }
  100. public static IntPtr[] GetPointerBuffer()
  101. {
  102. if (pointerBuffer == null)
  103. pointerBuffer = new IntPtr[Library.maxPeers];
  104. return pointerBuffer;
  105. }
  106. }
  107. public struct Address
  108. {
  109. private ENetAddress nativeAddress;
  110. internal ENetAddress NativeData {
  111. get {
  112. return nativeAddress;
  113. }
  114. set {
  115. nativeAddress = value;
  116. }
  117. }
  118. internal Address(ENetAddress address)
  119. {
  120. nativeAddress = address;
  121. }
  122. public ushort Port {
  123. get {
  124. return nativeAddress.port;
  125. }
  126. set {
  127. nativeAddress.port = value;
  128. }
  129. }
  130. public string GetIP()
  131. {
  132. StringBuilder ip = new StringBuilder(1024);
  133. if (Native.enet_address_get_host_ip(nativeAddress, ip, (IntPtr)ip.Capacity) != 0)
  134. return String.Empty;
  135. return ip.ToString();
  136. }
  137. public bool SetIP(string ip)
  138. {
  139. if (ip == null)
  140. throw new ArgumentNullException("ip");
  141. return Native.enet_address_set_host_ip(ref nativeAddress, ip) == 0;
  142. }
  143. public string GetHost()
  144. {
  145. StringBuilder hostName = new StringBuilder(1024);
  146. if (Native.enet_address_get_host(nativeAddress, hostName, (IntPtr)hostName.Capacity) != 0)
  147. return String.Empty;
  148. return hostName.ToString();
  149. }
  150. public bool SetHost(string hostName)
  151. {
  152. if (hostName == null)
  153. throw new ArgumentNullException("hostName");
  154. return Native.enet_address_set_host(ref nativeAddress, hostName) == 0;
  155. }
  156. }
  157. public struct Event
  158. {
  159. private ENetEvent nativeEvent;
  160. internal ENetEvent NativeData {
  161. get {
  162. return nativeEvent;
  163. }
  164. set {
  165. nativeEvent = value;
  166. }
  167. }
  168. internal Event(ENetEvent @event)
  169. {
  170. nativeEvent = @event;
  171. }
  172. public EventType Type {
  173. get {
  174. return nativeEvent.type;
  175. }
  176. }
  177. public Peer Peer {
  178. get {
  179. return new Peer(nativeEvent.peer);
  180. }
  181. }
  182. public byte ChannelID {
  183. get {
  184. return nativeEvent.channelID;
  185. }
  186. }
  187. public uint Data {
  188. get {
  189. return nativeEvent.data;
  190. }
  191. }
  192. public Packet Packet {
  193. get {
  194. return new Packet(nativeEvent.packet);
  195. }
  196. }
  197. }
  198. public class Callbacks
  199. {
  200. private ENetCallbacks nativeCallbacks;
  201. internal ENetCallbacks NativeData {
  202. get {
  203. return nativeCallbacks;
  204. }
  205. set {
  206. nativeCallbacks = value;
  207. }
  208. }
  209. public Callbacks(AllocCallback allocCallback, FreeCallback freeCallback, NoMemoryCallback noMemoryCallback)
  210. {
  211. nativeCallbacks.malloc = allocCallback;
  212. nativeCallbacks.free = freeCallback;
  213. nativeCallbacks.noMemory = noMemoryCallback;
  214. }
  215. }
  216. public struct Packet : IDisposable
  217. {
  218. private IntPtr nativePacket;
  219. internal IntPtr NativeData {
  220. get {
  221. return nativePacket;
  222. }
  223. set {
  224. nativePacket = value;
  225. }
  226. }
  227. internal Packet(IntPtr packet)
  228. {
  229. nativePacket = packet;
  230. }
  231. public void Dispose()
  232. {
  233. if (nativePacket != IntPtr.Zero)
  234. {
  235. Native.enet_packet_dispose(nativePacket);
  236. nativePacket = IntPtr.Zero;
  237. }
  238. }
  239. public bool IsSet {
  240. get {
  241. return nativePacket != IntPtr.Zero;
  242. }
  243. }
  244. public IntPtr Data {
  245. get {
  246. CheckCreated();
  247. return Native.enet_packet_get_data(nativePacket);
  248. }
  249. }
  250. public int Length {
  251. get {
  252. CheckCreated();
  253. return Native.enet_packet_get_length(nativePacket);
  254. }
  255. }
  256. public bool HasReferences {
  257. get {
  258. CheckCreated();
  259. return Native.enet_packet_check_references(nativePacket) != 0;
  260. }
  261. }
  262. internal void CheckCreated()
  263. {
  264. if (nativePacket == IntPtr.Zero)
  265. throw new InvalidOperationException("Packet not created");
  266. }
  267. public void SetFreeCallback(IntPtr callback)
  268. {
  269. CheckCreated();
  270. Native.enet_packet_set_free_callback(nativePacket, callback);
  271. }
  272. public void SetFreeCallback(PacketFreeCallback callback)
  273. {
  274. CheckCreated();
  275. Native.enet_packet_set_free_callback(nativePacket, Marshal.GetFunctionPointerForDelegate(callback));
  276. }
  277. public void Create(byte[] data)
  278. {
  279. if (data == null)
  280. throw new ArgumentNullException("data");
  281. Create(data, data.Length);
  282. }
  283. public void Create(byte[] data, int length)
  284. {
  285. Create(data, length, PacketFlags.None);
  286. }
  287. public void Create(byte[] data, PacketFlags flags)
  288. {
  289. Create(data, data.Length, flags);
  290. }
  291. public void Create(byte[] data, int length, PacketFlags flags)
  292. {
  293. if (data == null)
  294. throw new ArgumentNullException("data");
  295. if (length < 0 || length > data.Length)
  296. throw new ArgumentOutOfRangeException();
  297. nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags);
  298. }
  299. public void Create(IntPtr data, int length, PacketFlags flags)
  300. {
  301. if (data == IntPtr.Zero)
  302. throw new ArgumentNullException("data");
  303. if (length < 0)
  304. throw new ArgumentOutOfRangeException();
  305. nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags);
  306. }
  307. public void Create(byte[] data, int offset, int length, PacketFlags flags)
  308. {
  309. if (data == null)
  310. throw new ArgumentNullException("data");
  311. if (offset < 0 || length < 0 || length > data.Length)
  312. throw new ArgumentOutOfRangeException();
  313. nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags);
  314. }
  315. public void Create(IntPtr data, int offset, int length, PacketFlags flags)
  316. {
  317. if (data == IntPtr.Zero)
  318. throw new ArgumentNullException("data");
  319. if (offset < 0 || length < 0)
  320. throw new ArgumentOutOfRangeException();
  321. nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags);
  322. }
  323. public void CopyTo(byte[] destination)
  324. {
  325. if (destination == null)
  326. throw new ArgumentNullException("destination");
  327. if (Data == null)
  328. {
  329. return;
  330. }
  331. Marshal.Copy(Data, destination, 0, Length);
  332. }
  333. }
  334. public class Host : IDisposable
  335. {
  336. private IntPtr nativeHost;
  337. internal IntPtr NativeData {
  338. get {
  339. return nativeHost;
  340. }
  341. set {
  342. nativeHost = value;
  343. }
  344. }
  345. public void Dispose()
  346. {
  347. Dispose(true);
  348. GC.SuppressFinalize(this);
  349. }
  350. protected virtual void Dispose(bool disposing)
  351. {
  352. if (nativeHost != IntPtr.Zero)
  353. {
  354. Native.enet_host_destroy(nativeHost);
  355. nativeHost = IntPtr.Zero;
  356. }
  357. }
  358. ~Host()
  359. {
  360. Dispose(false);
  361. }
  362. public bool IsSet {
  363. get {
  364. return nativeHost != IntPtr.Zero;
  365. }
  366. }
  367. public uint PeersCount {
  368. get {
  369. CheckCreated();
  370. return Native.enet_host_get_peers_count(nativeHost);
  371. }
  372. }
  373. public uint PacketsSent {
  374. get {
  375. CheckCreated();
  376. return Native.enet_host_get_packets_sent(nativeHost);
  377. }
  378. }
  379. public uint PacketsReceived {
  380. get {
  381. CheckCreated();
  382. return Native.enet_host_get_packets_received(nativeHost);
  383. }
  384. }
  385. public uint BytesSent {
  386. get {
  387. CheckCreated();
  388. return Native.enet_host_get_bytes_sent(nativeHost);
  389. }
  390. }
  391. public uint BytesReceived {
  392. get {
  393. CheckCreated();
  394. return Native.enet_host_get_bytes_received(nativeHost);
  395. }
  396. }
  397. internal void CheckCreated()
  398. {
  399. if (nativeHost == IntPtr.Zero)
  400. throw new InvalidOperationException("Host not created");
  401. }
  402. private void CheckChannelLimit(int channelLimit)
  403. {
  404. if (channelLimit < 0 || channelLimit > Library.maxChannelCount)
  405. throw new ArgumentOutOfRangeException("channelLimit");
  406. }
  407. public void Create()
  408. {
  409. Create(null, 1, 0);
  410. }
  411. public void Create(int bufferSize)
  412. {
  413. Create(null, 1, 0, 0, 0, bufferSize);
  414. }
  415. public void Create(Address? address, int peerLimit)
  416. {
  417. Create(address, peerLimit, 0);
  418. }
  419. public void Create(Address? address, int peerLimit, int channelLimit)
  420. {
  421. Create(address, peerLimit, channelLimit, 0, 0, 0);
  422. }
  423. public void Create(int peerLimit, int channelLimit)
  424. {
  425. Create(null, peerLimit, channelLimit, 0, 0, 0);
  426. }
  427. public void Create(int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth)
  428. {
  429. Create(null, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0);
  430. }
  431. public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth)
  432. {
  433. Create(address, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0);
  434. }
  435. public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize)
  436. {
  437. if (nativeHost != IntPtr.Zero)
  438. throw new InvalidOperationException("Host already created");
  439. if (peerLimit < 0 || peerLimit > Library.maxPeers)
  440. throw new ArgumentOutOfRangeException("peerLimit");
  441. CheckChannelLimit(channelLimit);
  442. if (address != null)
  443. {
  444. ENetAddress nativeAddress = address.Value.NativeData;
  445. nativeHost = Native.enet_host_create(ref nativeAddress, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize);
  446. }
  447. else
  448. {
  449. nativeHost = Native.enet_host_create(IntPtr.Zero, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize);
  450. }
  451. if (nativeHost == IntPtr.Zero)
  452. throw new InvalidOperationException("Host creation call failed");
  453. }
  454. public void EnableCompression()
  455. {
  456. CheckCreated();
  457. Native.enet_host_enable_compression(nativeHost);
  458. }
  459. public void PreventConnections(bool state)
  460. {
  461. CheckCreated();
  462. Native.enet_host_prevent_connections(nativeHost, (byte)(state ? 1 : 0));
  463. }
  464. public void Broadcast(byte channelID, ref Packet packet)
  465. {
  466. CheckCreated();
  467. packet.CheckCreated();
  468. Native.enet_host_broadcast(nativeHost, channelID, packet.NativeData);
  469. packet.NativeData = IntPtr.Zero;
  470. }
  471. public void Broadcast(byte channelID, ref Packet packet, Peer excludedPeer)
  472. {
  473. CheckCreated();
  474. packet.CheckCreated();
  475. Native.enet_host_broadcast_exclude(nativeHost, channelID, packet.NativeData, excludedPeer.NativeData);
  476. packet.NativeData = IntPtr.Zero;
  477. }
  478. public void Broadcast(byte channelID, ref Packet packet, Peer[] peers)
  479. {
  480. CheckCreated();
  481. packet.CheckCreated();
  482. if (peers.Length > 0)
  483. {
  484. IntPtr[] nativePeers = ArrayPool.GetPointerBuffer();
  485. int nativeCount = 0;
  486. for (int i = 0; i < peers.Length; i++)
  487. {
  488. if (peers[i].NativeData != IntPtr.Zero)
  489. {
  490. nativePeers[nativeCount] = peers[i].NativeData;
  491. nativeCount++;
  492. }
  493. }
  494. Native.enet_host_broadcast_selective(nativeHost, channelID, packet.NativeData, nativePeers, (IntPtr)nativeCount);
  495. }
  496. packet.NativeData = IntPtr.Zero;
  497. }
  498. public int CheckEvents(out Event @event)
  499. {
  500. CheckCreated();
  501. int result = Native.enet_host_check_events(nativeHost, out ENetEvent nativeEvent);
  502. if (result <= 0)
  503. {
  504. @event = default;
  505. return result;
  506. }
  507. @event = new Event(nativeEvent);
  508. return result;
  509. }
  510. public Peer Connect(Address address)
  511. {
  512. return Connect(address, 0, 0);
  513. }
  514. public Peer Connect(Address address, int channelLimit)
  515. {
  516. return Connect(address, channelLimit, 0);
  517. }
  518. public Peer Connect(Address address, int channelLimit, uint data)
  519. {
  520. CheckCreated();
  521. CheckChannelLimit(channelLimit);
  522. ENetAddress nativeAddress = address.NativeData;
  523. Peer peer = new Peer(Native.enet_host_connect(nativeHost, ref nativeAddress, (IntPtr)channelLimit, data));
  524. if (peer.NativeData == IntPtr.Zero)
  525. throw new InvalidOperationException("Host connect call failed");
  526. return peer;
  527. }
  528. public int Service(int timeout, out Event @event)
  529. {
  530. if (timeout < 0)
  531. throw new ArgumentOutOfRangeException("timeout");
  532. CheckCreated();
  533. int result = Native.enet_host_service(nativeHost, out ENetEvent nativeEvent, (uint)timeout);
  534. if (result <= 0)
  535. {
  536. @event = default;
  537. return result;
  538. }
  539. @event = new Event(nativeEvent);
  540. return result;
  541. }
  542. public void SetBandwidthLimit(uint incomingBandwidth, uint outgoingBandwidth)
  543. {
  544. CheckCreated();
  545. Native.enet_host_bandwidth_limit(nativeHost, incomingBandwidth, outgoingBandwidth);
  546. }
  547. public void SetChannelLimit(int channelLimit)
  548. {
  549. CheckCreated();
  550. CheckChannelLimit(channelLimit);
  551. Native.enet_host_channel_limit(nativeHost, (IntPtr)channelLimit);
  552. }
  553. public void Flush()
  554. {
  555. CheckCreated();
  556. Native.enet_host_flush(nativeHost);
  557. }
  558. }
  559. public struct Peer
  560. {
  561. private IntPtr nativePeer;
  562. private readonly uint nativeID;
  563. internal IntPtr NativeData {
  564. get {
  565. return nativePeer;
  566. }
  567. set {
  568. nativePeer = value;
  569. }
  570. }
  571. internal Peer(IntPtr peer)
  572. {
  573. nativePeer = peer;
  574. nativeID = nativePeer != IntPtr.Zero ? Native.enet_peer_get_id(nativePeer) : 0;
  575. }
  576. public bool IsSet {
  577. get {
  578. return nativePeer != IntPtr.Zero;
  579. }
  580. }
  581. public uint ID {
  582. get {
  583. return nativeID;
  584. }
  585. }
  586. public string IP {
  587. get {
  588. CheckCreated();
  589. byte[] ip = ArrayPool.GetByteBuffer();
  590. if (Native.enet_peer_get_ip(nativePeer, ip, (IntPtr)ip.Length) == 0)
  591. return Encoding.ASCII.GetString(ip, 0, ip.StringLength());
  592. else
  593. return String.Empty;
  594. }
  595. }
  596. public ushort Port {
  597. get {
  598. CheckCreated();
  599. return Native.enet_peer_get_port(nativePeer);
  600. }
  601. }
  602. public uint MTU {
  603. get {
  604. CheckCreated();
  605. return Native.enet_peer_get_mtu(nativePeer);
  606. }
  607. }
  608. public PeerState State {
  609. get {
  610. return nativePeer == IntPtr.Zero ? PeerState.Uninitialized : Native.enet_peer_get_state(nativePeer);
  611. }
  612. }
  613. public uint RoundTripTime {
  614. get {
  615. CheckCreated();
  616. return Native.enet_peer_get_rtt(nativePeer);
  617. }
  618. }
  619. public uint LastSendTime {
  620. get {
  621. CheckCreated();
  622. return Native.enet_peer_get_lastsendtime(nativePeer);
  623. }
  624. }
  625. public uint LastReceiveTime {
  626. get {
  627. CheckCreated();
  628. return Native.enet_peer_get_lastreceivetime(nativePeer);
  629. }
  630. }
  631. public ulong PacketsSent {
  632. get {
  633. CheckCreated();
  634. return Native.enet_peer_get_packets_sent(nativePeer);
  635. }
  636. }
  637. public ulong PacketsLost {
  638. get {
  639. CheckCreated();
  640. return Native.enet_peer_get_packets_lost(nativePeer);
  641. }
  642. }
  643. public ulong BytesSent {
  644. get {
  645. CheckCreated();
  646. return Native.enet_peer_get_bytes_sent(nativePeer);
  647. }
  648. }
  649. public ulong BytesReceived {
  650. get {
  651. CheckCreated();
  652. return Native.enet_peer_get_bytes_received(nativePeer);
  653. }
  654. }
  655. public IntPtr Data {
  656. get {
  657. CheckCreated();
  658. return Native.enet_peer_get_data(nativePeer);
  659. }
  660. set {
  661. CheckCreated();
  662. Native.enet_peer_set_data(nativePeer, value);
  663. }
  664. }
  665. internal void CheckCreated()
  666. {
  667. if (nativePeer == IntPtr.Zero)
  668. throw new InvalidOperationException("Peer not created");
  669. }
  670. public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration, uint threshold)
  671. {
  672. CheckCreated();
  673. Native.enet_peer_throttle_configure(nativePeer, interval, acceleration, deceleration, threshold);
  674. }
  675. public bool Send(byte channelID, ref Packet packet)
  676. {
  677. CheckCreated();
  678. packet.CheckCreated();
  679. return Native.enet_peer_send(nativePeer, channelID, packet.NativeData) == 0;
  680. }
  681. // Added by Coburn. This version returns either 0 if the send was successful,
  682. // or the ENET return code if not. Sometimes a bool is not enough to determine
  683. // the root cause of the issue.
  684. public int SendAndReturnStatusCode(byte channelID, ref Packet packet)
  685. {
  686. CheckCreated();
  687. packet.CheckCreated();
  688. return Native.enet_peer_send(nativePeer, channelID, packet.NativeData);
  689. }
  690. public bool Receive(out byte channelID, out Packet packet)
  691. {
  692. CheckCreated();
  693. IntPtr nativePacket = Native.enet_peer_receive(nativePeer, out channelID);
  694. if (nativePacket != IntPtr.Zero)
  695. {
  696. packet = new Packet(nativePacket);
  697. return true;
  698. }
  699. packet = default;
  700. return false;
  701. }
  702. public void Ping()
  703. {
  704. CheckCreated();
  705. Native.enet_peer_ping(nativePeer);
  706. }
  707. public void PingInterval(uint interval)
  708. {
  709. CheckCreated();
  710. Native.enet_peer_ping_interval(nativePeer, interval);
  711. }
  712. public void Timeout(uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum)
  713. {
  714. CheckCreated();
  715. Native.enet_peer_timeout(nativePeer, timeoutLimit, timeoutMinimum, timeoutMaximum);
  716. }
  717. public void Disconnect(uint data)
  718. {
  719. CheckCreated();
  720. Native.enet_peer_disconnect(nativePeer, data);
  721. }
  722. public void DisconnectNow(uint data)
  723. {
  724. CheckCreated();
  725. Native.enet_peer_disconnect_now(nativePeer, data);
  726. }
  727. public void DisconnectLater(uint data)
  728. {
  729. CheckCreated();
  730. Native.enet_peer_disconnect_later(nativePeer, data);
  731. }
  732. public void Reset()
  733. {
  734. CheckCreated();
  735. Native.enet_peer_reset(nativePeer);
  736. }
  737. }
  738. public static class Extensions
  739. {
  740. public static int StringLength(this byte[] data)
  741. {
  742. if (data == null)
  743. throw new ArgumentNullException("data");
  744. int i;
  745. for (i = 0; i < data.Length && data[i] != 0; i++) ;
  746. return i;
  747. }
  748. }
  749. public static class Library
  750. {
  751. public const uint maxChannelCount = 0xFF;
  752. public const uint maxPeers = 0xFFF;
  753. public const uint maxPacketSize = 32 * 1024 * 1024;
  754. public const uint throttleThreshold = 20; // Reasonable threshold to help reduce throttling.
  755. public const uint throttleScale = 32;
  756. public const uint throttleAcceleration = 2;
  757. public const uint throttleDeceleration = 2;
  758. public const uint throttleInterval = 5000;
  759. public const uint timeoutLimit = 32;
  760. public const uint timeoutMinimum = 5000;
  761. public const uint timeoutMaximum = 30000;
  762. public const uint version = (2 << 16) | (4 << 8) | (0);
  763. public static bool Initialize()
  764. {
  765. return Native.enet_initialize() == 0;
  766. }
  767. public static bool Initialize(Callbacks inits)
  768. {
  769. return Native.enet_initialize_with_callbacks(version, inits.NativeData) == 0;
  770. }
  771. public static void Deinitialize()
  772. {
  773. Native.enet_deinitialize();
  774. }
  775. public static uint Time {
  776. get {
  777. return Native.enet_time_get();
  778. }
  779. }
  780. }
  781. [SuppressUnmanagedCodeSecurity]
  782. internal static class Native
  783. {
  784. #if __IOS__ || UNITY_IOS && !UNITY_EDITOR
  785. // iOS
  786. private const string nativeLibrary = "__Internal";
  787. #elif __APPLE__ || UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
  788. // MacOS
  789. // Custom ENet Repo builds as libenet.bundle; make sure it's the same.
  790. private const string nativeLibrary = "libenet";
  791. #else
  792. // Assume everything else, Windows et al...
  793. // This might be interesting if someone's building for Nintendo Switch or whatnot...
  794. private const string nativeLibrary = "enet";
  795. #endif
  796. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  797. internal static extern int enet_initialize();
  798. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  799. internal static extern int enet_initialize_with_callbacks(uint version, ENetCallbacks inits);
  800. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  801. internal static extern void enet_deinitialize();
  802. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  803. internal static extern uint enet_time_get();
  804. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  805. internal static extern int enet_address_set_host_ip(ref ENetAddress address, string ip);
  806. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  807. internal static extern int enet_address_set_host(ref ENetAddress address, string hostName);
  808. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  809. internal static extern int enet_address_get_host_ip(ENetAddress address, StringBuilder ip, IntPtr ipLength);
  810. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  811. internal static extern int enet_address_get_host(ENetAddress address, StringBuilder hostName, IntPtr nameLength);
  812. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  813. internal static extern IntPtr enet_packet_create(byte[] data, IntPtr dataLength, PacketFlags flags);
  814. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  815. internal static extern IntPtr enet_packet_create(IntPtr data, IntPtr dataLength, PacketFlags flags);
  816. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  817. internal static extern IntPtr enet_packet_create_offset(byte[] data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags);
  818. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  819. internal static extern IntPtr enet_packet_create_offset(IntPtr data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags);
  820. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  821. internal static extern int enet_packet_check_references(IntPtr packet);
  822. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  823. internal static extern IntPtr enet_packet_get_data(IntPtr packet);
  824. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  825. internal static extern int enet_packet_get_length(IntPtr packet);
  826. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  827. internal static extern void enet_packet_set_free_callback(IntPtr packet, IntPtr callback);
  828. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  829. internal static extern void enet_packet_dispose(IntPtr packet);
  830. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  831. internal static extern IntPtr enet_host_create(ref ENetAddress address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize);
  832. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  833. internal static extern IntPtr enet_host_create(IntPtr address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize);
  834. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  835. internal static extern IntPtr enet_host_connect(IntPtr host, ref ENetAddress address, IntPtr channelCount, uint data);
  836. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  837. internal static extern void enet_host_broadcast(IntPtr host, byte channelID, IntPtr packet);
  838. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  839. internal static extern void enet_host_broadcast_exclude(IntPtr host, byte channelID, IntPtr packet, IntPtr excludedPeer);
  840. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  841. internal static extern void enet_host_broadcast_selective(IntPtr host, byte channelID, IntPtr packet, IntPtr[] peers, IntPtr peersLength);
  842. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  843. internal static extern int enet_host_service(IntPtr host, out ENetEvent @event, uint timeout);
  844. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  845. internal static extern int enet_host_check_events(IntPtr host, out ENetEvent @event);
  846. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  847. internal static extern void enet_host_channel_limit(IntPtr host, IntPtr channelLimit);
  848. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  849. internal static extern void enet_host_bandwidth_limit(IntPtr host, uint incomingBandwidth, uint outgoingBandwidth);
  850. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  851. internal static extern uint enet_host_get_peers_count(IntPtr host);
  852. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  853. internal static extern uint enet_host_get_packets_sent(IntPtr host);
  854. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  855. internal static extern uint enet_host_get_packets_received(IntPtr host);
  856. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  857. internal static extern uint enet_host_get_bytes_sent(IntPtr host);
  858. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  859. internal static extern uint enet_host_get_bytes_received(IntPtr host);
  860. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  861. internal static extern void enet_host_flush(IntPtr host);
  862. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  863. internal static extern void enet_host_destroy(IntPtr host);
  864. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  865. internal static extern void enet_host_enable_compression(IntPtr host);
  866. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  867. internal static extern void enet_host_prevent_connections(IntPtr host, byte state);
  868. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  869. internal static extern void enet_peer_throttle_configure(IntPtr peer, uint interval, uint acceleration, uint deceleration, uint threshold);
  870. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  871. internal static extern uint enet_peer_get_id(IntPtr peer);
  872. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  873. internal static extern int enet_peer_get_ip(IntPtr peer, byte[] ip, IntPtr ipLength);
  874. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  875. internal static extern ushort enet_peer_get_port(IntPtr peer);
  876. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  877. internal static extern uint enet_peer_get_mtu(IntPtr peer);
  878. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  879. internal static extern PeerState enet_peer_get_state(IntPtr peer);
  880. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  881. internal static extern uint enet_peer_get_rtt(IntPtr peer);
  882. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  883. internal static extern uint enet_peer_get_lastsendtime(IntPtr peer);
  884. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  885. internal static extern uint enet_peer_get_lastreceivetime(IntPtr peer);
  886. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  887. internal static extern ulong enet_peer_get_packets_sent(IntPtr peer);
  888. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  889. internal static extern ulong enet_peer_get_packets_lost(IntPtr peer);
  890. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  891. internal static extern ulong enet_peer_get_bytes_sent(IntPtr peer);
  892. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  893. internal static extern ulong enet_peer_get_bytes_received(IntPtr peer);
  894. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  895. internal static extern IntPtr enet_peer_get_data(IntPtr peer);
  896. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  897. internal static extern void enet_peer_set_data(IntPtr peer, IntPtr data);
  898. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  899. internal static extern int enet_peer_send(IntPtr peer, byte channelID, IntPtr packet);
  900. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  901. internal static extern IntPtr enet_peer_receive(IntPtr peer, out byte channelID);
  902. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  903. internal static extern void enet_peer_ping(IntPtr peer);
  904. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  905. internal static extern void enet_peer_ping_interval(IntPtr peer, uint pingInterval);
  906. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  907. internal static extern void enet_peer_timeout(IntPtr peer, uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum);
  908. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  909. internal static extern void enet_peer_disconnect(IntPtr peer, uint data);
  910. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  911. internal static extern void enet_peer_disconnect_now(IntPtr peer, uint data);
  912. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  913. internal static extern void enet_peer_disconnect_later(IntPtr peer, uint data);
  914. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  915. internal static extern void enet_peer_reset(IntPtr peer);
  916. }
  917. }