static int enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) { ENetPeer * currentPeer = host -> lastServicedPeer; ENetChannel * channel; do { ++ currentPeer; if (currentPeer >= & host -> peers [host -> peerCount]) currentPeer = host -> peers; if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) continue; if (currentPeer -> state == ENET_PEER_STATE_ZOMBIE) { host -> recalculateBandwidthLimits = 1; event -> type = ENET_EVENT_TYPE_DISCONNECT; event -> peer = currentPeer; enet_peer_reset (currentPeer); host -> lastServicedPeer = currentPeer; return 1; } for (channel = currentPeer -> channels; channel < & currentPeer -> channels [currentPeer -> channelCount]; ++ channel) { if (enet_list_empty (& channel -> incomingReliableCommands) && enet_list_empty (& channel -> incomingUnreliableCommands)) continue; event -> packet = enet_peer_receive (currentPeer, (enet_uint8)(channel - currentPeer -> channels)); if (event -> packet == NULL) continue; event -> type = ENET_EVENT_TYPE_RECEIVE; event -> peer = currentPeer; event -> channelID = (enet_uint8) (channel - currentPeer -> channels); host -> lastServicedPeer = currentPeer; return 1; } } while (currentPeer != host -> lastServicedPeer); return 0; }
// called from ---NETPLAY--- thread unsigned int NetPlayServer::OnConnect(ENetPeer* socket) { sf::Packet rpac; ENetPacket* epack; do { epack = enet_peer_receive(socket, nullptr); } while (epack == nullptr); rpac.append(epack->data, epack->dataLength); // give new client first available id PlayerId pid = 1; for (auto i = m_players.begin(); i != m_players.end(); ++i) { if (i->second.pid == pid) { pid++; i = m_players.begin(); } } socket->data = new PlayerId(pid); std::string npver; rpac >> npver; // Dolphin netplay version if (npver != Common::scm_rev_git_str) return CON_ERR_VERSION_MISMATCH; // game is currently running if (m_is_running) return CON_ERR_GAME_RUNNING; // too many players if (m_players.size() >= 255) return CON_ERR_SERVER_FULL; // cause pings to be updated m_update_pings = true; Client player; player.pid = pid; player.socket = socket; rpac >> player.revision; rpac >> player.name; enet_packet_destroy(epack); // try to automatically assign new user a pad for (PadMapping& mapping : m_pad_map) { if (mapping == -1) { mapping = player.pid; break; } } // send join message to already connected clients sf::Packet spac; spac << static_cast<MessageId>(NP_MSG_PLAYER_JOIN); spac << player.pid << player.name << player.revision; SendToClients(spac); // send new client success message with their id spac.clear(); spac << static_cast<MessageId>(0); spac << player.pid; Send(player.socket, spac); // send new client the selected game if (m_selected_game != "") { spac.clear(); spac << static_cast<MessageId>(NP_MSG_CHANGE_GAME); spac << m_selected_game; Send(player.socket, spac); } if (!m_host_input_authority) { // send the pad buffer value spac.clear(); spac << static_cast<MessageId>(NP_MSG_PAD_BUFFER); spac << static_cast<u32>(m_target_buffer_size); Send(player.socket, spac); } // send input authority state spac.clear(); spac << static_cast<MessageId>(NP_MSG_HOST_INPUT_AUTHORITY); spac << m_host_input_authority; Send(player.socket, spac); // sync GC SRAM with new client if (!g_SRAM_netplay_initialized) { SConfig::GetInstance().m_strSRAM = File::GetUserPath(F_GCSRAM_IDX); InitSRAM(); g_SRAM_netplay_initialized = true; } spac.clear(); spac << static_cast<MessageId>(NP_MSG_SYNC_GC_SRAM); for (size_t i = 0; i < sizeof(g_SRAM) - offsetof(Sram, settings); ++i) { spac << g_SRAM[offsetof(Sram, settings) + i]; } Send(player.socket, spac); // sync values with new client for (const auto& p : m_players) { spac.clear(); spac << static_cast<MessageId>(NP_MSG_PLAYER_JOIN); spac << p.second.pid << p.second.name << p.second.revision; Send(player.socket, spac); spac.clear(); spac << static_cast<MessageId>(NP_MSG_GAME_STATUS); spac << p.second.pid << static_cast<u32>(p.second.game_status); Send(player.socket, spac); } if (Config::Get(Config::NETPLAY_ENABLE_QOS)) player.qos_session = Common::QoSSession(player.socket); // add client to the player list { std::lock_guard<std::recursive_mutex> lkp(m_crit.players); m_players.emplace(*(PlayerId*)player.socket->data, std::move(player)); UpdatePadMapping(); // sync pad mappings with everyone UpdateWiimoteMapping(); } return 0; }