From c4c8ddc6a10888826bcbe05ee46bbbb25cef3274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 2 Nov 2026 18:42:20 +0100 Subject: [PATCH] Ad hoc: GameModeUpdateReplica gives the last timestamp when there's no new data A PSP never writes the info struct's length, and on a call without new data writes updated = 0 and the last data's timestamp again, 0 before any came (pspautotests net/adhoc/pair/gamemodeinfo). PPSSPP wrote the length and left the timestamp alone without new data. Shaun White Snowboarding reads the timestamp either way, from a struct on its stack, and keeps the newest it has seen as the time of the last update; stack garbage got in there, and the host gave up on the game a moment after the match started ("The game is no longer available"). Co-Authored-By: Claude Opus 5.5 --- Core/HLE/proAdhoc.h | 1 + Core/HLE/sceNetAdhoc.cpp | 15 ++++++++------- pspautotests | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index c54c8b0a8b..26f574ef1b 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -281,6 +281,7 @@ typedef struct GameModeArea { int dataSent; SceNetEtherAddr mac; u8* data; // upto "size" bytes started from "addr" ? + u64 reportedTimestamp; // what UpdateReplica last gave out as the data's time } PACK GameModeArea; // Socket Polling Event Listener diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 07122b1165..4ec5b5bc43 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -4799,21 +4799,22 @@ static int sceNetAdhocGameModeUpdateReplica(MIPSState *mips, int id, u32 infoAdd gmuinfo = (GameModeUpdateInfo*)Memory::GetPointerOrException(infoAddr); } + // A PSP leaves the length alone, and with no new data gives the last data's timestamp again, or 0 + // before any came (pspautotests net/adhoc/pair/gamemodeinfo). Shaun White Snowboarding reads the + // timestamp either way, and took the stack garbage left there for the time of the last update. for (auto& gma : replicaGameModeAreas) { if (gma.id == id) { if (gma.data && gma.dataUpdated) { Memory::Memcpy(gma.addr, gma.data, gma.size); gma.dataUpdated = 0; + gma.reportedTimestamp = std::min(CoreTiming::GetGlobalTimeUsScaled(), std::max(gma.updateTimestamp, CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta)); if (gmuinfo != NULL) { - gmuinfo->length = sizeof(GameModeUpdateInfo); gmuinfo->updated = 1; - gmuinfo->timeStamp = std::max(gma.updateTimestamp, CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta); - } - } - else { - if (gmuinfo != NULL) { - gmuinfo->updated = 0; + gmuinfo->timeStamp = gma.reportedTimestamp; } + } else if (gmuinfo != NULL) { + gmuinfo->updated = 0; + gmuinfo->timeStamp = gma.reportedTimestamp; } break; } diff --git a/pspautotests b/pspautotests index 910f98bdde..8301390a1e 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 910f98bdde1437f957ead87f7af1a73490abb808 +Subproject commit 8301390a1e42755ffa5c6d5e0a4f1f8248ea48c1