import atexit from cpython cimport bool cdef extern from "enet/types.h": ctypedef unsigned char enet_uint8 ctypedef unsigned short enet_uint16 ctypedef unsigned int enet_uint32 ctypedef unsigned int size_t cdef extern from "enet/enet.h": ctypedef enet_uint32 ENetVersion # forward declaration ctypedef struct ENetPeer ctypedef struct ENetHost cdef enum: ENET_HOST_ANY = 0 ENET_HOST_BROADCAST = 0xFFFFFFFF ENET_PORT_ANY = 0 ctypedef int ENetSocket ctypedef struct ENetAddress: enet_uint32 host enet_uint16 port ctypedef enum ENetPacketFlag: ENET_PACKET_FLAG_RELIABLE = (1 << 0) ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1) ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2) ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3) ctypedef struct ENetPacket: size_t referenceCount enet_uint32 flags enet_uint8 *data size_t dataLength ctypedef enum ENetPeerState: ENET_PEER_STATE_DISCONNECTED = 0 ENET_PEER_STATE_CONNECTING = 1 ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2 ENET_PEER_STATE_CONNECTION_PENDING = 3 ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4 ENET_PEER_STATE_CONNECTED = 5 ENET_PEER_STATE_DISCONNECT_LATER = 6 ENET_PEER_STATE_DISCONNECTING = 7 ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8 ENET_PEER_STATE_ZOMBIE = 9 ctypedef struct ENetPeer: ENetHost *host enet_uint16 outgoingPeerID enet_uint16 incomingPeerID enet_uint32 connectID enet_uint8 outgoingSessionID enet_uint8 incomingSessionID ENetAddress address char *data ENetPeerState state size_t channelCount enet_uint32 incomingBandwidth enet_uint32 outgoingBandwidth enet_uint32 incomingBandwidthThrottleEpoch enet_uint32 outgoingBandwidthThrottleEpoch enet_uint32 incomingDataTotal enet_uint32 outgoingDataTotal enet_uint32 lastSendTime enet_uint32 lastReceiveTime enet_uint32 nextTimeout enet_uint32 earliestTimeout enet_uint32 packetLossEpoch enet_uint32 packetsSent enet_uint32 packetsLost enet_uint32 packetLoss enet_uint32 packetLossVariance enet_uint32 packetThrottle enet_uint32 packetThrottleLimit enet_uint32 packetThrottleCounter enet_uint32 packetThrottleEpoch enet_uint32 packetThrottleAcceleration enet_uint32 packetThrottleDeceleration enet_uint32 packetThrottleInterval enet_uint32 lastRoundTripTime enet_uint32 lowestRoundTripTime enet_uint32 lastRoundTripTimeVariance enet_uint32 highestRoundTripTimeVariance enet_uint32 roundTripTime enet_uint32 roundTripTimeVariance enet_uint32 mtu enet_uint32 windowSize enet_uint32 reliableDataInTransit enet_uint16 outgoingReliableSequenceNumber int needsDispatch enet_uint16 incomingUnsequencedGroup enet_uint16 outgoingUnsequencedGroup enet_uint32 unsequencedWindow enet_uint32 eventData ctypedef struct ENetHost: ENetSocket socket ENetAddress address enet_uint32 incomingBandwidth enet_uint32 outgoingBandwidth ENetPeer *peers size_t peerCount size_t channelLimit enet_uint32 totalSentData enet_uint32 totalSentPackets enet_uint32 totalReceivedData enet_uint32 totalReceivedPackets ctypedef enum ENetEventType: ENET_EVENT_TYPE_NONE = 0 ENET_EVENT_TYPE_CONNECT = 1 ENET_EVENT_TYPE_DISCONNECT = 2 ENET_EVENT_TYPE_RECEIVE = 3 ctypedef struct ENetEvent: ENetEventType type ENetPeer *peer enet_uint8 channelID enet_uint32 data ENetPacket *packet # Global functions int enet_initialize() void enet_deinitialize() # Address functions int enet_address_set_host(ENetAddress *address, char *hostName) int enet_address_get_host_ip(ENetAddress *address, char *hostName, size_t nameLength) int enet_address_get_host(ENetAddress *address, char *hostName, size_t nameLength) # Packet functions ENetPacket* enet_packet_create(char *dataContents, size_t dataLength, enet_uint32 flags) void enet_packet_destroy(ENetPacket *packet) int enet_packet_resize(ENetPacket *packet, size_t dataLength) # Host functions int enet_host_compress_with_range_coder(ENetHost *host) ENetHost* enet_host_create(ENetAddress *address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) void enet_host_destroy(ENetHost *host) ENetPeer* enet_host_connect(ENetHost *host, ENetAddress *address, size_t channelCount, enet_uint32 data) void enet_host_broadcast(ENetHost *host, enet_uint8 channelID, ENetPacket *packet) void enet_host_channel_limit(ENetHost *host, size_t channelLimit) void enet_host_bandwidth_limit(ENetHost *host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) void enet_host_flush(ENetHost *host) int enet_host_check_events(ENetHost *host, ENetEvent *event) int enet_host_service(ENetHost *host, ENetEvent *event, enet_uint32 timeout) # Peer functions void enet_peer_throttle_configure(ENetPeer *peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deacceleration) int enet_peer_send(ENetPeer *peer, enet_uint8 channelID, ENetPacket *packet) ENetPacket* enet_peer_receive(ENetPeer *peer, enet_uint8 *channelID) void enet_peer_ping(ENetPeer *peer) void enet_peer_reset(ENetPeer *peer) void enet_peer_disconnect(ENetPeer *peer, enet_uint32 data) void enet_peer_disconnect_now(ENetPeer *peer, enet_uint32 data) void enet_peer_disconnect_later(ENetPeer *peer, enet_uint32 data) cdef enum: MAXHOSTNAME = 257 PACKET_FLAG_RELIABLE = ENET_PACKET_FLAG_RELIABLE PACKET_FLAG_UNSEQUENCED = ENET_PACKET_FLAG_UNSEQUENCED PACKET_FLAG_NO_ALLOCATE = ENET_PACKET_FLAG_NO_ALLOCATE PACKET_FLAG_UNRELIABLE_FRAGMENT = ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT EVENT_TYPE_NONE = ENET_EVENT_TYPE_NONE EVENT_TYPE_CONNECT = ENET_EVENT_TYPE_CONNECT EVENT_TYPE_DISCONNECT = ENET_EVENT_TYPE_DISCONNECT EVENT_TYPE_RECEIVE = ENET_EVENT_TYPE_RECEIVE PEER_STATE_DISCONNECTED = ENET_PEER_STATE_DISCONNECTED PEER_STATE_CONNECTING = ENET_PEER_STATE_CONNECTING PEER_STATE_ACKNOWLEDGING_CONNECT = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT PEER_STATE_CONNECTION_PENDING = ENET_PEER_STATE_CONNECTION_PENDING PEER_STATE_CONNECTION_SUCCEEDED = ENET_PEER_STATE_CONNECTION_SUCCEEDED PEER_STATE_CONNECTED = ENET_PEER_STATE_CONNECTED PEER_STATE_DISCONNECT_LATER = ENET_PEER_STATE_DISCONNECT_LATER PEER_STATE_DISCONNECTING = ENET_PEER_STATE_DISCONNECTING PEER_STATE_ACKNOWLEDGING_DISCONNECT = ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT PEER_STATE_ZOMBIE = ENET_PEER_STATE_ZOMBIE cdef class Socket: """ Socket (int socket) DESCRIPTION An ENet socket. Can be used with select and poll. """ cdef ENetSocket _enet_socket def fileno(self): return self._enet_socket cdef class Address: """ Address (str address, int port) ATTRIBUTES str host Hostname referred to by the Address. int port Port referred to by the Address. DESCRIPTION An ENet address and port pair. When instantiated, performs a resolution upon 'address'. However, if 'address' is None, enet.HOST_ANY is assumed. """ cdef ENetAddress _enet_address def __init__(self, host, port): if host is not None: # Convert the hostname to a byte string if needed self.host = host if isinstance(host, bytes) else bytes(host, "ascii") else: self.host = None self.port = port def __str__(self): return "{0}:{1}".format(self.host, self.port) def __richcmp__(self, obj, op): if isinstance(obj, Address): if op == 2: # This is a '==' operation return (obj.host == self.host) and (obj.port == self.port) elif op == 3: # This is a '!=' operation return (obj.host != self.host) or (obj.port != self.port) raise NotImplementedError property host: def __get__(self): cdef char host[MAXHOSTNAME] if self._enet_address.host == ENET_HOST_ANY: return "*" elif self._enet_address.host: if enet_address_get_host_ip(&self._enet_address, host, MAXHOSTNAME): raise IOError("Resolution failure!") return unicode(host, "ascii") def __set__(self, value): if not value or value == "*": self._enet_address.host = ENET_HOST_ANY else: if enet_address_set_host(&self._enet_address, value): raise IOError("Resolution failure!") property hostname: def __get__(self): cdef char host[MAXHOSTNAME] if self._enet_address.host == ENET_HOST_ANY: return "*" elif self._enet_address.host: if enet_address_get_host(&self._enet_address, host, MAXHOSTNAME): raise IOError("Resolution failure!") return unicode(host, "ascii") property port: def __get__(self): return self._enet_address.port def __set__(self, value): self._enet_address.port = value cdef class Packet: """ Packet (str dataContents, int flags) ATTRIBUTES str data Contains the data for the packet. int flags Flags modifying delivery of the Packet: enet.PACKET_FLAG_RELIABLE Packet must be received by the target peer and resend attempts should be made until the packet is delivered. enet.PACKET_FLAG_UNSEQUENCED Packet will not be sequenced with other packets not supported for reliable packets. enet.PACKET_FLAG_NO_ALLOCATE Packet will not allocate data and user must supply it instead. enet.PACKET_FLAG_UNRELIABLE_FRAGMENT Packet will be fragmented using unreliable (instead of reliable) sends if it exceeds the MTU... DESCRIPTION An ENet data packet that may be sent to or received from a peer. """ cdef ENetPacket *_enet_packet cdef bool sent def __init__(self, data=None, flags=0): if data is not None: self._enet_packet = enet_packet_create(data, len(data), flags) # This will get set to True when a peer.send() is called with the Packet # to ensure we don't try to destroy this packet as ENET will handle that # for us. self.sent = False def __dealloc__(self): if self.is_valid() and not self.sent: enet_packet_destroy(self._enet_packet) def is_valid(self): if self._enet_packet: return True else: return False property data: def __get__(self): if self.is_valid(): return (self._enet_packet.data)[:self._enet_packet.dataLength] else: raise MemoryError("Packet has not been initiliazed properly!") property dataLength: def __get__(self): if self.is_valid(): return self._enet_packet.dataLength else: raise MemoryError("Packet has not been initiliazed properly!") property flags: def __get__(self): if self.is_valid(): return self._enet_packet.flags else: raise MemoryError("Packet has not been initiliazed properly!") property sent: def __get__(self): return self.sent def __set__(self, value): self.sent = value cdef class Peer: """ Peer () ATTRIBUTES Address address int state The peer's current state which is one of enet.PEER_STATE_* int packetLoss Mean packet loss of reliable packets as a ratio with respect to the constant enet.PEER_PACKET_LOSS_SCALE. int packetThrottleAcceleration int packetThrottleDeceleration int packetThrottleInterval int roundTripTime Mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement. int incomingPeerID DESCRIPTION An ENet peer which data packets may be sent or received from. This class should never be instantiated directly, but rather via enet.Host.connect or enet.Event.Peer. If you try to access any members of a Peer without being properly instantiated from a Host or Event object then a MemoryError will be raised. """ cdef ENetPeer *_enet_peer def __richcmp__(self, obj, op): if isinstance(obj, Peer): if op == 2: return self.address == obj.address elif op == 3: return self.address != obj.address raise NotImplementedError def send(self, channelID, Packet packet): """ send (int channelID, Packet packet) Queues a packet to be sent. returns 0 on sucess, < 0 on failure """ if self.check_valid() and packet.is_valid(): packet.sent = True return enet_peer_send(self._enet_peer, channelID, packet._enet_packet) def receive(self, unsigned char channelID): """ receive (int channelID) Attempts to dequeue any incoming queued packet. """ if self.check_valid(): packet = Packet() ( packet)._enet_packet = enet_peer_receive(self._enet_peer, &channelID) if packet._enet_packet: return packet else: return None def reset(self): """ reset () Forcefully disconnects a peer. """ if self.check_valid(): enet_peer_reset(self._enet_peer) def ping(self): """ ping () Sends a ping request to a peer. """ if self.check_valid(): enet_peer_ping(self._enet_peer) def disconnect(self, data=0): """ disconnect () Request a disconnection from a peer. """ if self.check_valid(): enet_peer_disconnect(self._enet_peer, data) def disconnect_later(self, data=0): """ disconnect_later () Request a disconnection from a peer, but only after all queued outgoing packets are sent. """ if self.check_valid(): enet_peer_disconnect_later(self._enet_peer, data) def disconnect_now(self, data=0): """ disconnect_now () Force an immediate disconnection from a peer. """ if self.check_valid(): enet_peer_disconnect_now(self._enet_peer, data) def check_valid(self): """ check_valid () Returns True if there is a valid enet_peer set Raises a Memory error if not """ if self._enet_peer: return True else: raise MemoryError("Empty Peer object accessed!") property host: def __get__(self): if self.check_valid(): # be a bit like pickle here. otherwise Host # would create a new enet host inside __init__ h = Host.__new__(Host) ( h)._enet_host = self._enet_peer.host return h property outgoingPeerID: def __get__(self): if self.check_valid(): return self._enet_peer.outgoingPeerID property incomingPeerID: def __get__(self): if self.check_valid(): return self._enet_peer.incomingPeerID property connectID: def __get__(self): if self.check_valid(): return self._enet_peer.connectID property outgoingSessionID: def __get__(self): if self.check_valid(): return self._enet_peer.outgoingSessionID property incomingSessionID: def __get__(self): if self.check_valid(): return self._enet_peer.incomingSessionID property address: def __get__(self): if self.check_valid(): a = Address(None, 0) (
a)._enet_address = self._enet_peer.address return a property data: def __get__(self): if self.check_valid(): return self._enet_peer.data def __set__(self, value): if self.check_valid(): self._enet_peer.data = value property state: def __get__(self): if self.check_valid(): return self._enet_peer.state property channelCount: def __get__(self): if self.check_valid(): return self._enet_peer.channelCount property incomingBandwidth: def __get__(self): if self.check_valid(): return self._enet_peer.incomingBandwidth property outgoingBandwidth: def __get__(self): if self.check_valid(): return self._enet_peer.outgoingBandwidth property incomingBandwidthThrottleEpoch: def __get__(self): if self.check_valid(): return self._enet_peer.incomingBandwidthThrottleEpoch property outgoingBandwidthThrottleEpoch: def __get__(self): if self.check_valid(): return self._enet_peer.outgoingBandwidthThrottleEpoch property incomingDataTotal: def __get__(self): if self.check_valid(): return self._enet_peer.incomingDataTotal property outgoingDataTotal: def __get__(self): if self.check_valid(): return self._enet_peer.outgoingDataTotal property lastSendTime: def __get__(self): if self.check_valid(): return self._enet_peer.lastSendTime property lastReceiveTime: def __get__(self): if self.check_valid(): return self._enet_peer.lastReceiveTime property nextTimeout: def __get__(self): if self.check_valid(): return self._enet_peer.nextTimeout property earliestTimeout: def __get__(self): if self.check_valid(): return self._enet_peer.earliestTimeout property packetLossEpoch: def __get__(self): if self.check_valid(): return self._enet_peer.packetLossEpoch property packetsSent: def __get__(self): if self.check_valid(): return self._enet_peer.packetsSent property packetsLost: def __get__(self): if self.check_valid(): return self._enet_peer.packetsLost property packetLoss: def __get__(self): if self.check_valid(): return self._enet_peer.packetLoss property packetLossVariance: def __get__(self): if self.check_valid(): return self._enet_peer.packetLossVariance property packetThrottle: def __get__(self): if self.check_valid(): return self._enet_peer.packetThrottle property packetThrottleLimit: def __get__(self): if self.check_valid(): return self._enet_peer.packetThrottleLimit property packetThrottleCounter: def __get__(self): if self.check_valid(): return self._enet_peer.packetThrottleCounter property packetThrottleEpoch: def __get__(self): if self.check_valid(): return self._enet_peer.packetThrottleEpoch property packetThrottleAcceleration: def __get__(self): if self.check_valid(): return self._enet_peer.packetThrottleAcceleration def __set__(self, value): if self.check_valid(): enet_peer_throttle_configure(self._enet_peer, self.packetThrottleInterval, value, self.packetThrottleDeceleration) property packetThrottleDeceleration: def __get__(self): if self.check_valid(): return self._enet_peer.packetThrottleDeceleration def __set__(self, value): if self.check_valid(): enet_peer_throttle_configure(self._enet_peer, self.packetThrottleInterval, self.packetThrottleAcceleration, value) property packetThrottleInterval: def __get__(self): if self.check_valid(): return self._enet_peer.packetThrottleInterval def __set__(self, value): if self.check_valid(): enet_peer_throttle_configure( self._enet_peer, value, self.packetThrottleAcceleration, self.packetThrottleDeceleration) property lastRoundTripTime: def __get__(self): if self.check_valid(): return self._enet_peer.lastRoundTripTime property lowestRoundTripTime: def __get__(self): if self.check_valid(): return self._enet_peer.lowestRoundTripTime property lastRoundTripTimeVariance: def __get__(self): if self.check_valid(): return self._enet_peer.lastRoundTripTimeVariance property highestRoundTripTimeVariance: def __get__(self): if self.check_valid(): return self._enet_peer.highestRoundTripTimeVariance property roundTripTime: def __get__(self): if self.check_valid(): return self._enet_peer.roundTripTime property roundTripTimeVariance: def __get__(self): if self.check_valid(): return self._enet_peer.roundTripTimeVariance property mtu: def __get__(self): if self.check_valid(): return self._enet_peer.mtu property windowSize: def __get__(self): if self.check_valid(): return self._enet_peer.windowSize property reliableDataInTransit: def __get__(self): if self.check_valid(): return self._enet_peer.reliableDataInTransit property outgoingReliableSequenceNumber: def __get__(self): if self.check_valid(): return self._enet_peer.outgoingReliableSequenceNumber property needsDispatch: def __get__(self): if self.check_valid(): return self._enet_peer.needsDispatch property incomingUnsequencedGroup: def __get__(self): if self.check_valid(): return self._enet_peer.incomingUnsequencedGroup property outgoingUnsequencedGroup: def __get__(self): if self.check_valid(): return self._enet_peer.outgoingUnsequencedGroup property eventData: def __get__(self): if self.check_valid(): return self._enet_peer.eventData cdef class Event: """ Event () ATTRIBUTES int type Type of the event. Will be enet.EVENT_TYPE_*. Peer peer Peer that generated the event. int channelID Packet packet DESCRIPTION An ENet event as returned by enet.Host.service. This class should never be instantiated directly. """ cdef ENetEvent _enet_event cdef Packet _packet def __init__(self): self._packet = None property type: def __get__(self): return self._enet_event.type property peer: def __get__(self): peer = Peer() ( peer)._enet_peer = self._enet_event.peer return peer property channelID: def __get__(self): return self._enet_event.channelID property data: def __get__(self): return self._enet_event.data property packet: def __get__(self): if not self._packet: self._packet = Packet() ( self._packet)._enet_packet = self._enet_event.packet return self._packet cdef class Host: """ Host (Address address, int peerCount, int channelLimit, int incomingBandwidth, int outgoingBandwidth) ATTRIBUTES Address address Internet address of the host. Socket socket The socket the host services. int incomingBandwidth Downstream bandwidth of the host. int outgoingBandwidth Upstream bandwidth of the host. DESCRIPTION An ENet host for communicating with peers. If 'address' is None, then the Host will be client only. """ cdef ENetHost *_enet_host cdef bool dealloc def __init__ (self, Address address=None, peerCount=0, channelLimit=0, incomingBandwidth=0, outgoingBandwidth=0): if address: self._enet_host = enet_host_create(&address._enet_address, peerCount, channelLimit, incomingBandwidth, outgoingBandwidth) else: self._enet_host = enet_host_create(NULL, peerCount, channelLimit, incomingBandwidth, outgoingBandwidth) if not self._enet_host: raise MemoryError("Unable to create host structure!") self.dealloc = True def __cinit__(self): self.dealloc = False self._enet_host = NULL def __dealloc__(self): if self.dealloc: enet_host_destroy(self._enet_host) def connect(self, Address address, channelCount, data=0): """ Peer connect (Address address, int channelCount, int data) Initiates a connection to a foreign host and returns a Peer. """ if self._enet_host: peer = Peer() ( peer)._enet_peer = enet_host_connect( self._enet_host, &address._enet_address, channelCount, data) if not ( peer)._enet_peer: raise IOError("Connection failure!") return peer def check_events(self): """ Checks for any queued events on the host and dispatches one if available """ if self._enet_host: event = Event() result = enet_host_check_events( self._enet_host, &( event)._enet_event) if result < 0: raise IOError("Servicing error - probably disconnected.") elif result == 0: return None else: return event def service(self, timeout): """ Event service (int timeout) Waits for events on the host specified and shuttles packets between the host and its peers. The timeout is in milliseconds. """ if self._enet_host: event = Event() result = enet_host_service( self._enet_host, &( event)._enet_event, timeout) if result < 0: raise IOError("Servicing error - probably disconnected.") else: return event def flush(self): """ flush () Sends any queued packets on the host specified to its designated peers. """ if self._enet_host: enet_host_flush(self._enet_host) def broadcast(self, channelID, Packet packet): """ broadcast (int channelID, Packet packet) Queues a packet to be sent to all peers associated with the host. """ if self._enet_host: if packet.is_valid(): packet.sent = True enet_host_broadcast(self._enet_host, channelID, packet._enet_packet) def compress_with_range_coder(self): """ Sets the packet compressor the host should use to the default range coder """ if self._enet_host: return enet_host_compress_with_range_coder(self._enet_host); property socket: def __get__(self): socket = Socket() ( socket)._enet_socket = self._enet_host.socket return socket property address: def __get__(self): if self._enet_host: a = Address(None, 0) (
a)._enet_address = self._enet_host.address return a property incomingBandwidth: def __get__(self): return self._enet_host.incomingBandwidth def __set__(self, value): enet_host_bandwidth_limit(self._enet_host, value, self.outgoingBandwidth) property outgoingBandwidth: def __get__(self): return self._enet_host.outgoingBandwidth def __set__(self, value): enet_host_bandwidth_limit(self._enet_host, self.incomingBandwidth, value) property peers: def __get__(self): cdef size_t i peers = [] for i from 0 <= i < self.peerCount: peer = Peer() ( peer)._enet_peer = &self._enet_host.peers[i] peers.append(peer) return peers property peerCount: def __get__(self): return self._enet_host.peerCount property channelLimit: def __get__(self): return self._enet_host.channelLimit def __set__(self, value): enet_host_channel_limit(self._enet_host, value) property totalSentData: def __get__(self): return self._enet_host.totalSentData def __set__(self, value): self._enet_host.totalSentData = value property totalSentPackets: def __get__(self): return self._enet_host.totalSentPackets def __set__(self, value): self._enet_host.totalSentPackets = value property totalReceivedData: def __get__(self): return self._enet_host.totalReceivedData def __set__(self, value): self._enet_host.totalReceivedData = value property totalReceivedPackets: def __get__(self): return self._enet_host.totalReceivedPackets def __set__(self, value): self._enet_host.totalReceivedPackets = value def _enet_atexit(): enet_deinitialize() enet_initialize() atexit.register(_enet_atexit)