ENet.cs 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  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. }
  38. public enum EventType {
  39. None = 0,
  40. Connect = 1,
  41. Disconnect = 2,
  42. Receive = 3,
  43. Timeout = 4
  44. }
  45. public enum PeerState {
  46. Uninitialized = -1,
  47. Disconnected = 0,
  48. Connecting = 1,
  49. AcknowledgingConnect = 2,
  50. ConnectionPending = 3,
  51. ConnectionSucceeded = 4,
  52. Connected = 5,
  53. DisconnectLater = 6,
  54. Disconnecting = 7,
  55. AcknowledgingDisconnect = 8,
  56. Zombie = 9
  57. }
  58. [StructLayout(LayoutKind.Sequential)]
  59. public struct ENetAddress {
  60. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
  61. public byte[] ip;
  62. public ushort port;
  63. }
  64. [StructLayout(LayoutKind.Sequential)]
  65. public 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. public 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(1024);
  121. if (Native.enet_address_get_host_ip(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_host_ip(ref nativeAddress, ip) == 0;
  129. }
  130. public string GetHost() {
  131. StringBuilder hostName = new StringBuilder(1024);
  132. if (Native.enet_address_get_host(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_host(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_excluding(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) | (2 << 8) | (9);
  664. public static bool Initialize() {
  665. return Native.enet_initialize() == 0;
  666. }
  667. public static bool Initialize(Callbacks inits) {
  668. return Native.enet_initialize_with_callbacks(version, inits.NativeData) == 0;
  669. }
  670. public static void Deinitialize() {
  671. Native.enet_deinitialize();
  672. }
  673. public static uint Time {
  674. get {
  675. return Native.enet_time_get();
  676. }
  677. }
  678. }
  679. [SuppressUnmanagedCodeSecurity]
  680. internal static class Native {
  681. #if __IOS__ || UNITY_IOS && !UNITY_EDITOR
  682. private const string nativeLibrary = "__Internal";
  683. #else
  684. private const string nativeLibrary = "enet";
  685. #endif
  686. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  687. internal static extern int enet_initialize();
  688. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  689. internal static extern int enet_initialize_with_callbacks(uint version, ENetCallbacks inits);
  690. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  691. internal static extern void enet_deinitialize();
  692. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  693. internal static extern uint enet_time_get();
  694. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  695. internal static extern int enet_address_set_host_ip(ref ENetAddress address, string ip);
  696. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  697. internal static extern int enet_address_set_host(ref ENetAddress address, string hostName);
  698. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  699. internal static extern int enet_address_get_host_ip(ENetAddress address, StringBuilder ip, IntPtr ipLength);
  700. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  701. internal static extern int enet_address_get_host(ENetAddress address, StringBuilder hostName, IntPtr nameLength);
  702. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  703. internal static extern IntPtr enet_packet_create(byte[] data, IntPtr dataLength, PacketFlags flags);
  704. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  705. internal static extern IntPtr enet_packet_create(IntPtr data, IntPtr dataLength, PacketFlags flags);
  706. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  707. internal static extern IntPtr enet_packet_create_offset(byte[] data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags);
  708. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  709. internal static extern IntPtr enet_packet_create_offset(IntPtr data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags);
  710. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  711. internal static extern int enet_packet_check_references(IntPtr packet);
  712. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  713. internal static extern IntPtr enet_packet_get_data(IntPtr packet);
  714. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  715. internal static extern int enet_packet_get_length(IntPtr packet);
  716. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  717. internal static extern void enet_packet_set_free_callback(IntPtr packet, IntPtr callback);
  718. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  719. internal static extern void enet_packet_dispose(IntPtr packet);
  720. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  721. internal static extern IntPtr enet_host_create(ref ENetAddress address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize);
  722. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  723. internal static extern IntPtr enet_host_create(IntPtr address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize);
  724. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  725. internal static extern IntPtr enet_host_connect(IntPtr host, ref ENetAddress address, IntPtr channelCount, uint data);
  726. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  727. internal static extern void enet_host_broadcast(IntPtr host, byte channelID, IntPtr packet);
  728. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  729. internal static extern void enet_host_broadcast_excluding(IntPtr host, byte channelID, IntPtr packet, IntPtr excludedPeer);
  730. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  731. internal static extern void enet_host_broadcast_selective(IntPtr host, byte channelID, IntPtr packet, IntPtr[] peers, IntPtr peersLength);
  732. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  733. internal static extern int enet_host_service(IntPtr host, out ENetEvent @event, uint timeout);
  734. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  735. internal static extern int enet_host_check_events(IntPtr host, out ENetEvent @event);
  736. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  737. internal static extern void enet_host_channel_limit(IntPtr host, IntPtr channelLimit);
  738. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  739. internal static extern void enet_host_bandwidth_limit(IntPtr host, uint incomingBandwidth, uint outgoingBandwidth);
  740. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  741. internal static extern uint enet_host_get_peers_count(IntPtr host);
  742. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  743. internal static extern uint enet_host_get_packets_sent(IntPtr host);
  744. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  745. internal static extern uint enet_host_get_packets_received(IntPtr host);
  746. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  747. internal static extern uint enet_host_get_bytes_sent(IntPtr host);
  748. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  749. internal static extern uint enet_host_get_bytes_received(IntPtr host);
  750. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  751. internal static extern void enet_host_flush(IntPtr host);
  752. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  753. internal static extern void enet_host_destroy(IntPtr host);
  754. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  755. internal static extern void enet_host_enable_compression(IntPtr host);
  756. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  757. internal static extern void enet_host_prevent_connections(IntPtr host, byte state);
  758. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  759. internal static extern void enet_peer_throttle_configure(IntPtr peer, uint interval, uint acceleration, uint deceleration, uint threshold);
  760. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  761. internal static extern uint enet_peer_get_id(IntPtr peer);
  762. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  763. internal static extern int enet_peer_get_ip(IntPtr peer, byte[] ip, IntPtr ipLength);
  764. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  765. internal static extern ushort enet_peer_get_port(IntPtr peer);
  766. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  767. internal static extern uint enet_peer_get_mtu(IntPtr peer);
  768. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  769. internal static extern PeerState enet_peer_get_state(IntPtr peer);
  770. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  771. internal static extern uint enet_peer_get_rtt(IntPtr peer);
  772. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  773. internal static extern uint enet_peer_get_lastsendtime(IntPtr peer);
  774. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  775. internal static extern uint enet_peer_get_lastreceivetime(IntPtr peer);
  776. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  777. internal static extern ulong enet_peer_get_packets_sent(IntPtr peer);
  778. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  779. internal static extern ulong enet_peer_get_packets_lost(IntPtr peer);
  780. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  781. internal static extern ulong enet_peer_get_bytes_sent(IntPtr peer);
  782. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  783. internal static extern ulong enet_peer_get_bytes_received(IntPtr peer);
  784. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  785. internal static extern IntPtr enet_peer_get_data(IntPtr peer);
  786. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  787. internal static extern void enet_peer_set_data(IntPtr peer, IntPtr data);
  788. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  789. internal static extern int enet_peer_send(IntPtr peer, byte channelID, IntPtr packet);
  790. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  791. internal static extern IntPtr enet_peer_receive(IntPtr peer, out byte channelID);
  792. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  793. internal static extern void enet_peer_ping(IntPtr peer);
  794. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  795. internal static extern void enet_peer_ping_interval(IntPtr peer, uint pingInterval);
  796. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  797. internal static extern void enet_peer_timeout(IntPtr peer, uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum);
  798. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  799. internal static extern void enet_peer_disconnect(IntPtr peer, uint data);
  800. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  801. internal static extern void enet_peer_disconnect_now(IntPtr peer, uint data);
  802. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  803. internal static extern void enet_peer_disconnect_later(IntPtr peer, uint data);
  804. [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
  805. internal static extern void enet_peer_reset(IntPtr peer);
  806. }
  807. }