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 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-11-02 18:42:29 +01:00
1 parent 91965a3d1d
commit c4c8ddc6a1
3 files changed
+10 -8

No files matched your search

+1
View File
@@ -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
+8 -7
View File
@@ -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;
}