diff --git a/host.c b/host.c index fff946a3..d6c3fc9d 100644 --- a/host.c +++ b/host.c @@ -48,12 +48,22 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL } memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); + host -> activePeers = (ENetPeer **)enet_malloc((peerCount + 1) * sizeof(ENetPeer*)); + if (host->activePeers == NULL) + { + enet_free(host->peers); + enet_free(host); + return NULL; + } + memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); + host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0)) { if (host -> socket != ENET_SOCKET_NULL) enet_socket_destroy (host -> socket); + enet_free (host -> activePeers); enet_free (host -> peers); enet_free (host); @@ -84,6 +94,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL host -> recalculateBandwidthLimits = 0; host -> mtu = ENET_HOST_DEFAULT_MTU; host -> peerCount = peerCount; + host -> peerStatesChanged = 1; host -> commandCount = 0; host -> bufferCount = 0; host -> checksum = NULL; @@ -157,6 +168,7 @@ enet_host_destroy (ENetHost * host) if (host -> compressor.context != NULL && host -> compressor.destroy) (* host -> compressor.destroy) (host -> compressor.context); + enet_free (host -> activePeers); enet_free (host -> peers); enet_free (host); } @@ -208,7 +220,7 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC if (currentPeer -> channels == NULL) return NULL; currentPeer -> channelCount = channelCount; - currentPeer -> state = ENET_PEER_STATE_CONNECTING; + enet_peer_change_state(currentPeer, ENET_PEER_STATE_CONNECTING); currentPeer -> address = * address; currentPeer -> connectID = enet_host_random (host); currentPeer -> mtu = host -> mtu; diff --git a/include/enet/enet.h b/include/enet/enet.h index dfa2c703..ec9d42a6 100644 --- a/include/enet/enet.h +++ b/include/enet/enet.h @@ -368,6 +368,8 @@ typedef struct _ENetHost int recalculateBandwidthLimits; ENetPeer * peers; /**< array of peers allocated for this host */ size_t peerCount; /**< number of peers allocated for this host */ + int peerStatesChanged; /**< 0,1 - flagged on any peer state change */ + ENetPeer ** activePeers; /**< active peer pointers */ size_t channelLimit; /**< maximum number of channels allowed for connected peers */ enet_uint32 serviceTime; ENetList dispatchQueue; @@ -599,6 +601,7 @@ extern void enet_peer_dispatch_incoming_unreliable_commands (EN extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *); extern void enet_peer_on_connect (ENetPeer *); extern void enet_peer_on_disconnect (ENetPeer *); +extern void enet_peer_change_state(ENetPeer *, ENetPeerState); ENET_API void * enet_range_coder_create (void); ENET_API void enet_range_coder_destroy (void *); diff --git a/peer.c b/peer.c index df8f40f3..c0538aff 100644 --- a/peer.c +++ b/peer.c @@ -376,6 +376,16 @@ enet_peer_on_disconnect (ENetPeer * peer) } } +void +enet_peer_change_state(ENetPeer * peer, ENetPeerState newState) +{ + peer->state = newState; + if (peer->host) + { + peer->host->peerStatesChanged = 1; + } +} + /** Forcefully disconnects a peer. @param peer peer to forcefully disconnect @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout @@ -389,7 +399,7 @@ enet_peer_reset (ENetPeer * peer) peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; peer -> connectID = 0; - peer -> state = ENET_PEER_STATE_DISCONNECTED; + enet_peer_change_state(peer, ENET_PEER_STATE_DISCONNECTED); peer -> incomingBandwidth = 0; peer -> outgoingBandwidth = 0; @@ -565,7 +575,7 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) { enet_peer_on_disconnect (peer); - peer -> state = ENET_PEER_STATE_DISCONNECTING; + enet_peer_change_state(peer, ENET_PEER_STATE_DISCONNECTING); } else { @@ -597,7 +607,7 @@ enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data) if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && enet_peer_has_outgoing_commands (peer)) { - peer -> state = ENET_PEER_STATE_DISCONNECT_LATER; + enet_peer_change_state(peer, ENET_PEER_STATE_DISCONNECT_LATER); peer -> eventData = data; } else diff --git a/protocol.c b/protocol.c index 1206b58c..6f06c3e9 100644 --- a/protocol.c +++ b/protocol.c @@ -40,7 +40,7 @@ enet_protocol_change_state (ENetHost * host, ENetPeer * peer, ENetPeerState stat else enet_peer_on_disconnect (peer); - peer -> state = state; + enet_peer_change_state(peer, state); } static void @@ -337,7 +337,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet if (peer -> channels == NULL) return NULL; peer -> channelCount = channelCount; - peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; + enet_peer_change_state(peer, ENET_PEER_STATE_ACKNOWLEDGING_CONNECT); peer -> connectID = command -> connect.connectID; peer -> address = host -> receivedAddress; peer -> mtu = host -> mtu; @@ -1596,22 +1596,49 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer, ENetLis return canPing; } +static void +enet_protocol_on_peer_states_changed(ENetHost * host) +{ + // Update active peers array + enet_uint16 activePeersPos = 0; + for (ENetPeer *currentPeer = host->peers; currentPeer < &host -> peers[host->peerCount]; ++currentPeer) + { + if (currentPeer -> state != ENET_PEER_STATE_DISCONNECTED && + currentPeer -> state != ENET_PEER_STATE_ZOMBIE) + { + host -> activePeers[activePeersPos] = currentPeer; + activePeersPos++; + } + } + // End of active peers + host -> activePeers[activePeersPos] = NULL; +} + static int enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts) { enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)]; ENetProtocolHeader * header = (ENetProtocolHeader *) headerData; int sentLength = 0; + ENetPeer * currentPeer = NULL; size_t shouldCompress = 0; ENetList sentUnreliableCommands; enet_list_clear (& sentUnreliableCommands); for (int sendPass = 0, continueSending = 0; sendPass <= continueSending; ++ sendPass) - for (ENetPeer * currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) { + // Check if active peers array must be refilled. + // Normally a peer state is stable and equals Connected or Disconnected, so no refilling is required. + if (host->peerStatesChanged) + { + host->peerStatesChanged = 0; + enet_protocol_on_peer_states_changed(host); + } + + for (enet_uint16 i = 0; host->activePeers[i]; ++i) + { + currentPeer = host->activePeers[i]; if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED || currentPeer -> state == ENET_PEER_STATE_ZOMBIE || (sendPass > 0 && ! (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING))) @@ -1737,6 +1764,7 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch nextPeer: if (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING) continueSending = sendPass + 1; + } } return 0;