Merge pull request #3567 from lioncash/netplay

NetPlayClient: Minor changes
This commit is contained in:
Mathew Maidment 2016-01-25 05:13:54 -05:00
commit 48e7e5b72e
3 changed files with 154 additions and 136 deletions

View File

@ -2,23 +2,23 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm>
#include <memory>
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/ENetUtil.h" #include "Common/ENetUtil.h"
#include "Common/MsgHandler.h"
#include "Common/Timer.h" #include "Common/Timer.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/NetPlayClient.h" #include "Core/NetPlayClient.h"
#include "Core/HW/EXI_DeviceIPL.h" #include "Core/HW/EXI_DeviceIPL.h"
#include "Core/HW/SI.h" #include "Core/HW/SI.h"
#include "Core/HW/SI_DeviceDanceMat.h"
#include "Core/HW/SI_DeviceGCController.h" #include "Core/HW/SI_DeviceGCController.h"
#include "Core/HW/SI_DeviceGCSteeringWheel.h"
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h"
static const char* NETPLAY_VERSION = scm_rev_git_str; static const char* NETPLAY_VERSION = scm_rev_git_str;
static std::mutex crit_netplay_client; static std::mutex crit_netplay_client;
@ -32,7 +32,7 @@ NetPlayClient::~NetPlayClient()
if (m_is_running.load()) if (m_is_running.load())
StopGame(); StopGame();
if (is_connected) if (m_is_connected)
{ {
m_do_loop.store(false); m_do_loop.store(false);
m_thread.join(); m_thread.join();
@ -61,27 +61,11 @@ NetPlayClient::~NetPlayClient()
// called from ---GUI--- thread // called from ---GUI--- thread
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal, const std::string& centralServer, u16 centralPort) NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal, const std::string& centralServer, u16 centralPort)
: m_state(Failure) : m_dialog(dialog)
, m_dialog(dialog) , m_player_name(name)
, m_client(nullptr)
, m_server(nullptr)
, m_is_running(false)
, m_do_loop(true)
, m_target_buffer_size()
, m_local_player(nullptr)
, m_current_game(0)
, m_is_recording(false)
, m_pid(0)
, m_connecting(false)
, m_traversal_client(nullptr)
{ {
m_target_buffer_size = 20;
ClearBuffers(); ClearBuffers();
is_connected = false;
m_player_name = name;
if (!traversal) if (!traversal)
{ {
//Direct Connection //Direct Connection
@ -138,7 +122,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
m_traversal_client->ReconnectToServer(); m_traversal_client->ReconnectToServer();
m_traversal_client->m_Client = this; m_traversal_client->m_Client = this;
m_host_spec = address; m_host_spec = address;
m_state = WaitingForTraversalClientConnection; m_connection_state = ConnectionState::WaitingForTraversalClientConnection;
OnTraversalStateChanged(); OnTraversalStateChanged();
m_connecting = true; m_connecting = true;
@ -160,7 +144,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
m_server = netEvent.peer; m_server = netEvent.peer;
if (Connect()) if (Connect())
{ {
m_state = Connected; m_connection_state = ConnectionState::Connected;
m_thread = std::thread(&NetPlayClient::ThreadFunc, this); m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
} }
return; return;
@ -237,7 +221,7 @@ bool NetPlayClient::Connect()
m_dialog->Update(); m_dialog->Update();
is_connected = true; m_is_connected = true;
return true; return true;
} }
@ -327,11 +311,20 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
{ {
PadMapping map = 0; PadMapping map = 0;
GCPadStatus pad; GCPadStatus pad;
packet >> map >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight; packet >> map
>> pad.button
>> pad.analogA
>> pad.analogB
>> pad.stickX
>> pad.stickY
>> pad.substickX
>> pad.substickY
>> pad.triggerLeft
>> pad.triggerRight;
// trusting server for good map value (>=0 && <4) // Trusting server for good map value (>=0 && <4)
// add to pad buffer // add to pad buffer
m_pad_buffer[map].Push(pad); m_pad_buffer.at(map).Push(pad);
} }
break; break;
@ -347,9 +340,9 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
for (unsigned int i = 0; i < size; ++i) for (unsigned int i = 0; i < size; ++i)
packet >> nw[i]; packet >> nw[i];
// trusting server for good map value (>=0 && <4) // Trusting server for good map value (>=0 && <4)
// add to Wiimote buffer // add to Wiimote buffer
m_wiimote_buffer[(unsigned)map].Push(nw); m_wiimote_buffer.at(map).Push(nw);
} }
break; break;
@ -505,7 +498,7 @@ void NetPlayClient::Disconnect()
{ {
ENetEvent netEvent; ENetEvent netEvent;
m_connecting = false; m_connecting = false;
m_state = Failure; m_connection_state = ConnectionState::Failure;
if (m_server) if (m_server)
enet_peer_disconnect(m_server, 0); enet_peer_disconnect(m_server, 0);
else else
@ -530,11 +523,11 @@ void NetPlayClient::Disconnect()
m_server = nullptr; m_server = nullptr;
} }
void NetPlayClient::SendAsync(sf::Packet* packet) void NetPlayClient::SendAsync(std::unique_ptr<sf::Packet> packet)
{ {
{ {
std::lock_guard<std::recursive_mutex> lkq(m_crit.async_queue_write); std::lock_guard<std::recursive_mutex> lkq(m_crit.async_queue_write);
m_async_queue.Push(std::unique_ptr<sf::Packet>(packet)); m_async_queue.Push(std::move(packet));
} }
ENetUtil::WakeupThread(m_client); ENetUtil::WakeupThread(m_client);
} }
@ -591,29 +584,26 @@ void NetPlayClient::GetPlayerList(std::string& list, std::vector<int>& pid_list)
std::ostringstream ss; std::ostringstream ss;
std::map<PlayerId, Player>::const_iterator const auto enumerate_player_controller_mappings = [&ss](const PadMappingArray& mappings, const Player& player) {
i = m_players.begin(), for (size_t i = 0; i < mappings.size(); i++)
e = m_players.end(); {
for (; i != e; ++i) if (mappings[i] == player.pid)
ss << i + 1;
else
ss << '-';
}
};
for (const auto& entry : m_players)
{ {
const Player *player = &(i->second); const Player& player = entry.second;
ss << player->name << "[" << (int)player->pid << "] : " << player->revision << " | "; ss << player.name << "[" << static_cast<int>(player.pid) << "] : " << player.revision << " | ";
for (unsigned int j = 0; j < 4; j++)
{ enumerate_player_controller_mappings(m_pad_map, player);
if (m_pad_map[j] == player->pid) enumerate_player_controller_mappings(m_wiimote_map, player);
ss << j + 1;
else ss << " |\nPing: " << player.ping << "ms\n\n";
ss << '-'; pid_list.push_back(player.pid);
}
for (unsigned int j = 0; j < 4; j++)
{
if (m_wiimote_map[j] == player->pid)
ss << j + 1;
else
ss << '-';
}
ss << " |\nPing: " << player->ping << "ms\n\n";
pid_list.push_back(player->pid);
} }
list = ss.str(); list = ss.str();
@ -631,50 +621,74 @@ std::vector<const Player*> NetPlayClient::GetPlayers()
return players; return players;
} }
// called from ---GUI--- thread // called from ---GUI--- thread
void NetPlayClient::SendChatMessage(const std::string& msg) void NetPlayClient::SendChatMessage(const std::string& msg)
{ {
sf::Packet* spac = new sf::Packet; auto spac = std::make_unique<sf::Packet>();
*spac << (MessageId)NP_MSG_CHAT_MESSAGE; *spac << static_cast<MessageId>(NP_MSG_CHAT_MESSAGE);
*spac << msg; *spac << msg;
SendAsync(spac);
SendAsync(std::move(spac));
} }
// called from ---CPU--- thread // called from ---CPU--- thread
void NetPlayClient::SendPadState(const PadMapping in_game_pad, const GCPadStatus& pad) void NetPlayClient::SendPadState(const PadMapping in_game_pad, const GCPadStatus& pad)
{ {
sf::Packet* spac = new sf::Packet; auto spac = std::make_unique<sf::Packet>();
*spac << (MessageId)NP_MSG_PAD_DATA; *spac << static_cast<MessageId>(NP_MSG_PAD_DATA);
*spac << in_game_pad; *spac << in_game_pad;
*spac << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight; *spac << pad.button
<< pad.analogA
<< pad.analogB
<< pad.stickX
<< pad.stickY
<< pad.substickX
<< pad.substickY
<< pad.triggerLeft
<< pad.triggerRight;
SendAsync(spac); SendAsync(std::move(spac));
} }
// called from ---CPU--- thread // called from ---CPU--- thread
void NetPlayClient::SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw) void NetPlayClient::SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw)
{ {
sf::Packet* spac = new sf::Packet; auto spac = std::make_unique<sf::Packet>();
*spac << (MessageId)NP_MSG_WIIMOTE_DATA; *spac << static_cast<MessageId>(NP_MSG_WIIMOTE_DATA);
*spac << in_game_pad; *spac << in_game_pad;
*spac << (u8)nw.size(); *spac << static_cast<u8>(nw.size());
for (auto it : nw) for (auto it : nw)
{ {
*spac << it; *spac << it;
} }
SendAsync(spac);
SendAsync(std::move(spac));
}
// called from ---GUI--- thread
void NetPlayClient::SendStartGamePacket()
{
auto spac = std::make_unique<sf::Packet>();
*spac << static_cast<MessageId>(NP_MSG_START_GAME);
*spac << m_current_game;
SendAsync(std::move(spac));
}
// called from ---GUI--- thread
void NetPlayClient::SendStopGamePacket()
{
auto spac = std::make_unique<sf::Packet>();
*spac << static_cast<MessageId>(NP_MSG_STOP_GAME);
SendAsync(std::move(spac));
} }
// called from ---GUI--- thread // called from ---GUI--- thread
bool NetPlayClient::StartGame(const std::string &path) bool NetPlayClient::StartGame(const std::string &path)
{ {
std::lock_guard<std::recursive_mutex> lkg(m_crit.game); std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
// tell server i started the game SendStartGamePacket();
sf::Packet* spac = new sf::Packet;
*spac << (MessageId)NP_MSG_START_GAME;
*spac << m_current_game;
SendAsync(spac);
if (m_is_running.load()) if (m_is_running.load())
{ {
@ -771,13 +785,13 @@ void NetPlayClient::ClearBuffers()
// called from ---NETPLAY--- thread // called from ---NETPLAY--- thread
void NetPlayClient::OnTraversalStateChanged() void NetPlayClient::OnTraversalStateChanged()
{ {
if (m_state == WaitingForTraversalClientConnection && if (m_connection_state == ConnectionState::WaitingForTraversalClientConnection &&
m_traversal_client->m_State == TraversalClient::Connected) m_traversal_client->m_State == TraversalClient::Connected)
{ {
m_state = WaitingForTraversalClientConnectReady; m_connection_state = ConnectionState::WaitingForTraversalClientConnectReady;
m_traversal_client->ConnectToClient(m_host_spec); m_traversal_client->ConnectToClient(m_host_spec);
} }
else if (m_state != Failure && else if (m_connection_state != ConnectionState::Failure &&
m_traversal_client->m_State == TraversalClient::Failure) m_traversal_client->m_State == TraversalClient::Failure)
{ {
Disconnect(); Disconnect();
@ -787,9 +801,9 @@ void NetPlayClient::OnTraversalStateChanged()
// called from ---NETPLAY--- thread // called from ---NETPLAY--- thread
void NetPlayClient::OnConnectReady(ENetAddress addr) void NetPlayClient::OnConnectReady(ENetAddress addr)
{ {
if (m_state == WaitingForTraversalClientConnectReady) if (m_connection_state == ConnectionState::WaitingForTraversalClientConnectReady)
{ {
m_state = Connecting; m_connection_state = ConnectionState::Connecting;
enet_host_connect(m_client, &addr, 0, 0); enet_host_connect(m_client, &addr, 0, 0);
} }
} }
@ -798,7 +812,7 @@ void NetPlayClient::OnConnectReady(ENetAddress addr)
void NetPlayClient::OnConnectFailed(u8 reason) void NetPlayClient::OnConnectFailed(u8 reason)
{ {
m_connecting = false; m_connecting = false;
m_state = Failure; m_connection_state = ConnectionState::Failure;
switch (reason) switch (reason)
{ {
case TraversalConnectFailedClientDidntRespond: case TraversalConnectFailedClientDidntRespond:
@ -1010,28 +1024,20 @@ void NetPlayClient::Stop()
if (!m_is_running.load()) if (!m_is_running.load())
return; return;
bool isPadMapped = false; // Tell the server to stop if we have a pad mapped in game.
for (PadMapping mapping : m_pad_map) if (LocalPlayerHasControllerMapped())
{ SendStopGamePacket();
if (mapping == m_local_player->pid) }
{
isPadMapped = true; // called from ---GUI--- thread
} bool NetPlayClient::LocalPlayerHasControllerMapped() const
} {
for (PadMapping mapping : m_wiimote_map) const auto mapping_matches_player_id = [this](const PadMapping& mapping) {
{ return mapping == m_local_player->pid;
if (mapping == m_local_player->pid) };
{
isPadMapped = true; return std::any_of(m_pad_map.begin(), m_pad_map.end(), mapping_matches_player_id) ||
} std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id);
}
// tell the server to stop if we have a pad mapped in game.
if (isPadMapped)
{
sf::Packet* spac = new sf::Packet;
*spac << (MessageId)NP_MSG_STOP_GAME;
SendAsync(spac);
}
} }
u8 NetPlayClient::InGamePadToLocalPad(u8 ingame_pad) u8 NetPlayClient::InGamePadToLocalPad(u8 ingame_pad)
@ -1096,12 +1102,13 @@ void NetPlayClient::SendTimeBase()
u64 timebase = SystemTimers::GetFakeTimeBase(); u64 timebase = SystemTimers::GetFakeTimeBase();
sf::Packet* spac = new sf::Packet; auto spac = std::make_unique<sf::Packet>();
*spac << (MessageId)NP_MSG_TIMEBASE; *spac << static_cast<MessageId>(NP_MSG_TIMEBASE);
*spac << (u32)timebase; *spac << static_cast<u32>(timebase);
*spac << (u32)(timebase << 32); *spac << static_cast<u32>(timebase << 32);
*spac << netplay_client->m_timebase_frame++; *spac << netplay_client->m_timebase_frame++;
netplay_client->SendAsync(spac);
netplay_client->SendAsync(std::move(spac));
} }
// stuff hacked into dolphin // stuff hacked into dolphin

View File

@ -4,12 +4,14 @@
#pragma once #pragma once
#include <array>
#include <atomic> #include <atomic>
#include <map> #include <map>
#include <memory>
#include <mutex> #include <mutex>
#include <queue> #include <string>
#include <sstream>
#include <thread> #include <thread>
#include <vector>
#include <SFML/Network/Packet.hpp> #include <SFML/Network/Packet.hpp>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/FifoQueue.h" #include "Common/FifoQueue.h"
@ -48,7 +50,7 @@ class NetPlayClient : public TraversalClientClient
{ {
public: public:
void ThreadFunc(); void ThreadFunc();
void SendAsync(sf::Packet* packet); void SendAsync(std::unique_ptr<sf::Packet> packet);
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal, const std::string& centralServer, u16 centralPort); NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal, const std::string& centralServer, u16 centralPort);
~NetPlayClient(); ~NetPlayClient();
@ -56,7 +58,8 @@ public:
void GetPlayerList(std::string& list, std::vector<int>& pid_list); void GetPlayerList(std::string& list, std::vector<int>& pid_list);
std::vector<const Player*> GetPlayers(); std::vector<const Player*> GetPlayers();
bool is_connected; // Called from the GUI thread.
bool IsConnected() const { return m_is_connected; }
bool StartGame(const std::string &path); bool StartGame(const std::string &path);
bool StopGame(); bool StopGame();
@ -79,16 +82,6 @@ public:
static void SendTimeBase(); static void SendTimeBase();
enum State
{
WaitingForTraversalClientConnection,
WaitingForTraversalClientConnectReady,
Connecting,
WaitingForHelloResponse,
Connected,
Failure
} m_state;
protected: protected:
void ClearBuffers(); void ClearBuffers();
@ -102,31 +95,46 @@ protected:
Common::FifoQueue<std::unique_ptr<sf::Packet>, false> m_async_queue; Common::FifoQueue<std::unique_ptr<sf::Packet>, false> m_async_queue;
Common::FifoQueue<GCPadStatus> m_pad_buffer[4]; std::array<Common::FifoQueue<GCPadStatus>, 4> m_pad_buffer;
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4]; std::array<Common::FifoQueue<NetWiimote >, 4> m_wiimote_buffer;
NetPlayUI* m_dialog; NetPlayUI* m_dialog = nullptr;
ENetHost* m_client; ENetHost* m_client = nullptr;
ENetPeer* m_server; ENetPeer* m_server = nullptr;
std::thread m_thread; std::thread m_thread;
std::string m_selected_game; std::string m_selected_game;
std::atomic<bool> m_is_running; std::atomic<bool> m_is_running{false};
std::atomic<bool> m_do_loop; std::atomic<bool> m_do_loop{true};
unsigned int m_target_buffer_size; unsigned int m_target_buffer_size = 20;
Player* m_local_player; Player* m_local_player = nullptr;
u32 m_current_game; u32 m_current_game = 0;
PadMappingArray m_pad_map; PadMappingArray m_pad_map;
PadMappingArray m_wiimote_map; PadMappingArray m_wiimote_map;
bool m_is_recording; bool m_is_recording = false;
private: private:
enum class ConnectionState
{
WaitingForTraversalClientConnection,
WaitingForTraversalClientConnectReady,
Connecting,
WaitingForHelloResponse,
Connected,
Failure
};
bool LocalPlayerHasControllerMapped() const;
void SendStartGamePacket();
void SendStopGamePacket();
void UpdateDevices(); void UpdateDevices();
void SendPadState(const PadMapping in_game_pad, const GCPadStatus& np); void SendPadState(const PadMapping in_game_pad, const GCPadStatus& np);
void SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw); void SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw);
@ -135,14 +143,17 @@ private:
void Disconnect(); void Disconnect();
bool Connect(); bool Connect();
PlayerId m_pid; bool m_is_connected = false;
ConnectionState m_connection_state = ConnectionState::Failure;
PlayerId m_pid = 0;
std::map<PlayerId, Player> m_players; std::map<PlayerId, Player> m_players;
std::string m_host_spec; std::string m_host_spec;
std::string m_player_name; std::string m_player_name;
bool m_connecting; bool m_connecting = false;
TraversalClient* m_traversal_client; TraversalClient* m_traversal_client = nullptr;
u32 m_timebase_frame; u32 m_timebase_frame = 0;
}; };
void NetPlay_Enable(NetPlayClient* const np); void NetPlay_Enable(NetPlayClient* const np);

View File

@ -291,7 +291,7 @@ void NetPlaySetupFrame::MakeNetPlayDiag(int port, const std::string &game, bool
GetTraversalServer(netplay_section, &centralServer); GetTraversalServer(netplay_section, &centralServer);
netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()), trav, centralServer, (u16) centralPort); netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()), trav, centralServer, (u16) centralPort);
if (netplay_client->is_connected) if (netplay_client->IsConnected())
{ {
npd->Show(); npd->Show();
Destroy(); Destroy();