Netplay: First Attempt at creating a rolling checksum for desync detection
This commit is contained in:
parent
df4e21a170
commit
f89965b570
|
@ -13,6 +13,9 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <xxhash.h>
|
||||||
|
#include "host.h"
|
||||||
|
|
||||||
Log_SetChannel(Netplay);
|
Log_SetChannel(Netplay);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -57,6 +60,9 @@ static void InitializeFramePacing();
|
||||||
static void HandleTimeSyncEvent(float frame_delta, int update_interval);
|
static void HandleTimeSyncEvent(float frame_delta, int update_interval);
|
||||||
static void Throttle();
|
static void Throttle();
|
||||||
|
|
||||||
|
// Desync Detection
|
||||||
|
static void GenerateChecksumForFrame(int* checksum, int frame, unsigned char* buffer, int buffer_size);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Variables
|
// Variables
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -107,8 +113,8 @@ s32 Netplay::Start(s32 lhandle, u16 lport, std::string& raddr, u16 rport, s32 ld
|
||||||
ggpo_start_session(&s_ggpo, &cb, "Duckstation-Netplay", 2, sizeof(Netplay::Input), lport, MAX_ROLLBACK_FRAMES);
|
ggpo_start_session(&s_ggpo, &cb, "Duckstation-Netplay", 2, sizeof(Netplay::Input), lport, MAX_ROLLBACK_FRAMES);
|
||||||
// result = ggpo_start_synctest(&s_ggpo, &cb, (char*)"asdf", 2, sizeof(Netplay::Input), 1);
|
// result = ggpo_start_synctest(&s_ggpo, &cb, (char*)"asdf", 2, sizeof(Netplay::Input), 1);
|
||||||
|
|
||||||
ggpo_set_disconnect_timeout(s_ggpo, 3000);
|
ggpo_set_disconnect_timeout(s_ggpo, 10000);
|
||||||
ggpo_set_disconnect_notify_start(s_ggpo, 1000);
|
ggpo_set_disconnect_notify_start(s_ggpo, 2000);
|
||||||
|
|
||||||
for (int i = 1; i <= 2; i++)
|
for (int i = 1; i <= 2; i++)
|
||||||
{
|
{
|
||||||
|
@ -206,7 +212,7 @@ void Netplay::HandleTimeSyncEvent(float frame_delta, int update_interval)
|
||||||
// Distribute the frame difference over the next N * 0.75 frames.
|
// Distribute the frame difference over the next N * 0.75 frames.
|
||||||
// only part of the interval time is used since we want to come back to normal speed.
|
// only part of the interval time is used since we want to come back to normal speed.
|
||||||
// otherwise we will keep spiraling into unplayable gameplay.
|
// otherwise we will keep spiraling into unplayable gameplay.
|
||||||
float total_time = (frame_delta / 8) * s_frame_period;
|
float total_time = (frame_delta * s_frame_period) / 4;
|
||||||
float mun_timesync_frames = update_interval * 0.75f;
|
float mun_timesync_frames = update_interval * 0.75f;
|
||||||
float added_time_per_frame = -(total_time / mun_timesync_frames);
|
float added_time_per_frame = -(total_time / mun_timesync_frames);
|
||||||
float iterations_per_frame = 1.0f / s_frame_period;
|
float iterations_per_frame = 1.0f / s_frame_period;
|
||||||
|
@ -264,6 +270,15 @@ void Netplay::Throttle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Netplay::GenerateChecksumForFrame(int* checksum, int frame, unsigned char* buffer, int buffer_size)
|
||||||
|
{
|
||||||
|
u32 sliding_window_size = 4096;
|
||||||
|
u32 num_pages = buffer_size / sliding_window_size;
|
||||||
|
u32 start_position = (frame % num_pages) * sliding_window_size;
|
||||||
|
*checksum = XXH32(buffer + start_position, sliding_window_size, frame);
|
||||||
|
Log_VerbosePrintf("check: f:%d c:%u", frame, *checksum);
|
||||||
|
}
|
||||||
|
|
||||||
void Netplay::AdvanceFrame(u16 checksum)
|
void Netplay::AdvanceFrame(u16 checksum)
|
||||||
{
|
{
|
||||||
ggpo_advance_frame(s_ggpo, checksum);
|
ggpo_advance_frame(s_ggpo, checksum);
|
||||||
|
@ -314,7 +329,7 @@ Netplay::Input Netplay::ReadLocalInput()
|
||||||
Netplay::Input inp{0};
|
Netplay::Input inp{0};
|
||||||
for (u32 i = 0; i < (u32)DigitalController::Button::Count; i++)
|
for (u32 i = 0; i < (u32)DigitalController::Button::Count; i++)
|
||||||
{
|
{
|
||||||
if (s_net_input[0][i] >= 0.25f)
|
if (s_net_input[0][i] >= 0.4f)
|
||||||
inp.button_data |= 1 << i;
|
inp.button_data |= 1 << i;
|
||||||
}
|
}
|
||||||
return inp;
|
return inp;
|
||||||
|
@ -425,6 +440,7 @@ bool Netplay::NpBeginGameCb(void* ctx, const char* game_name)
|
||||||
while (System::GetInternalFrameNumber() < 2)
|
while (System::GetInternalFrameNumber() < 2)
|
||||||
System::RunFrame();
|
System::RunFrame();
|
||||||
SPU::SetAudioOutputMuted(false);
|
SPU::SetAudioOutputMuted(false);
|
||||||
|
// Set Initial Frame Pacing
|
||||||
InitializeFramePacing();
|
InitializeFramePacing();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -457,8 +473,13 @@ bool Netplay::NpSaveFrameCb(void* ctx, unsigned char** buffer, int* len, int* ch
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Netplay::GenerateChecksumForFrame(checksum, frame,
|
||||||
|
reinterpret_cast<unsigned char*>(our_buffer.get()->state_stream.get()->GetMemoryPointer()),
|
||||||
|
our_buffer.get()->state_stream.get()->GetMemorySize());
|
||||||
|
|
||||||
*len = sizeof(System::MemorySaveState);
|
*len = sizeof(System::MemorySaveState);
|
||||||
*buffer = reinterpret_cast<unsigned char*>(our_buffer.release());
|
*buffer = reinterpret_cast<unsigned char*>(our_buffer.release());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,6 +542,7 @@ bool Netplay::NpOnEventCb(void* ctx, GGPOEvent* ev)
|
||||||
sprintf(buff, "Netplay Desync Detected!: Frame: %d, L:%u, R:%u", ev->u.desync.nFrameOfDesync,
|
sprintf(buff, "Netplay Desync Detected!: Frame: %d, L:%u, R:%u", ev->u.desync.nFrameOfDesync,
|
||||||
ev->u.desync.ourCheckSum, ev->u.desync.remoteChecksum);
|
ev->u.desync.ourCheckSum, ev->u.desync.remoteChecksum);
|
||||||
msg = buff;
|
msg = buff;
|
||||||
|
Host::AddKeyedOSDMessage("Netplay", msg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(buff, "Netplay Event Code: %d", ev->code);
|
sprintf(buff, "Netplay Event Code: %d", ev->code);
|
||||||
|
|
Loading…
Reference in New Issue