Compare timebase of netplay users to detect desyncs.
This commit is contained in:
parent
3d9fdf57e8
commit
04ca54623c
|
@ -118,6 +118,8 @@ struct SConfig : NonCopyable
|
||||||
bool m_GameCubeAdapter;
|
bool m_GameCubeAdapter;
|
||||||
bool m_AdapterRumble;
|
bool m_AdapterRumble;
|
||||||
|
|
||||||
|
bool m_NetplayDesyncCheck;
|
||||||
|
|
||||||
SysConf* m_SYSCONF;
|
SysConf* m_SYSCONF;
|
||||||
|
|
||||||
// Save settings
|
// Save settings
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
#include "Core/Movie.h"
|
#include "Core/Movie.h"
|
||||||
|
#include "Core/NetPlayClient.h"
|
||||||
#include "Core/NetPlayProto.h"
|
#include "Core/NetPlayProto.h"
|
||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
|
@ -163,6 +164,9 @@ void FrameUpdate()
|
||||||
FrameSkipping();
|
FrameSkipping();
|
||||||
|
|
||||||
s_bPolled = false;
|
s_bPolled = false;
|
||||||
|
|
||||||
|
if (NetPlay::IsNetPlayRunning() && SConfig::GetInstance().m_NetplayDesyncCheck)
|
||||||
|
NetPlayClient::SendTimeBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
// called when game is booting up, even if no movie is active,
|
// called when game is booting up, even if no movie is active,
|
||||||
|
|
|
@ -374,6 +374,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||||
case NP_MSG_START_GAME:
|
case NP_MSG_START_GAME:
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
SConfig::GetInstance().m_NetplayDesyncCheck = true;
|
||||||
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
|
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
|
||||||
packet >> m_current_game;
|
packet >> m_current_game;
|
||||||
packet >> g_NetPlaySettings.m_CPUthread;
|
packet >> g_NetPlaySettings.m_CPUthread;
|
||||||
|
@ -442,6 +443,24 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NP_MSG_DESYNC_DETECTED:
|
||||||
|
{
|
||||||
|
if (!SConfig::GetInstance().m_NetplayDesyncCheck)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int id;
|
||||||
|
u32 frame;
|
||||||
|
packet >> id;
|
||||||
|
packet >> frame;
|
||||||
|
std::string sID = "";
|
||||||
|
if (id != -1)
|
||||||
|
sID = StringFromFormat(" from player ID %d", id);
|
||||||
|
|
||||||
|
m_dialog->AppendChat("Possible desync detected" + sID + StringFromFormat(" on frame: %u", frame));
|
||||||
|
SConfig::GetInstance().m_NetplayDesyncCheck = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlertT("Unknown message received with id : %d", mid);
|
PanicAlertT("Unknown message received with id : %d", mid);
|
||||||
break;
|
break;
|
||||||
|
@ -1044,6 +1063,20 @@ u8 NetPlayClient::LocalWiimoteToInGameWiimote(u8 local_pad)
|
||||||
return ingame_pad;
|
return ingame_pad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetPlayClient::SendTimeBase()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(crit_netplay_client);
|
||||||
|
|
||||||
|
u64 timebase = SystemTimers::GetFakeTimeBase();
|
||||||
|
|
||||||
|
sf::Packet* spac = new sf::Packet;
|
||||||
|
*spac << (MessageId)NP_MSG_TIMEBASE;
|
||||||
|
*spac << (u32)timebase;
|
||||||
|
*spac << (u32)(timebase << 32);
|
||||||
|
*spac << (u32)Movie::g_currentFrame;
|
||||||
|
netplay_client->SendAsync(spac);
|
||||||
|
}
|
||||||
|
|
||||||
// stuff hacked into dolphin
|
// stuff hacked into dolphin
|
||||||
|
|
||||||
// called from ---CPU--- thread
|
// called from ---CPU--- thread
|
||||||
|
|
|
@ -77,6 +77,8 @@ public:
|
||||||
|
|
||||||
u8 LocalWiimoteToInGameWiimote(u8 local_pad);
|
u8 LocalWiimoteToInGameWiimote(u8 local_pad);
|
||||||
|
|
||||||
|
static void SendTimeBase();
|
||||||
|
|
||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
WaitingForTraversalClientConnection,
|
WaitingForTraversalClientConnection,
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct Rpt : public std::vector<u8>
|
||||||
|
|
||||||
typedef std::vector<u8> NetWiimote;
|
typedef std::vector<u8> NetWiimote;
|
||||||
|
|
||||||
#define NETPLAY_VERSION "Dolphin NetPlay 2014-01-08"
|
#define NETPLAY_VERSION "Dolphin NetPlay 2015-03-10"
|
||||||
|
|
||||||
extern u64 g_netplay_initial_gctime;
|
extern u64 g_netplay_initial_gctime;
|
||||||
|
|
||||||
|
@ -53,6 +53,9 @@ enum
|
||||||
NP_MSG_STOP_GAME = 0xA2,
|
NP_MSG_STOP_GAME = 0xA2,
|
||||||
NP_MSG_DISABLE_GAME = 0xA3,
|
NP_MSG_DISABLE_GAME = 0xA3,
|
||||||
|
|
||||||
|
NP_MSG_TIMEBASE = 0xB0,
|
||||||
|
NP_MSG_DESYNC_DETECTED = 0xB1,
|
||||||
|
|
||||||
NP_MSG_READY = 0xD0,
|
NP_MSG_READY = 0xD0,
|
||||||
NP_MSG_NOT_READY = 0xD1,
|
NP_MSG_NOT_READY = 0xD1,
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
u64 g_netplay_initial_gctime = 1272737767;
|
u64 g_netplay_initial_gctime = 1272737767;
|
||||||
|
|
||||||
|
static std::map<u32, std::vector<std::pair<u64, u8>>> s_timebase;
|
||||||
|
|
||||||
NetPlayServer::~NetPlayServer()
|
NetPlayServer::~NetPlayServer()
|
||||||
{
|
{
|
||||||
if (is_connected)
|
if (is_connected)
|
||||||
|
@ -110,8 +112,7 @@ void NetPlayServer::ThreadFunc()
|
||||||
while (m_do_loop)
|
while (m_do_loop)
|
||||||
{
|
{
|
||||||
// update pings every so many seconds
|
// update pings every so many seconds
|
||||||
|
if (m_update_pings || (m_ping_timer.GetTimeElapsed() > 1000))
|
||||||
if ((m_ping_timer.GetTimeElapsed() > 1000) || m_update_pings)
|
|
||||||
{
|
{
|
||||||
m_ping_key = Common::Timer::GetTimeMs();
|
m_ping_key = Common::Timer::GetTimeMs();
|
||||||
|
|
||||||
|
@ -208,6 +209,7 @@ void NetPlayServer::ThreadFunc()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Common::SleepCurrentThread(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// close listening socket and client sockets
|
// close listening socket and client sockets
|
||||||
|
@ -581,6 +583,50 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NP_MSG_TIMEBASE:
|
||||||
|
{
|
||||||
|
u32 x, y, frame;
|
||||||
|
packet >> x;
|
||||||
|
packet >> y;
|
||||||
|
packet >> frame;
|
||||||
|
s_timebase[frame].emplace_back(x | ((u64)y >> 32), player.pid);
|
||||||
|
|
||||||
|
if (!std::all_of(s_timebase[frame].begin(), s_timebase[frame].end(), [&frame](std::pair<u64, u8> i){ return i.first == s_timebase[frame][0].first; }))
|
||||||
|
{
|
||||||
|
sf::Packet spac;
|
||||||
|
spac << (MessageId) NP_MSG_DESYNC_DETECTED;
|
||||||
|
|
||||||
|
int pid = -1;
|
||||||
|
if (s_timebase[frame].size() > 2)
|
||||||
|
{
|
||||||
|
for (auto time : s_timebase[frame])
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (auto _time : s_timebase[frame])
|
||||||
|
{
|
||||||
|
if (_time.first == time.first)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if ((size_t)count != s_timebase[frame].size() - 1)
|
||||||
|
{
|
||||||
|
if (pid == -1)
|
||||||
|
{
|
||||||
|
pid = time.second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pid = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spac << pid;
|
||||||
|
spac << frame;
|
||||||
|
SendToClients(spac);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PanicAlertT("Unknown message with id:%d received from player:%d Kicking player!", mid, player.pid);
|
PanicAlertT("Unknown message with id:%d received from player:%d Kicking player!", mid, player.pid);
|
||||||
// unknown message, kick the client
|
// unknown message, kick the client
|
||||||
|
@ -635,6 +681,7 @@ void NetPlayServer::SetNetSettings(const NetSettings &settings)
|
||||||
// called from ---GUI--- thread
|
// called from ---GUI--- thread
|
||||||
bool NetPlayServer::StartGame()
|
bool NetPlayServer::StartGame()
|
||||||
{
|
{
|
||||||
|
s_timebase.clear();
|
||||||
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
|
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
|
||||||
m_current_game = Common::Timer::GetTimeMs();
|
m_current_game = Common::Timer::GetTimeMs();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue