diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 94b5fe205888..b2419a799096 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -1241,7 +1241,7 @@ void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * // Don't share buffer address space with other mipscall in the queue since mipscalls aren't immediately executed MatchingArgs argsNew = { 0 }; u32_le dataBufLen = msg->optlen + 8; //max(bufLen, msg->optlen + 8); - u32_le dataBufAddr = userMemory.Alloc(dataBufLen); // We will free this memory after returning from mipscall + u32_le dataBufAddr = userMemory.Alloc(dataBufLen); // We will free this memory after returning from mipscall. FIXME: Are these buffers supposed to be taken/pre-allocated from the memory pool during sceNetAdhocMatchingInit? uint8_t * dataPtr = Memory::GetPointer(dataBufAddr); if (dataPtr) { memcpy(dataPtr, &msg->mac, sizeof(msg->mac)); @@ -1255,6 +1255,7 @@ void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * } else { argsNew.data[1] = PSP_ADHOC_MATCHING_EVENT_ERROR; // not sure where to put the error code for EVENT_ERROR tho + //argsNew.data[2] = dataBufAddr; // FIXME: Is the MAC address mandatory (ie. can't be null pointer) even for EVENT_ERROR? Where should we put this MAC data in the case we failed to allocate the memory? may be on the memory pool? } argsNew.data[0] = context->id; argsNew.data[5] = context->handler.entryPoint; //not part of callback argument, just borrowing a space to store callback address so i don't need to search the context first later diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index e725950fa36a..f1e8e0dd06cf 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -732,7 +732,7 @@ enum { #define PSP_ADHOC_MATCHING_MODE_P2P 3 // Matching Events -#define PSP_ADHOC_MATCHING_EVENT_HELLO 1 +#define PSP_ADHOC_MATCHING_EVENT_HELLO 1 // Should be ignored when Join Request is in progress ? #define PSP_ADHOC_MATCHING_EVENT_REQUEST 2 #define PSP_ADHOC_MATCHING_EVENT_LEAVE 3 #define PSP_ADHOC_MATCHING_EVENT_DENY 4 diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 12bbe547525a..a97fda72df07 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -4674,7 +4674,7 @@ int sceNetAdhocMatchingDelete(int matchingId) { } int sceNetAdhocMatchingInit(u32 memsize) { - WARN_LOG(SCENET, "sceNetAdhocMatchingInit(%d) at %08x", memsize, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocMatchingInit, SCENET, "sceNetAdhocMatchingInit(%d) at %08x", memsize, currentMIPS->pc); // Uninitialized Library if (netAdhocMatchingInited) @@ -5746,23 +5746,34 @@ void __NetMatchingCallbacks() //(int matchingId) { std::lock_guard adhocGuard(adhocEvtMtx); hleSkipDeadbeef(); - int delayus = adhocDefaultDelay; + // Note: Super Pocket Tennis / Thrillville Off the Rails seems to have a very short timeout (ie. ~5ms) while waiting for the event to arrived on the callback handler, but Lord of Arcana may not work well with 5ms (~3m or ~10ms seems to be good) + // Games with 4-players or more (ie. Gundam: Senjou No Kizuna Portable) will also need lower delay/latency (ie. ~3ms seems to be good, 2ms or lower doesn't work well) so MatchingEvents can be processed faster, thus won't be piling up in the queue. + // Using 3ms seems to fix Player list issue on StarWars The Force Unleashed. + int delayus = 3000; auto params = matchingEvents.begin(); if (params != matchingEvents.end()) { u32_le *args = params->data; - //auto context = findMatchingContext(args[0]); + auto context = findMatchingContext(args[0]); if (actionAfterMatchingMipsCall < 0) { actionAfterMatchingMipsCall = __KernelRegisterActionType(AfterMatchingMipsCall::Create); } DEBUG_LOG(SCENET, "AdhocMatching - Remaining Events: %zu", matchingEvents.size()); - DEBUG_LOG(SCENET, "AdhocMatchingCallback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr *)Memory::GetPointer(args[2])).c_str()); - AfterMatchingMipsCall *after = (AfterMatchingMipsCall *)__KernelCreateAction(actionAfterMatchingMipsCall); - after->SetData(args[0], args[1], args[2]); - hleEnqueueCall(args[5], 5, args, after); - matchingEvents.pop_front(); - delayus = adhocMatchingEventDelay; // Add extra delay to prevent I/O Timing method from causing disconnection, but delaying too long may cause matchingEvents to pile up + auto peer = findPeer(context, (SceNetEtherAddr*)Memory::GetPointer(args[2])); + // Discard HELLO Events when in the middle of joining, as some games (ie. Super Pocket Tennis) might tried to join again (TODO: Need to confirm whether sceNetAdhocMatchingSelectTarget supposed to be blocking the current thread or not) + if (peer == NULL || (args[1] != PSP_ADHOC_MATCHING_EVENT_HELLO || (peer->state != PSP_ADHOC_MATCHING_PEER_OUTGOING_REQUEST && peer->state != PSP_ADHOC_MATCHING_PEER_INCOMING_REQUEST))) { + DEBUG_LOG(SCENET, "AdhocMatchingCallback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr *)Memory::GetPointer(args[2])).c_str()); + + AfterMatchingMipsCall* after = (AfterMatchingMipsCall*)__KernelCreateAction(actionAfterMatchingMipsCall); + after->SetData(args[0], args[1], args[2]); + hleEnqueueCall(args[5], 5, args, after); + matchingEvents.pop_front(); + } + else { + DEBUG_LOG(SCENET, "AdhocMatching - Discarding Callback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr*)Memory::GetPointer(args[2])).c_str()); + matchingEvents.pop_front(); + } } // Must be delayed long enough whenever there is a pending callback. Should it be 10-100ms for Matching Events? or Not Less than the delays on sceNetAdhocMatching HLE? diff --git a/Core/HLE/sceNetAdhoc.h b/Core/HLE/sceNetAdhoc.h index 9027012b850e..114e7cec726a 100644 --- a/Core/HLE/sceNetAdhoc.h +++ b/Core/HLE/sceNetAdhoc.h @@ -24,7 +24,7 @@ #pragma pack(push,1) #endif typedef struct MatchingArgs { - u32_le data[6]; //ContextID, Opcode, bufAddr[ to MAC], OptLen, OptAddr[, EntryPoint] + u32_le data[6]; // ContextID, EventID, bufAddr[ to MAC], OptLen, OptAddr[, EntryPoint] } PACK MatchingArgs; typedef struct SceNetAdhocDiscoverParam {