ENet.cs 29 KB

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