diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19a2ab8893..3d30e7e0b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2252,6 +2252,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceNet.h
Core/HLE/sceNet_lib.cpp
Core/HLE/sceNet_lib.h
+ Core/HLE/NetAdhocCommon.cpp
+ Core/HLE/NetAdhocCommon.h
Core/HLE/sceNetAdhoc.cpp
Core/HLE/sceNetAdhoc.h
Core/HLE/sceNetAdhocMatching.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 95afc14886..4623e05f56 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -627,6 +627,7 @@
+
@@ -1140,6 +1141,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index e9d8adab35..f37280cbaa 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -520,6 +520,9 @@
HLE\Libraries
+
+ HLE\Libraries
+
HLE\Libraries
@@ -1758,6 +1761,9 @@
HLE\Libraries
+
+ HLE\Libraries
+
HLE\Libraries
diff --git a/Core/HLE/NetAdhocCommon.cpp b/Core/HLE/NetAdhocCommon.cpp
new file mode 100644
index 0000000000..242735a3c6
--- /dev/null
+++ b/Core/HLE/NetAdhocCommon.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 2025- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "Core/HLE/NetAdhocCommon.h"
+
+#include "sceKernelMemory.h"
+#include "Core/MemMapHelpers.h"
+
+u32 dummyThreadHackAddr = 0;
+u32_le dummyThreadCode[3];
+
+
+void netAdhocValidateLoopMemory() {
+ // Allocate Memory if it wasn't valid/allocated after loaded from old SaveState
+ if (!dummyThreadHackAddr || strcmp("dummythreadhack", kernelMemory.GetBlockTag(dummyThreadHackAddr)) != 0) {
+ u32 blockSize = sizeof(dummyThreadCode);
+ dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, "dummythreadhack");
+ if (dummyThreadHackAddr)
+ Memory::Memcpy(dummyThreadHackAddr, dummyThreadCode, sizeof(dummyThreadCode));
+ }
+}
+
+int netAdhocEnterGameModeTimeout = 15000000; // 15 sec as default timeout, to wait for all players to join
+
+std::recursive_mutex adhocEvtMtx;
+
+int IsAdhocctlInCB = 0;
+
+
+u32 matchingThreadHackAddr = 0;
+u32_le matchingThreadCode[3];
+
+bool g_adhocServerConnected = false;
diff --git a/Core/HLE/NetAdhocCommon.h b/Core/HLE/NetAdhocCommon.h
new file mode 100644
index 0000000000..1e0b532b06
--- /dev/null
+++ b/Core/HLE/NetAdhocCommon.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2025- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "CommonTypes.h"
+#include "Swap.h"
+
+#include
+
+extern u32 dummyThreadHackAddr;
+extern u32_le dummyThreadCode[3];
+
+void netAdhocValidateLoopMemory();
+
+extern int netAdhocEnterGameModeTimeout;
+
+// Old comments regarding the value of adhocDefaultTimeout:
+// 3000000 usec
+//2000000 usec // For some unknown reason, sometimes it tooks more than 2 seconds for Adhocctl Init to connect to AdhocServer on localhost (normally only 10 ms), and sometimes it tooks more than 1 seconds for built-in AdhocServer to be ready (normally only 1 ms)
+constexpr int adhocDefaultTimeout = 5000000;
+
+constexpr int adhocDefaultDelay = 10000; //10000
+constexpr int adhocExtraDelay = 20000; //20000
+constexpr int adhocEventPollDelay = 100000; //100000; // Seems to be the same with PSP_ADHOCCTL_RECV_TIMEOUT
+
+// Old comments regarding the value of adhocEventDelay:
+//1000000
+constexpr int adhocEventDelay = 2000000; //2000000 on real PSP ?
+
+extern std::recursive_mutex adhocEvtMtx;
+
+// TODO: this one is broken, perhaps delete it entirely?
+extern int IsAdhocctlInCB;
+
+
+extern u32 matchingThreadHackAddr;
+extern u32_le matchingThreadCode[3];
+
+extern bool g_adhocServerConnected;
+
+constexpr u32 defaultLastRecvDelta = 10000; //10000 usec worked well for games published by Falcom (ie. Ys vs Sora Kiseki, Vantage Master Portable)
diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp
index a3d6d1730b..1afa6b0731 100644
--- a/Core/HLE/proAdhoc.cpp
+++ b/Core/HLE/proAdhoc.cpp
@@ -52,7 +52,9 @@
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceNetAdhoc.h"
#include "Core/Instance.h"
-#include "proAdhoc.h"
+#include "proAdhoc.h"
+
+#include "Core/HLE/NetAdhocCommon.h"
#ifdef _WIN32
#undef errno
diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp
index 17617d8b17..5f1ea72722 100644
--- a/Core/HLE/sceNet.cpp
+++ b/Core/HLE/sceNet.cpp
@@ -54,6 +54,9 @@
#include "Core/HLE/sceNp2.h"
#include "Core/HLE/sceNetInet.h"
#include "Core/HLE/sceNetResolver.h"
+#include "Core/HLE/NetAdhocCommon.h"
+
+#include "Core/MIPS/MIPSCodeUtils.h" // for macros to implement __CreateHLELoop
// These are all public. Should probably add accessors around these.
bool g_netInited;
@@ -524,6 +527,19 @@ static void __ResetInitNetLib() {
memset(¶meter, 0, sizeof(parameter));
}
+u32_le __CreateHLELoop(u32_le *loopAddr, const char *sceFuncName, const char *hleFuncName, const char *tagName) {
+ if (loopAddr == NULL || sceFuncName == NULL || hleFuncName == NULL)
+ return 0;
+
+ loopAddr[0] = MIPS_MAKE_SYSCALL(sceFuncName, hleFuncName);
+ loopAddr[1] = MIPS_MAKE_B(-2);
+ loopAddr[2] = MIPS_MAKE_NOP();
+ u32 blockSize = sizeof(u32_le)*3;
+ u32_le threadHackAddress = kernelMemory.Alloc(blockSize, false, tagName); // blockSize will be rounded to 256 granularity
+ Memory::Memcpy(threadHackAddress, loopAddr, sizeof(u32_le) * 3); // This area will be cleared again after loading an old savestate :(
+ return threadHackAddress;
+}
+
void __NetCallbackInit() {
// Init Network Callbacks
dummyThreadHackAddr = __CreateHLELoop(dummyThreadCode, "sceNetAdhoc", "__NetTriggerCallbacks", "dummythreadhack");
diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp
index 53801fa2da..8457e0bca0 100644
--- a/Core/HLE/sceNetAdhoc.cpp
+++ b/Core/HLE/sceNetAdhoc.cpp
@@ -52,6 +52,7 @@
#include "Core/HLE/sceNet.h"
#include "Core/HLE/proAdhocServer.h"
#include "Core/HLE/KernelWaitHelpers.h"
+#include "Core/HLE/NetAdhocCommon.h"
#ifdef _WIN32
#undef errno
@@ -62,7 +63,6 @@
// TODO: Make accessor functions instead, and throw all this state in a struct.
bool netAdhocInited;
bool netAdhocctlInited;
-bool g_adhocServerConnected = false;
#define DISCOVER_DURATION_US 2000000 // 2 seconds is probably the normal time it takes for PSP to connect to a group (ie. similar to NetconfigDialog time)
u64 netAdhocDiscoverStartTime = 0;
@@ -72,25 +72,11 @@ SceNetAdhocDiscoverParam* netAdhocDiscoverParam = nullptr;
u32 netAdhocDiscoverBufAddr = 0;
bool netAdhocGameModeEntered = false;
-int netAdhocEnterGameModeTimeout = 15000000; // 15 sec as default timeout, to wait for all players to join
-
-int adhocDefaultTimeout = 5000000; //2000000 usec // For some unknown reason, sometimes it tooks more than 2 seconds for Adhocctl Init to connect to AdhocServer on localhost (normally only 10 ms), and sometimes it tooks more than 1 seconds for built-in AdhocServer to be ready (normally only 1 ms)
-int adhocDefaultDelay = 10000; //10000
-int adhocExtraDelay = 20000; //20000
-int adhocEventPollDelay = 100000; //100000; // Same timings with PSP_ADHOCCTL_RECV_TIMEOUT ?
-int adhocMatchingEventDelay = 30000; //30000
-int adhocEventDelay = 2000000; //2000000 on real PSP ?
-
-constexpr u32 defaultLastRecvDelta = 10000; //10000 usec worked well for games published by Falcom (ie. Ys vs Sora Kiseki, Vantage Master Portable)
SceUID threadAdhocID;
-std::recursive_mutex adhocEvtMtx;
std::deque> adhocctlEvents;
std::map adhocctlHandlers;
-
-int IsAdhocctlInCB = 0;
-
int adhocctlNotifyEvent = -1;
int adhocctlStateEvent = -1;
int adhocSocketNotifyEvent = -1;
@@ -100,11 +86,6 @@ std::map sendTargetPeers;
int gameModeNotifyEvent = -1;
-u32 dummyThreadHackAddr = 0;
-u32_le dummyThreadCode[3];
-u32 matchingThreadHackAddr = 0;
-u32_le matchingThreadCode[3];
-
int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEtherAddr* addr, u16_le* port);
int PollAdhocSocket(SceNetAdhocPollSd* sds, int count, int timeout, int nonblock);
int FlushPtpSocket(int socketId);
@@ -1092,16 +1073,6 @@ int WaitBlockingAdhocSocket(u64 threadSocketId, int type, int pspSocketId, void*
return ERROR_NET_ADHOC_TIMEOUT;
}
-void netAdhocValidateLoopMemory() {
- // Allocate Memory if it wasn't valid/allocated after loaded from old SaveState
- if (!dummyThreadHackAddr || strcmp("dummythreadhack", kernelMemory.GetBlockTag(dummyThreadHackAddr)) != 0) {
- u32 blockSize = sizeof(dummyThreadCode);
- dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, "dummythreadhack");
- if (dummyThreadHackAddr)
- Memory::Memcpy(dummyThreadHackAddr, dummyThreadCode, sizeof(dummyThreadCode));
- }
-}
-
void __NetAdhocDoState(PointerWrap &p) {
auto s = p.Section("sceNetAdhoc", 1, 8);
if (!s)
@@ -1208,19 +1179,6 @@ void __UpdateAdhocctlHandlers(u32 flag, u32 error) {
adhocctlEvents.push_back({ flag, error });
}
-u32_le __CreateHLELoop(u32_le *loopAddr, const char *sceFuncName, const char *hleFuncName, const char *tagName) {
- if (loopAddr == NULL || sceFuncName == NULL || hleFuncName == NULL)
- return 0;
-
- loopAddr[0] = MIPS_MAKE_SYSCALL(sceFuncName, hleFuncName);
- loopAddr[1] = MIPS_MAKE_B(-2);
- loopAddr[2] = MIPS_MAKE_NOP();
- u32 blockSize = sizeof(u32_le)*3;
- u32_le dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, tagName); // blockSize will be rounded to 256 granularity
- Memory::Memcpy(dummyThreadHackAddr, loopAddr, sizeof(u32_le) * 3); // This area will be cleared again after loading an old savestate :(
- return dummyThreadHackAddr;
-}
-
void __AdhocNotifInit() {
adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify);
adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify);
diff --git a/Core/HLE/sceNetAdhoc.h b/Core/HLE/sceNetAdhoc.h
index a3fa481d34..76793fe61c 100644
--- a/Core/HLE/sceNetAdhoc.h
+++ b/Core/HLE/sceNetAdhoc.h
@@ -23,12 +23,6 @@
#ifdef _MSC_VER
#pragma pack(push,1)
#endif
-typedef struct SceNetAdhocDiscoverParam {
- u32_le unknown1; // SleepMode? (ie. 0 on on Legend Of The Dragon, 1 on Dissidia 012)
- char groupName[ADHOCCTL_GROUPNAME_LEN];
- u32_le unknown2; // size of something? (ie. 0x3c on Legend Of The Dragon, 0x14 on Dissidia 012) // Note: the param size is 0x14 may be it can contains extra data too?
- u32_le result; // inited to 0?
-} PACK SceNetAdhocDiscoverParam;
typedef struct ProductStruct { // Similar to SceNetAdhocctlAdhocId ?
s32_le unknown; // Unknown, set to 0 // Product Type ?
@@ -79,6 +73,14 @@ enum AdhocSocketRequestType : int
ADHOC_POLL_SOCKET = 7,
};
+// TODO: maybe move these to sceNetAdhocDiscover?
+typedef struct SceNetAdhocDiscoverParam {
+ u32_le unknown1; // SleepMode? (ie. 0 on on Legend Of The Dragon, 1 on Dissidia 012)
+ char groupName[ADHOCCTL_GROUPNAME_LEN];
+ u32_le unknown2; // size of something? (ie. 0x3c on Legend Of The Dragon, 0x14 on Dissidia 012) // Note: the param size is 0x14 may be it can contains extra data too?
+ u32_le result; // inited to 0?
+} PACK SceNetAdhocDiscoverParam;
+
enum AdhocDiscoverStatus : int
{
NET_ADHOC_DISCOVER_STATUS_NONE = 0,
@@ -99,17 +101,21 @@ class PointerWrap;
void Register_sceNetAdhoc();
void Register_sceNetAdhocDiscover();
+
+// TODO: expose it via "sceNetAdhocctl.h"
void Register_sceNetAdhocctl();
-u32_le __CreateHLELoop(u32_le* loopAddr, const char* sceFuncName, const char* hleFuncName, const char* tagName = NULL);
void __NetAdhocInit();
void __NetAdhocShutdown();
void __NetAdhocDoState(PointerWrap &p);
+
+// TODO: expose it via "sceNetAdhocctl.h"
void __UpdateAdhocctlHandlers(u32 flags, u32 error);
bool __NetAdhocConnected();
+// TODO: expose these via "sceNetAdhocctl.h"
// Called from netdialog (and from sceNetApctl)
// NOTE: use hleCall for sceNet* ones!
int sceNetAdhocctlGetState(u32 ptrToStatus);
@@ -125,29 +131,15 @@ int sceNetAdhocctlTerm();
int NetAdhocctl_Term();
int NetAdhocctl_GetState();
int NetAdhocctl_Create(const char* groupName);
+
int NetAdhoc_Term();
// May need to use these from sceNet.cpp
-extern bool netAdhocInited;
-extern bool netAdhocctlInited;
-extern bool g_adhocServerConnected;
+extern bool netAdhocInited; // TODO: keep here
+extern bool netAdhocctlInited; // TODO: move to sceNetAdhocctl
+
extern bool netAdhocGameModeEntered;
-extern s32 netAdhocDiscoverStatus;
-
-extern int netAdhocEnterGameModeTimeout;
-extern int adhocDefaultTimeout; //3000000 usec
-extern int adhocDefaultDelay; //10000
-extern int adhocExtraDelay; //20000
-extern int adhocEventPollDelay; //100000; // Seems to be the same with PSP_ADHOCCTL_RECV_TIMEOUT
-extern int adhocMatchingEventDelay; //30000
-extern int adhocEventDelay; //1000000
-extern std::recursive_mutex adhocEvtMtx;
-extern int IsAdhocctlInCB;
-
-extern u32 dummyThreadHackAddr;
-extern u32_le dummyThreadCode[3];
-extern u32 matchingThreadHackAddr;
-extern u32_le matchingThreadCode[3];
+extern s32 netAdhocDiscoverStatus; // TODO: maybe move to sceNetAdhocDiscover?
// Exposing those for the matching routines
// NOTE: use hleCall for sceNet* ones!
diff --git a/Core/HLE/sceNetAdhocMatching.cpp b/Core/HLE/sceNetAdhocMatching.cpp
index 9351b8d761..f4a577937e 100644
--- a/Core/HLE/sceNetAdhocMatching.cpp
+++ b/Core/HLE/sceNetAdhocMatching.cpp
@@ -18,6 +18,7 @@
#include "Core/HLE/sceNetAdhocMatching.h"
#include "Core/HLE/sceNetAdhoc.h"
+#include "Core/HLE/NetAdhocCommon.h"
#include
#include
@@ -43,6 +44,8 @@ std::vector matchingThreads;
std::deque matchingEvents;
bool netAdhocMatchingInited;
+int adhocMatchingEventDelay = 30000; //30000
+
static bool savedNetAdhocMatchingInited; // the storage to use during the savestating routine in sceNetAdhoc.cpp
void DoNetAdhocMatchingInited(PointerWrap &p) {
@@ -69,8 +72,6 @@ void RestoreNetAdhocMatchingInited() {
int netAdhocMatchingStarted = 0;
-constexpr u32 defaultLastRecvDelta = 10000; //10000 usec worked well for games published by Falcom (ie. Ys vs Sora Kiseki, Vantage Master Portable)
-
void __UpdateMatchingHandler(const MatchingArgs &ArgsPtr) {
std::lock_guard adhocGuard(adhocEvtMtx);
diff --git a/Core/HLE/sceNetAdhocMatching.h b/Core/HLE/sceNetAdhocMatching.h
index 0aeae59dfc..a262a66995 100644
--- a/Core/HLE/sceNetAdhocMatching.h
+++ b/Core/HLE/sceNetAdhocMatching.h
@@ -44,3 +44,4 @@ void __NetAdhocMatchingInit();
void __NetAdhocMatchingShutdown();
extern bool netAdhocMatchingInited;
+extern int adhocMatchingEventDelay; //30000
diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp
index a5459bbad9..62afba4405 100644
--- a/UI/ImDebugger/ImDebugger.cpp
+++ b/UI/ImDebugger/ImDebugger.cpp
@@ -36,6 +36,7 @@
#include "Core/HLE/sceNetAdhoc.h"
#include "Core/HLE/proAdhoc.h"
#include "Core/HLE/sceNetAdhocMatching.h"
+#include "Core/HLE/NetAdhocCommon.h"
#include "Common/System/Request.h"
#include "Core/Util/AtracTrack.h"
diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp
index 7336981174..8068addbfb 100644
--- a/UI/PauseScreen.cpp
+++ b/UI/PauseScreen.cpp
@@ -47,6 +47,7 @@
#include "Core/HLE/sceNet.h"
#include "Core/HLE/sceNetInet.h"
#include "Core/HLE/sceNetAdhoc.h"
+#include "Core/HLE/NetAdhocCommon.h"
#include "GPU/GPUCommon.h"
#include "GPU/GPUState.h"
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 672b819f73..fa433fa784 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -214,6 +214,7 @@
+
@@ -478,6 +479,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index dada5b41fc..b459ebb663 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -126,6 +126,7 @@
+
@@ -538,6 +539,7 @@
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 5987d02894..bd579004fb 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -708,6 +708,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/HLE/sceNet_lib.cpp \
$(SRC)/Core/HLE/proAdhoc.cpp \
$(SRC)/Core/HLE/proAdhocServer.cpp \
+ $(SRC)/Core/HLE/NetAdhocCommon.cpp \
$(SRC)/Core/HLE/sceNetAdhoc.cpp \
$(SRC)/Core/HLE/sceNetAdhocMatching.cpp \
$(SRC)/Core/HLE/sceNetApctl.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index dc7a0ddf64..604727db4c 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -739,6 +739,7 @@ SOURCES_CXX += \
$(COREDIR)/HLE/sceMpeg.cpp \
$(COREDIR)/HLE/sceNet.cpp \
$(COREDIR)/HLE/sceNet_lib.cpp \
+ $(COREDIR)/HLE/NetAdhocCommon.cpp \
$(COREDIR)/HLE/sceNetAdhoc.cpp \
$(COREDIR)/HLE/sceNetAdhocMatching.cpp \
$(COREDIR)/HLE/sceNetApctl.cpp \