Simplify and improve.

Note - I removed a SleepCurrentThread(1) the patch added which seemed to
be unrelated to the actual job at hand.  If there was a real need for it
(which sounds like it would be an enet-related bug - enet_host_service
is supposed to *sleep*), that needs to be dealt with...
This commit is contained in:
comex 2015-06-05 19:00:26 -04:00
parent 04ca54623c
commit f2631a835e
5 changed files with 46 additions and 42 deletions

View File

@ -118,8 +118,6 @@ 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

View File

@ -165,7 +165,7 @@ void FrameUpdate()
s_bPolled = false; s_bPolled = false;
if (NetPlay::IsNetPlayRunning() && SConfig::GetInstance().m_NetplayDesyncCheck) if (NetPlay::IsNetPlayRunning())
NetPlayClient::SendTimeBase(); NetPlayClient::SendTimeBase();
} }

View File

@ -374,7 +374,6 @@ 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;
@ -445,19 +444,21 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
case NP_MSG_DESYNC_DETECTED: case NP_MSG_DESYNC_DETECTED:
{ {
if (!SConfig::GetInstance().m_NetplayDesyncCheck) int pid_to_blame;
break;
int id;
u32 frame; u32 frame;
packet >> id; packet >> pid_to_blame;
packet >> frame; packet >> frame;
std::string sID = ""; const char* blame_str = "";
if (id != -1) const char* blame_name = "";
sID = StringFromFormat(" from player ID %d", id); std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
if (pid_to_blame != -1)
{
auto it = m_players.find(pid_to_blame);
blame_str = " from player ";
blame_name = it != m_players.end() ? it->second.name.c_str() : "??";
}
m_dialog->AppendChat("Possible desync detected" + sID + StringFromFormat(" on frame: %u", frame)); m_dialog->AppendChat(StringFromFormat("/!\\ Possible desync detected%s%s on frame %u", blame_str, blame_name, frame));
SConfig::GetInstance().m_NetplayDesyncCheck = false;
} }
break; break;

View File

@ -23,8 +23,6 @@
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)
@ -112,7 +110,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();
@ -209,7 +207,6 @@ void NetPlayServer::ThreadFunc()
break; break;
} }
} }
Common::SleepCurrentThread(1);
} }
// close listening socket and client sockets // close listening socket and client sockets
@ -589,41 +586,44 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
packet >> x; packet >> x;
packet >> y; packet >> y;
packet >> frame; 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; })) if (m_desync_detected)
break;
u64 timebase = x | ((u64)y << 32);
std::vector<std::pair<PlayerId, u64>>& timebases = m_timebase_by_frame[frame];
timebases.emplace_back(player.pid, timebase);
if (timebases.size() >= m_players.size())
{ {
sf::Packet spac; // we have all records for this frame
spac << (MessageId) NP_MSG_DESYNC_DETECTED;
int pid = -1; if (!std::all_of(timebases.begin(), timebases.end(), [&](std::pair<PlayerId, u64> pair){ return pair.second == timebases[0].second; }))
if (s_timebase[frame].size() > 2)
{ {
for (auto time : s_timebase[frame]) int pid_to_blame = -1;
if (timebases.size() > 2)
{ {
int count = 0; for (auto pair : timebases)
for (auto _time : s_timebase[frame])
{ {
if (_time.first == time.first) if (std::all_of(timebases.begin(), timebases.end(), [&](std::pair<PlayerId, u64> other) {
count++; return other.first == pair.first || other.second != pair.second;
} }))
if ((size_t)count != s_timebase[frame].size() - 1)
{
if (pid == -1)
{ {
pid = time.second; // we are the only outlier
} pid_to_blame = pair.first;
else
{
pid = -1;
break; break;
} }
} }
} }
sf::Packet spac;
spac << (MessageId) NP_MSG_DESYNC_DETECTED;
spac << pid_to_blame;
spac << frame;
SendToClients(spac);
m_desync_detected = true;
} }
spac << pid; m_timebase_by_frame.erase(frame);
spac << frame;
SendToClients(spac);
} }
} }
break; break;
@ -681,7 +681,8 @@ void NetPlayServer::SetNetSettings(const NetSettings &settings)
// called from ---GUI--- thread // called from ---GUI--- thread
bool NetPlayServer::StartGame() bool NetPlayServer::StartGame()
{ {
s_timebase.clear(); m_timebase_by_frame.clear();
m_desync_detected = false;
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();

View File

@ -9,6 +9,7 @@
#include <queue> #include <queue>
#include <sstream> #include <sstream>
#include <thread> #include <thread>
#include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <SFML/Network/Packet.hpp> #include <SFML/Network/Packet.hpp>
#include "Common/Timer.h" #include "Common/Timer.h"
@ -99,6 +100,9 @@ private:
std::map<PlayerId, Client> m_players; std::map<PlayerId, Client> m_players;
std::unordered_map<u32, std::vector<std::pair<PlayerId, u64>>> m_timebase_by_frame;
bool m_desync_detected;
struct struct
{ {
std::recursive_mutex game; std::recursive_mutex game;