/* * Managed C# wrapper for an extended version of ENet * Copyright (c) 2013 James Bellinger * Copyright (c) 2016 Nate Shoffner * Copyright (c) 2018 Stanislav Denisov * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ using System; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace ENet { [Flags] public enum PacketFlags { None = 0, Reliable = 1 << 0, Unsequenced = 1 << 1, NoAllocate = 1 << 2, UnreliableFragmented = 1 << 3, Instant = 1 << 4, Unthrottled = 1 << 5, Sent = 1 << 8 } public enum EventType { None = 0, Connect = 1, Disconnect = 2, Receive = 3, Timeout = 4 } public enum PeerState { Uninitialized = -1, Disconnected = 0, Connecting = 1, AcknowledgingConnect = 2, ConnectionPending = 3, ConnectionSucceeded = 4, Connected = 5, DisconnectLater = 6, Disconnecting = 7, AcknowledgingDisconnect = 8, Zombie = 9 } [StructLayout(LayoutKind.Explicit, Size = 18)] internal struct ENetAddress { [FieldOffset(16)] public ushort port; } [StructLayout(LayoutKind.Sequential)] internal struct ENetEvent { public EventType type; public IntPtr peer; public byte channelID; public uint data; public IntPtr packet; } [StructLayout(LayoutKind.Sequential)] internal struct ENetCallbacks { public AllocCallback malloc; public FreeCallback free; public NoMemoryCallback noMemory; } public delegate IntPtr AllocCallback(IntPtr size); public delegate void FreeCallback(IntPtr memory); public delegate void NoMemoryCallback(); public delegate void PacketFreeCallback(Packet packet); public delegate int InterceptCallback(ref Event @event, ref Address address, IntPtr receivedData, int receivedDataLength); public delegate ulong ChecksumCallback(IntPtr buffers, int bufferCount); internal static class ArrayPool { [ThreadStatic] private static byte[] byteBuffer; [ThreadStatic] private static IntPtr[] pointerBuffer; public static byte[] GetByteBuffer() { if (byteBuffer == null) byteBuffer = new byte[64]; return byteBuffer; } public static IntPtr[] GetPointerBuffer() { if (pointerBuffer == null) pointerBuffer = new IntPtr[Library.maxPeers]; return pointerBuffer; } } public struct Address { private ENetAddress nativeAddress; internal ENetAddress NativeData { get { return nativeAddress; } set { nativeAddress = value; } } internal Address(ENetAddress address) { nativeAddress = address; } public ushort Port { get { return nativeAddress.port; } set { nativeAddress.port = value; } } public string GetIP() { StringBuilder ip = new StringBuilder(1025); if (Native.enet_address_get_ip(ref nativeAddress, ip, (IntPtr)ip.Capacity) != 0) return String.Empty; return ip.ToString(); } public bool SetIP(string ip) { if (ip == null) throw new ArgumentNullException("ip"); return Native.enet_address_set_ip(ref nativeAddress, ip) == 0; } public string GetHost() { StringBuilder hostName = new StringBuilder(1025); if (Native.enet_address_get_hostname(ref nativeAddress, hostName, (IntPtr)hostName.Capacity) != 0) return String.Empty; return hostName.ToString(); } public bool SetHost(string hostName) { if (hostName == null) throw new ArgumentNullException("hostName"); return Native.enet_address_set_hostname(ref nativeAddress, hostName) == 0; } } public struct Event { private ENetEvent nativeEvent; internal ENetEvent NativeData { get { return nativeEvent; } set { nativeEvent = value; } } internal Event(ENetEvent @event) { nativeEvent = @event; } public EventType Type { get { return nativeEvent.type; } } public Peer Peer { get { return new Peer(nativeEvent.peer); } } public byte ChannelID { get { return nativeEvent.channelID; } } public uint Data { get { return nativeEvent.data; } } public Packet Packet { get { return new Packet(nativeEvent.packet); } } } public class Callbacks { private ENetCallbacks nativeCallbacks; internal ENetCallbacks NativeData { get { return nativeCallbacks; } set { nativeCallbacks = value; } } public Callbacks(AllocCallback allocCallback, FreeCallback freeCallback, NoMemoryCallback noMemoryCallback) { nativeCallbacks.malloc = allocCallback; nativeCallbacks.free = freeCallback; nativeCallbacks.noMemory = noMemoryCallback; } } public struct Packet : IDisposable { private IntPtr nativePacket; internal IntPtr NativeData { get { return nativePacket; } set { nativePacket = value; } } internal Packet(IntPtr packet) { nativePacket = packet; } public void Dispose() { if (nativePacket != IntPtr.Zero) { Native.enet_packet_dispose(nativePacket); nativePacket = IntPtr.Zero; } } public bool IsSet { get { return nativePacket != IntPtr.Zero; } } public IntPtr Data { get { ThrowIfNotCreated(); return Native.enet_packet_get_data(nativePacket); } } public IntPtr UserData { get { ThrowIfNotCreated(); return Native.enet_packet_get_user_data(nativePacket); } set { ThrowIfNotCreated(); Native.enet_packet_set_user_data(nativePacket, value); } } public int Length { get { ThrowIfNotCreated(); return Native.enet_packet_get_length(nativePacket); } } public bool HasReferences { get { ThrowIfNotCreated(); return Native.enet_packet_check_references(nativePacket) != 0; } } internal void ThrowIfNotCreated() { if (nativePacket == IntPtr.Zero) throw new InvalidOperationException("Packet not created"); } public void SetFreeCallback(IntPtr callback) { ThrowIfNotCreated(); Native.enet_packet_set_free_callback(nativePacket, callback); } public void SetFreeCallback(PacketFreeCallback callback) { ThrowIfNotCreated(); Native.enet_packet_set_free_callback(nativePacket, Marshal.GetFunctionPointerForDelegate(callback)); } public void Create(byte[] data) { if (data == null) throw new ArgumentNullException("data"); Create(data, data.Length); } public void Create(byte[] data, int length) { Create(data, length, PacketFlags.None); } public void Create(byte[] data, PacketFlags flags) { Create(data, data.Length, flags); } public void Create(byte[] data, int length, PacketFlags flags) { if (data == null) throw new ArgumentNullException("data"); if (length < 0 || length > data.Length) throw new ArgumentOutOfRangeException("length"); nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); } public void Create(IntPtr data, int length, PacketFlags flags) { if (data == IntPtr.Zero) throw new ArgumentNullException("data"); if (length < 0) throw new ArgumentOutOfRangeException("length"); nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); } public void Create(byte[] data, int offset, int length, PacketFlags flags) { if (data == null) throw new ArgumentNullException("data"); if (offset < 0) throw new ArgumentOutOfRangeException("offset"); if (length < 0 || length > data.Length) throw new ArgumentOutOfRangeException("length"); nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); } public void Create(IntPtr data, int offset, int length, PacketFlags flags) { if (data == IntPtr.Zero) throw new ArgumentNullException("data"); if (offset < 0) throw new ArgumentOutOfRangeException("offset"); if (length < 0) throw new ArgumentOutOfRangeException("length"); nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); } public void CopyTo(byte[] destination) { if (destination == null) throw new ArgumentNullException("destination"); Marshal.Copy(Data, destination, 0, Length); } } public class Host : IDisposable { private IntPtr nativeHost; internal IntPtr NativeData { get { return nativeHost; } set { nativeHost = value; } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (nativeHost != IntPtr.Zero) { Native.enet_host_destroy(nativeHost); nativeHost = IntPtr.Zero; } } ~Host() { Dispose(false); } public bool IsSet { get { return nativeHost != IntPtr.Zero; } } public uint PeersCount { get { ThrowIfNotCreated(); return Native.enet_host_get_peers_count(nativeHost); } } public uint PacketsSent { get { ThrowIfNotCreated(); return Native.enet_host_get_packets_sent(nativeHost); } } public uint PacketsReceived { get { ThrowIfNotCreated(); return Native.enet_host_get_packets_received(nativeHost); } } public uint BytesSent { get { ThrowIfNotCreated(); return Native.enet_host_get_bytes_sent(nativeHost); } } public uint BytesReceived { get { ThrowIfNotCreated(); return Native.enet_host_get_bytes_received(nativeHost); } } internal void ThrowIfNotCreated() { if (nativeHost == IntPtr.Zero) throw new InvalidOperationException("Host not created"); } private static void ThrowIfChannelsExceeded(int channelLimit) { if (channelLimit < 0 || channelLimit > Library.maxChannelCount) throw new ArgumentOutOfRangeException("channelLimit"); } public void Create() { Create(null, 1, 0); } public void Create(int bufferSize) { Create(null, 1, 0, 0, 0, bufferSize); } public void Create(Address? address, int peerLimit) { Create(address, peerLimit, 0); } public void Create(Address? address, int peerLimit, int channelLimit) { Create(address, peerLimit, channelLimit, 0, 0, 0); } public void Create(int peerLimit, int channelLimit) { Create(null, peerLimit, channelLimit, 0, 0, 0); } public void Create(int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) { Create(null, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); } public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) { Create(address, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); } public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize) { if (nativeHost != IntPtr.Zero) throw new InvalidOperationException("Host already created"); if (peerLimit < 0 || peerLimit > Library.maxPeers) throw new ArgumentOutOfRangeException("peerLimit"); ThrowIfChannelsExceeded(channelLimit); if (address != null) { var nativeAddress = address.Value.NativeData; nativeHost = Native.enet_host_create(ref nativeAddress, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); } else { nativeHost = Native.enet_host_create(IntPtr.Zero, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); } if (nativeHost == IntPtr.Zero) throw new InvalidOperationException("Host creation call failed"); } public void PreventConnections(bool state) { ThrowIfNotCreated(); Native.enet_host_prevent_connections(nativeHost, (byte)(state ? 1 : 0)); } public void Broadcast(byte channelID, ref Packet packet) { ThrowIfNotCreated(); packet.ThrowIfNotCreated(); Native.enet_host_broadcast(nativeHost, channelID, packet.NativeData); packet.NativeData = IntPtr.Zero; } public void Broadcast(byte channelID, ref Packet packet, Peer excludedPeer) { ThrowIfNotCreated(); packet.ThrowIfNotCreated(); Native.enet_host_broadcast_exclude(nativeHost, channelID, packet.NativeData, excludedPeer.NativeData); packet.NativeData = IntPtr.Zero; } public void Broadcast(byte channelID, ref Packet packet, Peer[] peers) { if (peers == null) throw new ArgumentNullException("peers"); ThrowIfNotCreated(); packet.ThrowIfNotCreated(); if (peers.Length > 0) { IntPtr[] nativePeers = ArrayPool.GetPointerBuffer(); int nativeCount = 0; for (int i = 0; i < peers.Length; i++) { if (peers[i].NativeData != IntPtr.Zero) { nativePeers[nativeCount] = peers[i].NativeData; nativeCount++; } } Native.enet_host_broadcast_selective(nativeHost, channelID, packet.NativeData, nativePeers, (IntPtr)nativeCount); packet.NativeData = IntPtr.Zero; } else { packet.Dispose(); throw new ArgumentOutOfRangeException("Peers array can't be empty"); } } public int CheckEvents(out Event @event) { ThrowIfNotCreated(); ENetEvent nativeEvent; var result = Native.enet_host_check_events(nativeHost, out nativeEvent); if (result <= 0) { @event = default(Event); return result; } @event = new Event(nativeEvent); return result; } public Peer Connect(Address address) { return Connect(address, 0, 0); } public Peer Connect(Address address, int channelLimit) { return Connect(address, channelLimit, 0); } public Peer Connect(Address address, int channelLimit, uint data) { ThrowIfNotCreated(); ThrowIfChannelsExceeded(channelLimit); var nativeAddress = address.NativeData; var peer = new Peer(Native.enet_host_connect(nativeHost, ref nativeAddress, (IntPtr)channelLimit, data)); if (peer.NativeData == IntPtr.Zero) throw new InvalidOperationException("Host connect call failed"); return peer; } public int Service(int timeout, out Event @event) { if (timeout < 0) throw new ArgumentOutOfRangeException("timeout"); ThrowIfNotCreated(); ENetEvent nativeEvent; var result = Native.enet_host_service(nativeHost, out nativeEvent, (uint)timeout); if (result <= 0) { @event = default(Event); return result; } @event = new Event(nativeEvent); return result; } public void SetBandwidthLimit(uint incomingBandwidth, uint outgoingBandwidth) { ThrowIfNotCreated(); Native.enet_host_bandwidth_limit(nativeHost, incomingBandwidth, outgoingBandwidth); } public void SetChannelLimit(int channelLimit) { ThrowIfNotCreated(); ThrowIfChannelsExceeded(channelLimit); Native.enet_host_channel_limit(nativeHost, (IntPtr)channelLimit); } public void SetMaxDuplicatePeers(ushort number) { ThrowIfNotCreated(); Native.enet_host_set_max_duplicate_peers(nativeHost, number); } public void SetInterceptCallback(IntPtr callback) { ThrowIfNotCreated(); Native.enet_host_set_intercept_callback(nativeHost, callback); } public void SetInterceptCallback(InterceptCallback callback) { ThrowIfNotCreated(); Native.enet_host_set_intercept_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); } public void SetChecksumCallback(IntPtr callback) { ThrowIfNotCreated(); Native.enet_host_set_checksum_callback(nativeHost, callback); } public void SetChecksumCallback(ChecksumCallback callback) { ThrowIfNotCreated(); Native.enet_host_set_checksum_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); } public void Flush() { ThrowIfNotCreated(); Native.enet_host_flush(nativeHost); } } public struct Peer { private IntPtr nativePeer; private uint nativeID; internal IntPtr NativeData { get { return nativePeer; } set { nativePeer = value; } } internal Peer(IntPtr peer) { nativePeer = peer; nativeID = nativePeer != IntPtr.Zero ? Native.enet_peer_get_id(nativePeer) : 0; } public bool IsSet { get { return nativePeer != IntPtr.Zero; } } public uint ID { get { return nativeID; } } public string IP { get { ThrowIfNotCreated(); byte[] ip = ArrayPool.GetByteBuffer(); if (Native.enet_peer_get_ip(nativePeer, ip, (IntPtr)ip.Length) == 0) return Encoding.ASCII.GetString(ip, 0, ip.StringLength()); else return String.Empty; } } public ushort Port { get { ThrowIfNotCreated(); return Native.enet_peer_get_port(nativePeer); } } public uint MTU { get { ThrowIfNotCreated(); return Native.enet_peer_get_mtu(nativePeer); } } public PeerState State { get { return nativePeer == IntPtr.Zero ? PeerState.Uninitialized : Native.enet_peer_get_state(nativePeer); } } public uint RoundTripTime { get { ThrowIfNotCreated(); return Native.enet_peer_get_rtt(nativePeer); } } public uint LastRoundTripTime { get { ThrowIfNotCreated(); return Native.enet_peer_get_last_rtt(nativePeer); } } public uint LastSendTime { get { ThrowIfNotCreated(); return Native.enet_peer_get_lastsendtime(nativePeer); } } public uint LastReceiveTime { get { ThrowIfNotCreated(); return Native.enet_peer_get_lastreceivetime(nativePeer); } } public ulong PacketsSent { get { ThrowIfNotCreated(); return Native.enet_peer_get_packets_sent(nativePeer); } } public ulong PacketsLost { get { ThrowIfNotCreated(); return Native.enet_peer_get_packets_lost(nativePeer); } } public float PacketsThrottle { get { ThrowIfNotCreated(); return Native.enet_peer_get_packets_throttle(nativePeer); } } public ulong BytesSent { get { ThrowIfNotCreated(); return Native.enet_peer_get_bytes_sent(nativePeer); } } public ulong BytesReceived { get { ThrowIfNotCreated(); return Native.enet_peer_get_bytes_received(nativePeer); } } public IntPtr Data { get { ThrowIfNotCreated(); return Native.enet_peer_get_data(nativePeer); } set { ThrowIfNotCreated(); Native.enet_peer_set_data(nativePeer, value); } } internal void ThrowIfNotCreated() { if (nativePeer == IntPtr.Zero) throw new InvalidOperationException("Peer not created"); } public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration, uint threshold) { ThrowIfNotCreated(); Native.enet_peer_throttle_configure(nativePeer, interval, acceleration, deceleration, threshold); } public bool Send(byte channelID, ref Packet packet) { ThrowIfNotCreated(); packet.ThrowIfNotCreated(); return Native.enet_peer_send(nativePeer, channelID, packet.NativeData) == 0; } public bool Receive(out byte channelID, out Packet packet) { ThrowIfNotCreated(); IntPtr nativePacket = Native.enet_peer_receive(nativePeer, out channelID); if (nativePacket != IntPtr.Zero) { packet = new Packet(nativePacket); return true; } packet = default(Packet); return false; } public void Ping() { ThrowIfNotCreated(); Native.enet_peer_ping(nativePeer); } public void PingInterval(uint interval) { ThrowIfNotCreated(); Native.enet_peer_ping_interval(nativePeer, interval); } public void Timeout(uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum) { ThrowIfNotCreated(); Native.enet_peer_timeout(nativePeer, timeoutLimit, timeoutMinimum, timeoutMaximum); } public void Disconnect(uint data) { ThrowIfNotCreated(); Native.enet_peer_disconnect(nativePeer, data); } public void DisconnectNow(uint data) { ThrowIfNotCreated(); Native.enet_peer_disconnect_now(nativePeer, data); } public void DisconnectLater(uint data) { ThrowIfNotCreated(); Native.enet_peer_disconnect_later(nativePeer, data); } public void Reset() { ThrowIfNotCreated(); Native.enet_peer_reset(nativePeer); } } public static class Extensions { public static int StringLength(this byte[] data) { if (data == null) throw new ArgumentNullException("data"); int i; for (i = 0; i < data.Length && data[i] != 0; i++); return i; } } public static class Library { public const uint maxChannelCount = 0xFF; public const uint maxPeers = 0xFFF; public const uint maxPacketSize = 32 * 1024 * 1024; public const uint throttleThreshold = 40; public const uint throttleScale = 32; public const uint throttleAcceleration = 2; public const uint throttleDeceleration = 2; public const uint throttleInterval = 5000; public const uint timeoutLimit = 32; public const uint timeoutMinimum = 5000; public const uint timeoutMaximum = 30000; public const uint version = (2 << 16) | (4 << 8) | (8); public static uint Time { get { return Native.enet_time_get(); } } public static bool Initialize() { if (Native.enet_linked_version() != version) throw new InvalidOperationException("Incompatible version"); return Native.enet_initialize() == 0; } public static bool Initialize(Callbacks callbacks) { if (callbacks == null) throw new ArgumentNullException("callbacks"); if (Native.enet_linked_version() != version) throw new InvalidOperationException("Incompatible version"); ENetCallbacks nativeCallbacks = callbacks.NativeData; return Native.enet_initialize_with_callbacks(version, ref nativeCallbacks) == 0; } public static void Deinitialize() { Native.enet_deinitialize(); } public static ulong CRC64(IntPtr buffers, int bufferCount) { return Native.enet_crc64(buffers, bufferCount); } } [SuppressUnmanagedCodeSecurity] internal static class Native { #if __IOS__ || UNITY_IOS && !UNITY_EDITOR private const string nativeLibrary = "__Internal"; #else private const string nativeLibrary = "enet"; #endif [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_initialize(); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_initialize_with_callbacks(uint version, ref ENetCallbacks inits); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_deinitialize(); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_linked_version(); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_time_get(); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern ulong enet_crc64(IntPtr buffers, int bufferCount); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_address_set_ip(ref ENetAddress address, string ip); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_address_set_hostname(ref ENetAddress address, string hostName); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_address_get_ip(ref ENetAddress address, StringBuilder ip, IntPtr ipLength); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_address_get_hostname(ref ENetAddress address, StringBuilder hostName, IntPtr nameLength); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_packet_create(byte[] data, IntPtr dataLength, PacketFlags flags); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_packet_create(IntPtr data, IntPtr dataLength, PacketFlags flags); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_packet_create_offset(byte[] data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_packet_create_offset(IntPtr data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_packet_check_references(IntPtr packet); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_packet_get_data(IntPtr packet); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_packet_get_user_data(IntPtr packet); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_packet_set_user_data(IntPtr packet, IntPtr userData); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_packet_get_length(IntPtr packet); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_packet_set_free_callback(IntPtr packet, IntPtr callback); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_packet_dispose(IntPtr packet); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_host_create(ref ENetAddress address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_host_create(IntPtr address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_host_connect(IntPtr host, ref ENetAddress address, IntPtr channelCount, uint data); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_broadcast(IntPtr host, byte channelID, IntPtr packet); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_broadcast_exclude(IntPtr host, byte channelID, IntPtr packet, IntPtr excludedPeer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_broadcast_selective(IntPtr host, byte channelID, IntPtr packet, IntPtr[] peers, IntPtr peersLength); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_host_service(IntPtr host, out ENetEvent @event, uint timeout); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_host_check_events(IntPtr host, out ENetEvent @event); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_channel_limit(IntPtr host, IntPtr channelLimit); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_bandwidth_limit(IntPtr host, uint incomingBandwidth, uint outgoingBandwidth); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_host_get_peers_count(IntPtr host); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_host_get_packets_sent(IntPtr host); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_host_get_packets_received(IntPtr host); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_host_get_bytes_sent(IntPtr host); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_host_get_bytes_received(IntPtr host); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_set_max_duplicate_peers(IntPtr host, ushort number); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_set_intercept_callback(IntPtr host, IntPtr callback); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_set_checksum_callback(IntPtr host, IntPtr callback); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_flush(IntPtr host); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_destroy(IntPtr host); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_host_prevent_connections(IntPtr host, byte state); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_throttle_configure(IntPtr peer, uint interval, uint acceleration, uint deceleration, uint threshold); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_peer_get_id(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_peer_get_ip(IntPtr peer, byte[] ip, IntPtr ipLength); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern ushort enet_peer_get_port(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_peer_get_mtu(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern PeerState enet_peer_get_state(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_peer_get_rtt(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_peer_get_last_rtt(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_peer_get_lastsendtime(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern uint enet_peer_get_lastreceivetime(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern ulong enet_peer_get_packets_sent(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern ulong enet_peer_get_packets_lost(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern float enet_peer_get_packets_throttle(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern ulong enet_peer_get_bytes_sent(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern ulong enet_peer_get_bytes_received(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_peer_get_data(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_set_data(IntPtr peer, IntPtr data); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern int enet_peer_send(IntPtr peer, byte channelID, IntPtr packet); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr enet_peer_receive(IntPtr peer, out byte channelID); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_ping(IntPtr peer); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_ping_interval(IntPtr peer, uint pingInterval); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_timeout(IntPtr peer, uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_disconnect(IntPtr peer, uint data); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_disconnect_now(IntPtr peer, uint data); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_disconnect_later(IntPtr peer, uint data); [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] internal static extern void enet_peer_reset(IntPtr peer); } }