From d628eb2ebdb94859f2e6fd773ee48e4f9e818547 Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Thu, 8 Oct 2020 00:52:30 +0700 Subject: [PATCH] Fix Falcom games (ie. Ys vs. Sora no Kiseki, Vantage Master Portable) --- Core/HLE/proAdhoc.cpp | 2 +- Core/HLE/proAdhoc.h | 12 ++++++---- Core/HLE/sceNet.cpp | 13 ++++++----- Core/HLE/sceNetAdhoc.cpp | 49 ++++++++++++++++++++++++---------------- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 3c8e6f00b9..4f952f6432 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -1985,7 +1985,7 @@ int getNicknameCount(const char * nickname) for (; peer != NULL; peer = peer->next) { // Match found - if (strncmp((char *)&peer->nickname.data, nickname, ADHOCCTL_NICKNAME_LEN) == 0) count++; + if (peer->last_recv != 0 && strncmp((char *)&peer->nickname.data, nickname, ADHOCCTL_NICKNAME_LEN) == 0) count++; } // Return Result diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 327054711a..550bb4b694 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -207,9 +207,9 @@ extern uint8_t broadcastMAC[ETHER_ADDR_LEN]; // Malloc Pool Information typedef struct SceNetMallocStat { - s32_le pool; // Pointer to the pool? // This should be the poolSize isn't? - s32_le maximum; // Maximum size of the pool? Maximum usage (ie. pool- free) ? - s32_le free; // How much memory is free + s32_le pool; // On Vantage Master Portable this is 0x1ffe0 on sceNetGetMallocStat, while the poolSize arg on sceNetInit was 0x20000 + s32_le maximum; // On Vantage Master Portable this is 0x4050, Footprint of Highest amount allocated so far? + s32_le free; // On Vantage Master Portable this is 0x1f300, VMP compares this value with required size before sending data } PACK SceNetMallocStat; // Adhoc Virtual Network Name @@ -352,10 +352,14 @@ typedef struct AdhocSocket { s32_le type; // SOCK_PDP/SOCK_PTP s32_le flags; // Socket Alert Flags s32_le alerted_flags; // Socket Alerted Flags + s32_le nonblocking; // last non-blocking flag + u32 buffer_size; u32 send_timeout; // default connect timeout u32 recv_timeout; // default accept timeout - s32 retry_count; // combined with timeout to be used on keepalive + s32 retry_interval; // related to keepalive + s32 retry_count; // multiply with retry interval to be used as keepalive timeout s32 attemptCount; // connect/accept attempts + u64 lastAttempt; // timestamp to retry again union { SceNetAdhocPdpStat pdp; SceNetAdhocPtpStat ptp; diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 757221f1db..2de660cc5e 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -641,14 +641,15 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini } WARN_LOG(SCENET, "sceNetInit(poolsize=%d, calloutpri=%i, calloutstack=%d, netintrpri=%i, netintrstack=%d) at %08x", poolSize, calloutPri, calloutStack, netinitPri, netinitStack, currentMIPS->pc); - netInited = true; - netMallocStat.pool = poolSize; // This should be the poolSize isn't? - netMallocStat.maximum = poolSize/2; // According to JPCSP's sceNetGetMallocStat this is Currently Used size = (poolSize - free), faked to half the pool - netMallocStat.free = poolSize - netMallocStat.maximum; + + netMallocStat.pool = poolSize - 0x20; // On Vantage Master Portable this is slightly (32 bytes) smaller than the poolSize arg when tested with JPCSP + prx files + netMallocStat.maximum = 0x4050; // Dummy maximum foot print + netMallocStat.free = netMallocStat.pool; // Dummy free size, we should set this high enough to prevent any issue (ie. Vantage Master Portable), this is probably the only field being checked by games? // Clear Socket Translator Memory memset(&adhocSockets, 0, sizeof(adhocSockets)); - + + netInited = true; return hleLogSuccessI(SCENET, 0); } @@ -770,7 +771,7 @@ static void sceNetEtherStrton(u32 bufferPtr, u32 macPtr) { // Write static data since we don't actually manage any memory for sceNet* yet. static int sceNetGetMallocStat(u32 statPtr) { - VERBOSE_LOG(SCENET, "UNTESTED sceNetGetMallocStat(%x)", statPtr); + VERBOSE_LOG(SCENET, "UNTESTED sceNetGetMallocStat(%x) at %08x", statPtr, currentMIPS->pc); if(Memory::IsValidAddress(statPtr)) Memory::WriteStruct(statPtr, &netMallocStat); else diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index fe84d3aa1c..06a1ad6496 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -75,6 +75,7 @@ int adhocExtraDelay = 20000; //20000 int adhocEventPollDelay = 100000; //100000; // Same timings with PSP_ADHOCCTL_RECV_TIMEOUT ? int adhocMatchingEventDelay = 30000; //30000 int adhocEventDelay = 1000000; //1000000 +u32 defaultLastRecvDelta = 10000; //10000 usec worked well for games published by Falcom (ie. Ys vs Sora Kiseki, Vantage Master Portable) SceUID threadAdhocID; @@ -2270,7 +2271,7 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { for (; peer != NULL; peer = peer->next) { // Match found - if (isMacMatch(&peer->mac_addr, (const SceNetEtherAddr*)mac)) + if (peer->last_recv != 0 && isMacMatch(&peer->mac_addr, (const SceNetEtherAddr*)mac)) { // Write Data *nickname = peer->nickname; @@ -2316,7 +2317,7 @@ int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { if (netAdhocctlInited) { if ((size < (int)sizeof(SceNetAdhocctlPeerInfoEmu)) || (buf == NULL)) return ERROR_NET_ADHOCCTL_INVALID_ARG; - int retval = ERROR_NET_ADHOCCTL_INVALID_ARG; // -1; + int retval = ERROR_NET_ADHOC_NO_ENTRY; // -1; // Local MAC if (isLocalMAC(maddr)) { @@ -2329,7 +2330,7 @@ int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { buf->mac_addr = *maddr; buf->flags = 0x0400; buf->padding = 0; - buf->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; + buf->last_recv = CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta; // Success retval = 0; @@ -2341,12 +2342,11 @@ int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { peerlock.lock(); SceNetAdhocctlPeerInfo * peer = findFriend(maddr); - if (peer != NULL) { + if (peer != NULL && peer->last_recv != 0) { // Fake Receive Time - if (peer->last_recv != 0) - peer->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; + peer->last_recv = std::max(peer->last_recv, CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta); - //buf->next = 0; + buf->next = 0; buf->nickname = peer->nickname; buf->nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; // last char need to be null-terminated char buf->mac_addr = *maddr; @@ -5386,7 +5386,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { if (!excludeTimedout || peer->last_recv != 0) { // Faking Last Receive Time if (peer->last_recv != 0) - peer->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; + peer->last_recv = std::max(peer->last_recv, CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta); // Copy Peer Info buf[discovered].nickname = peer->nickname; @@ -5418,7 +5418,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { peerlock.unlock(); // Return Success - return 0; + return hleDelayResult(0, "delay 1 ~ 10ms", 1000); // seems to have different thread running within the delay duration } // Invalid Arguments @@ -5437,7 +5437,7 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b memcpy(nckName, nickName, ADHOCCTL_NICKNAME_LEN); // Copied to null-terminated var to prevent unexpected behaviour on Logs nckName[ADHOCCTL_NICKNAME_LEN - 1] = 0; - WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlGetAddrByName(%s, [%08x]=%d/%zu, %08x)", nckName, sizeAddr, buflen ? *buflen : -1, sizeof(SceNetAdhocctlPeerInfoEmu), bufAddr); + WARN_LOG_REPORT_ONCE(sceNetAdhocctlGetAddrByName, SCENET, "UNTESTED sceNetAdhocctlGetAddrByName(%s, [%08x]=%d/%zu, %08x) at %08x", nckName, sizeAddr, buflen ? *buflen : -1, sizeof(SceNetAdhocctlPeerInfoEmu), bufAddr, currentMIPS->pc); // Library initialized if (netAdhocctlInited) @@ -5452,8 +5452,11 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b peerlock.lock(); // Length Calculation Mode - if (buf == NULL) *buflen = getNicknameCount(nickName) * sizeof(SceNetAdhocctlPeerInfoEmu); - + if (buf == NULL) { + int foundName = getNicknameCount(nickName); + *buflen = foundName * sizeof(SceNetAdhocctlPeerInfoEmu); + DEBUG_LOG(SCENET, "PeerNameList [%s: %i]", nickName, foundName); + } // Normal Information Mode else { @@ -5474,13 +5477,18 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b { // Get Local IP Address sockaddr_in addr; + SceNetEtherAddr mac; getLocalIp(&addr); buf[discovered].nickname = parameter.nickname; buf[discovered].nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; // last char need to be null-terminated char - getLocalMac(&buf[discovered].mac_addr); + getLocalMac(&mac); + buf[discovered].mac_addr = mac; buf[discovered].flags = 0x0400; - buf[discovered++].last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; + u64 lastrecv = CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta; + buf[discovered++].last_recv = lastrecv; + + DEBUG_LOG(SCENET, "Peer [%s][%s][%s][%llu]", mac2str(&mac).c_str(), inet_ntoa(addr.sin_addr), nickName, lastrecv); } // Peer Reference @@ -5490,11 +5498,10 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b for (; peer != NULL && discovered < requestcount; peer = peer->next) { // Match found - if (strncmp((char *)&peer->nickname.data, nickName, ADHOCCTL_NICKNAME_LEN) == 0) + if (peer->last_recv != 0 && strncmp((char *)&peer->nickname.data, nickName, ADHOCCTL_NICKNAME_LEN) == 0) { // Fake Receive Time - if (peer->last_recv != 0) - peer->last_recv = CoreTiming::GetGlobalTimeUsScaled() - 1; + peer->last_recv = std::max(peer->last_recv, CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta); // Copy Peer Info buf[discovered].nickname = peer->nickname; @@ -5502,6 +5509,9 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b buf[discovered].mac_addr = peer->mac_addr; buf[discovered].flags = 0x0400; buf[discovered++].last_recv = peer->last_recv; + + u32_le ipaddr = peer->ip_addr; + DEBUG_LOG(SCENET, "Peer [%s][%s][%s][%llu]", mac2str(&peer->mac_addr).c_str(), inet_ntoa(*(in_addr*)&ipaddr), (const char*)&peer->nickname.data, peer->last_recv); } } @@ -5518,13 +5528,14 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b // Fix Buffer Size *buflen = discovered * sizeof(SceNetAdhocctlPeerInfoEmu); + DEBUG_LOG(SCENET, "PeerNameList [%s][Requested: %i][Discovered: %i]", nickName, requestcount, discovered); } // Multithreading Unlock peerlock.unlock(); // Return Success - return 0; + return hleLogDebug(SCENET, hleDelayResult(0, "delay 1 ~ 10ms", 1000), "success"); // FIXME: Might have similar delay with GetPeerList? need to know which games using this tho } // Invalid Arguments @@ -6867,7 +6878,7 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi now = CoreTiming::GetGlobalTimeUsScaled(); u64_le delta = now - peer->last_recv; DEBUG_LOG(SCENET, "Timestamp Delta: %llu (%llu - %llu) from %s", delta, now, peer->last_recv, mac2str(&sendermac).c_str()); - if (/*context->rxbuf[0] > 0 &&*/ peer->last_recv != 0) peer->last_recv = now - 1; // - context->keepalive_int; // May need to deduce by ping interval to prevent Dissidia 012 unable to see other players (ie. disappearing issue) + if (peer->last_recv != 0) peer->last_recv = now - defaultLastRecvDelta; } else { WARN_LOG(SCENET, "InputLoop[%d]: Unknown Peer[%s:%u] (Recved=%i, Length=%i)", matchingId, mac2str(&sendermac).c_str(), senderport, recvresult, rxbuflen);