mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-05-01 17:54:53 +00:00
Merge pull request #10944 from Sage-King/NetPlayServerUpdates
NetPlayServer.cpp OnConnect() Minor Code Updates
This commit is contained in:
commit
4f96d2f1c3
5 changed files with 116 additions and 88 deletions
|
@ -152,8 +152,9 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend reliable traffic timeout
|
// Update time in milliseconds of no acknoledgment of
|
||||||
enet_peer_timeout(m_server, 0, PEER_TIMEOUT, PEER_TIMEOUT);
|
// sent packets before a connection is deemed disconnected
|
||||||
|
enet_peer_timeout(m_server, 0, PEER_TIMEOUT.count(), PEER_TIMEOUT.count());
|
||||||
|
|
||||||
ENetEvent netEvent;
|
ENetEvent netEvent;
|
||||||
int net = enet_host_service(m_client, &netEvent, 5000);
|
int net = enet_host_service(m_client, &netEvent, 5000);
|
||||||
|
@ -211,8 +212,9 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
||||||
case ENET_EVENT_TYPE_CONNECT:
|
case ENET_EVENT_TYPE_CONNECT:
|
||||||
m_server = netEvent.peer;
|
m_server = netEvent.peer;
|
||||||
|
|
||||||
// Extend reliable traffic timeout
|
// Update time in milliseconds of no acknoledgment of
|
||||||
enet_peer_timeout(m_server, 0, PEER_TIMEOUT, PEER_TIMEOUT);
|
// sent packets before a connection is deemed disconnected
|
||||||
|
enet_peer_timeout(m_server, 0, PEER_TIMEOUT.count(), PEER_TIMEOUT.count());
|
||||||
|
|
||||||
if (Connect())
|
if (Connect())
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <SFML/Network/Packet.hpp>
|
#include <SFML/Network/Packet.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -14,7 +15,10 @@
|
||||||
|
|
||||||
namespace NetPlay
|
namespace NetPlay
|
||||||
{
|
{
|
||||||
constexpr u32 PEER_TIMEOUT = 30000;
|
using namespace std::chrono_literals;
|
||||||
|
// An arbitrary amount of time of no acknowledgement of sent packets before netplay decides a
|
||||||
|
// connection is disconnected
|
||||||
|
constexpr std::chrono::milliseconds PEER_TIMEOUT = 30s;
|
||||||
|
|
||||||
bool CompressFileIntoPacket(const std::string& file_path, sf::Packet& packet);
|
bool CompressFileIntoPacket(const std::string& file_path, sf::Packet& packet);
|
||||||
bool CompressFolderIntoPacket(const std::string& folder_path, sf::Packet& packet);
|
bool CompressFolderIntoPacket(const std::string& folder_path, sf::Packet& packet);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
@ -379,119 +380,78 @@ static void SendSyncIdentifier(sf::Packet& spac, const SyncIdentifier& sync_iden
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---NETPLAY--- thread
|
// called from ---NETPLAY--- thread
|
||||||
ConnectionError NetPlayServer::OnConnect(ENetPeer* socket, sf::Packet& rpac)
|
ConnectionError NetPlayServer::OnConnect(ENetPeer* incoming_connection, sf::Packet& received_packet)
|
||||||
{
|
{
|
||||||
// give new client first available id
|
std::string netplay_version;
|
||||||
PlayerId pid = 1;
|
received_packet >> netplay_version;
|
||||||
for (auto i = m_players.begin(); i != m_players.end(); ++i)
|
if (netplay_version != Common::GetScmRevGitStr())
|
||||||
{
|
|
||||||
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::GetScmRevGitStr())
|
|
||||||
return ConnectionError::VersionMismatch;
|
return ConnectionError::VersionMismatch;
|
||||||
|
|
||||||
// game is currently running or game start is pending
|
|
||||||
if (m_is_running || m_start_pending)
|
if (m_is_running || m_start_pending)
|
||||||
return ConnectionError::GameRunning;
|
return ConnectionError::GameRunning;
|
||||||
|
|
||||||
// too many players
|
|
||||||
if (m_players.size() >= 255)
|
if (m_players.size() >= 255)
|
||||||
return ConnectionError::ServerFull;
|
return ConnectionError::ServerFull;
|
||||||
|
|
||||||
Client player;
|
Client new_player{};
|
||||||
player.pid = pid;
|
new_player.pid = GiveFirstAvailableIDTo(incoming_connection);
|
||||||
player.socket = socket;
|
new_player.socket = incoming_connection;
|
||||||
|
|
||||||
rpac >> player.revision;
|
received_packet >> new_player.revision;
|
||||||
rpac >> player.name;
|
received_packet >> new_player.name;
|
||||||
|
|
||||||
if (StringUTF8CodePointCount(player.name) > MAX_NAME_LENGTH)
|
if (StringUTF8CodePointCount(new_player.name) > MAX_NAME_LENGTH)
|
||||||
return ConnectionError::NameTooLong;
|
return ConnectionError::NameTooLong;
|
||||||
|
|
||||||
// Extend reliable traffic timeout
|
// Update time in milliseconds of no acknoledgment of
|
||||||
enet_peer_timeout(socket, 0, PEER_TIMEOUT, PEER_TIMEOUT);
|
// sent packets before a connection is deemed disconnected
|
||||||
|
enet_peer_timeout(incoming_connection, 0, PEER_TIMEOUT.count(), PEER_TIMEOUT.count());
|
||||||
|
|
||||||
// cause pings to be updated
|
// force a ping on first netplay loop
|
||||||
m_update_pings = true;
|
m_update_pings = true;
|
||||||
|
|
||||||
// try to automatically assign new user a pad
|
AssignNewUserAPad(new_player);
|
||||||
for (PlayerId& mapping : m_pad_map)
|
|
||||||
{
|
|
||||||
if (mapping == 0)
|
|
||||||
{
|
|
||||||
mapping = player.pid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// send join message to already connected clients
|
// tell other players a new player joined
|
||||||
sf::Packet spac;
|
SendResponseToAllPlayers(MessageID::PlayerJoin, new_player.pid, new_player.name,
|
||||||
spac << MessageID::PlayerJoin;
|
new_player.revision);
|
||||||
spac << player.pid << player.name << player.revision;
|
|
||||||
SendToClients(spac);
|
|
||||||
|
|
||||||
// send new client success message with their ID
|
// tell new client they connected and their ID
|
||||||
spac.clear();
|
SendResponseToPlayer(new_player, MessageID::ConnectionSuccessful, new_player.pid);
|
||||||
spac << MessageID::ConnectionSuccessful;
|
|
||||||
spac << player.pid;
|
|
||||||
Send(player.socket, spac);
|
|
||||||
|
|
||||||
// send new client the selected game
|
// tell new client the selected game
|
||||||
if (!m_selected_game_name.empty())
|
if (!m_selected_game_name.empty())
|
||||||
{
|
{
|
||||||
spac.clear();
|
sf::Packet send_packet;
|
||||||
spac << MessageID::ChangeGame;
|
send_packet << MessageID::ChangeGame;
|
||||||
SendSyncIdentifier(spac, m_selected_game_identifier);
|
SendSyncIdentifier(send_packet, m_selected_game_identifier);
|
||||||
spac << m_selected_game_name;
|
send_packet << m_selected_game_name;
|
||||||
Send(player.socket, spac);
|
Send(new_player.socket, send_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_host_input_authority)
|
if (!m_host_input_authority)
|
||||||
|
SendResponseToPlayer(new_player, MessageID::PadBuffer, m_target_buffer_size);
|
||||||
|
|
||||||
|
SendResponseToPlayer(new_player, MessageID::HostInputAuthority, m_host_input_authority);
|
||||||
|
|
||||||
|
for (const auto& existing_player : m_players)
|
||||||
{
|
{
|
||||||
// send the pad buffer value
|
SendResponseToPlayer(new_player, MessageID::PlayerJoin, existing_player.second.pid,
|
||||||
spac.clear();
|
existing_player.second.name, existing_player.second.revision);
|
||||||
spac << MessageID::PadBuffer;
|
|
||||||
spac << m_target_buffer_size;
|
|
||||||
Send(player.socket, spac);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send input authority state
|
SendResponseToPlayer(new_player, MessageID::GameStatus, existing_player.second.pid,
|
||||||
spac.clear();
|
static_cast<u8>(existing_player.second.game_status));
|
||||||
spac << MessageID::HostInputAuthority;
|
|
||||||
spac << m_host_input_authority;
|
|
||||||
Send(player.socket, spac);
|
|
||||||
|
|
||||||
// sync values with new client
|
|
||||||
for (const auto& p : m_players)
|
|
||||||
{
|
|
||||||
spac.clear();
|
|
||||||
spac << MessageID::PlayerJoin;
|
|
||||||
spac << p.second.pid << p.second.name << p.second.revision;
|
|
||||||
Send(player.socket, spac);
|
|
||||||
|
|
||||||
spac.clear();
|
|
||||||
spac << MessageID::GameStatus;
|
|
||||||
spac << p.second.pid << p.second.game_status;
|
|
||||||
Send(player.socket, spac);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config::Get(Config::NETPLAY_ENABLE_QOS))
|
if (Config::Get(Config::NETPLAY_ENABLE_QOS))
|
||||||
player.qos_session = Common::QoSSession(player.socket);
|
new_player.qos_session = Common::QoSSession(new_player.socket);
|
||||||
|
|
||||||
// add client to the player list
|
|
||||||
{
|
{
|
||||||
std::lock_guard lkp(m_crit.players);
|
std::lock_guard lkp(m_crit.players);
|
||||||
m_players.emplace(*PeerPlayerId(player.socket), std::move(player));
|
// add new player to list of players
|
||||||
UpdatePadMapping(); // sync pad mappings with everyone
|
m_players.emplace(*PeerPlayerId(new_player.socket), std::move(new_player));
|
||||||
|
// sync pad mappings with everyone
|
||||||
|
UpdatePadMapping();
|
||||||
UpdateGBAConfig();
|
UpdateGBAConfig();
|
||||||
UpdateWiimoteMapping();
|
UpdateWiimoteMapping();
|
||||||
}
|
}
|
||||||
|
@ -2085,6 +2045,57 @@ bool NetPlayServer::PlayerHasControllerMapped(const PlayerId pid) const
|
||||||
std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id);
|
std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetPlayServer::AssignNewUserAPad(const Client& player)
|
||||||
|
{
|
||||||
|
for (PlayerId& mapping : m_pad_map)
|
||||||
|
{
|
||||||
|
// 0 means unmapped
|
||||||
|
if (mapping == 0)
|
||||||
|
{
|
||||||
|
mapping = player.pid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerId NetPlayServer::GiveFirstAvailableIDTo(ENetPeer* player)
|
||||||
|
{
|
||||||
|
PlayerId pid = 1;
|
||||||
|
for (auto i = m_players.begin(); i != m_players.end(); ++i)
|
||||||
|
{
|
||||||
|
if (i->second.pid == pid)
|
||||||
|
{
|
||||||
|
pid++;
|
||||||
|
i = m_players.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player->data = new PlayerId(pid);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Data>
|
||||||
|
void NetPlayServer::SendResponseToPlayer(const Client& player, const MessageID message_id,
|
||||||
|
Data&&... data_to_send)
|
||||||
|
{
|
||||||
|
sf::Packet response;
|
||||||
|
response << message_id;
|
||||||
|
// this is a C++17 fold expression used to call the << operator for all of the data
|
||||||
|
(response << ... << std::forward<Data>(data_to_send));
|
||||||
|
|
||||||
|
Send(player.socket, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Data>
|
||||||
|
void NetPlayServer::SendResponseToAllPlayers(const MessageID message_id, Data&&... data_to_send)
|
||||||
|
{
|
||||||
|
sf::Packet response;
|
||||||
|
response << message_id;
|
||||||
|
// this is a C++17 fold expression used to call the << operator for all of the data
|
||||||
|
(response << ... << std::forward<Data>(data_to_send));
|
||||||
|
|
||||||
|
SendToClients(response);
|
||||||
|
}
|
||||||
|
|
||||||
u16 NetPlayServer::GetPort() const
|
u16 NetPlayServer::GetPort() const
|
||||||
{
|
{
|
||||||
return m_server->address.port;
|
return m_server->address.port;
|
||||||
|
|
|
@ -126,10 +126,15 @@ private:
|
||||||
|
|
||||||
u64 GetInitialNetPlayRTC() const;
|
u64 GetInitialNetPlayRTC() const;
|
||||||
|
|
||||||
|
template <typename... Data>
|
||||||
|
void SendResponseToPlayer(const Client& player, const MessageID message_id,
|
||||||
|
Data&&... data_to_send);
|
||||||
|
template <typename... Data>
|
||||||
|
void SendResponseToAllPlayers(const MessageID message_id, Data&&... data_to_send);
|
||||||
void SendToClients(const sf::Packet& packet, PlayerId skip_pid = 0,
|
void SendToClients(const sf::Packet& packet, PlayerId skip_pid = 0,
|
||||||
u8 channel_id = DEFAULT_CHANNEL);
|
u8 channel_id = DEFAULT_CHANNEL);
|
||||||
void Send(ENetPeer* socket, const sf::Packet& packet, u8 channel_id = DEFAULT_CHANNEL);
|
void Send(ENetPeer* socket, const sf::Packet& packet, u8 channel_id = DEFAULT_CHANNEL);
|
||||||
ConnectionError OnConnect(ENetPeer* socket, sf::Packet& rpac);
|
ConnectionError OnConnect(ENetPeer* socket, sf::Packet& received_packet);
|
||||||
unsigned int OnDisconnect(const Client& player);
|
unsigned int OnDisconnect(const Client& player);
|
||||||
unsigned int OnData(sf::Packet& packet, Client& player);
|
unsigned int OnData(sf::Packet& packet, Client& player);
|
||||||
|
|
||||||
|
@ -147,6 +152,12 @@ private:
|
||||||
void SetupIndex();
|
void SetupIndex();
|
||||||
bool PlayerHasControllerMapped(PlayerId pid) const;
|
bool PlayerHasControllerMapped(PlayerId pid) const;
|
||||||
|
|
||||||
|
// pulled from OnConnect()
|
||||||
|
void AssignNewUserAPad(const Client& player);
|
||||||
|
// pulled from OnConnect()
|
||||||
|
// returns the PID given
|
||||||
|
PlayerId GiveFirstAvailableIDTo(ENetPeer* player);
|
||||||
|
|
||||||
NetSettings m_settings;
|
NetSettings m_settings;
|
||||||
|
|
||||||
bool m_is_running = false;
|
bool m_is_running = false;
|
||||||
|
|
|
@ -36,7 +36,7 @@ struct SyncIdentifier
|
||||||
|
|
||||||
// The order of entries in this enum matters, as the lowest value is
|
// The order of entries in this enum matters, as the lowest value is
|
||||||
// treated as the "best" available option.
|
// treated as the "best" available option.
|
||||||
enum class SyncIdentifierComparison
|
enum class SyncIdentifierComparison : u8
|
||||||
{
|
{
|
||||||
SameGame,
|
SameGame,
|
||||||
DifferentHash,
|
DifferentHash,
|
||||||
|
|
Loading…
Add table
Reference in a new issue