Create GameMode's socket after Master and all Replicas have been created so we will know the largest buffer size.

This commit is contained in:
ANR2ME 2021-05-31 02:41:50 +07:00
parent 59322d3063
commit 7a06103cc6
3 changed files with 45 additions and 26 deletions

View file

@ -92,6 +92,7 @@ int adhocctlCurrentMode = ADHOCCTL_MODE_NONE;
int adhocConnectionType = ADHOC_CONNECT;
int gameModeSocket = (int)INVALID_SOCKET; // UDP/PDP socket? on Master only?
int gameModeBuffSize = 0;
u8* gameModeBuffer = nullptr;
GameModeArea masterGameModeArea;
std::vector<GameModeArea> replicaGameModeAreas;
@ -423,6 +424,7 @@ void deleteAllGMB() {
if (gameModeBuffer) {
free(gameModeBuffer);
gameModeBuffer = nullptr;
gameModeBuffSize = 0;
}
if (masterGameModeArea.data) {
free(masterGameModeArea.data);

View file

@ -120,6 +120,7 @@ inline bool isDisconnected(int errcode) { return (errcode == EPIPE || errcode ==
#define GAMEMODE_UPDATE_INTERVAL 500 // 12000 usec on JPCSP, but lower value works better on BattleZone (in order to get full speed 60 FPS)
#define GAMEMODE_INIT_DELAY 10000
#define GAMEMODE_SYNC_TIMEOUT 250000
#define GAMEMODE_WAITID 0x2001 // Just to differentiate WaitID with other ID on WAITTYPE_NET
// GameMode Type
#define ADHOCCTL_GAMETYPE_1A 1
@ -934,6 +935,7 @@ extern int adhocctlCurrentMode;
extern int adhocConnectionType;
extern int gameModeSocket;
extern int gameModeBuffSize;
extern u8* gameModeBuffer;
extern GameModeArea masterGameModeArea;
extern std::vector<GameModeArea> replicaGameModeAreas;

View file

@ -111,6 +111,7 @@ int FlushPtpSocket(int socketId);
int NetAdhocGameMode_DeleteMaster();
int NetAdhocctl_ExitGameMode();
int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect = true);
static int sceNetAdhocPdpCreate(const char* mac, int port, int bufferSize, u32 flag);
static int sceNetAdhocPdpSend(int id, const char* mac, u32 port, void* data, int len, int timeout, int flag);
static int sceNetAdhocPdpRecv(int id, void* addr, void* port, void* buf, void* dataLength, u32 timeout, int flag);
@ -144,18 +145,40 @@ void __NetAdhocShutdown() {
}
bool IsGameModeActive() {
return netAdhocGameModeEntered && gameModeBuffer != nullptr && gameModeSocket > 0 && adhocSockets[gameModeSocket - 1] != nullptr;
return netAdhocGameModeEntered;
}
static void __GameModeNotify(u64 userdata, int cyclesLate) {
SceUID threadID = userdata >> 32;
int uid = (int)(userdata & 0xFFFFFFFF);
if (IsGameModeActive()) {
auto sock = adhocSockets[gameModeSocket - 1];
// Need to make sure all replicas have been created before we start syncing data
if (replicaGameModeAreas.size() == (gameModeMacs.size() - 1)) {
// Socket's buffer size should fit the largest size from master/replicas, so we waited until Master & all Replicas to be created first before creating the socket, since there are games (ie. Fading Shadows) that use different buffer size for Master and Replica.
if (gameModeSocket < 0 && !isZeroMAC(&masterGameModeArea.mac)) {
u8* buf = (u8*)realloc(gameModeBuffer, gameModeBuffSize);
if (buf)
gameModeBuffer = buf;
if ((gameModeSocket = sceNetAdhocPdpCreate((const char*)&masterGameModeArea.mac, ADHOC_GAMEMODE_PORT, gameModeBuffSize, 0)) < 0) {
ERROR_LOG(SCENET, "GameMode: Failed to create socket (Error %08x)", gameModeSocket);
__KernelResumeThreadFromWait(threadID, gameModeSocket);
return;
}
else
INFO_LOG(SCENET, "GameMode: Synchronizer (%d, %d) has started", gameModeSocket, gameModeBuffSize);
}
if (gameModeSocket < 0) {
// ReSchedule
CoreTiming::ScheduleEvent(usToCycles(GAMEMODE_UPDATE_INTERVAL) - cyclesLate, gameModeNotifyEvent, userdata);
return;
}
auto sock = adhocSockets[gameModeSocket - 1];
if (!sock) {
WARN_LOG(SCENET, "GameMode: Socket (%d) got deleted", gameModeSocket);
return;
}
// Send Master data
if (masterGameModeArea.dataUpdated) {
int sentcount = 0;
@ -177,7 +200,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) {
else {
u32 error;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error);
if (error == 0 && waitID == sock->data.pdp.id) {
if (error == 0 && waitID == GAMEMODE_WAITID) {
// Resume thread after all replicas data have been received
int recvd = 0;
for (auto& gma : replicaGameModeAreas) {
@ -218,7 +241,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) {
if (IsSocketReady(sock->data.pdp.id, true, false) > 0) {
SceNetEtherAddr sendermac;
s32_le senderport = ADHOC_GAMEMODE_PORT;
s32_le bufsz = uid; // GAMEMODE_BUFFER_SIZE;
s32_le bufsz = gameModeBuffSize;
int ret = sceNetAdhocPdpRecv(gameModeSocket, &sendermac, &senderport, gameModeBuffer, &bufsz, 0, ADHOC_F_NONBLOCK);
if (ret >= 0 && bufsz > 0) {
for (auto& gma : replicaGameModeAreas) {
@ -238,7 +261,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) {
CoreTiming::ScheduleEvent(usToCycles(GAMEMODE_UPDATE_INTERVAL) - cyclesLate, gameModeNotifyEvent, userdata);
return;
}
INFO_LOG(SCENET, "GameMode Scheduler (%d, %d) has finished", gameModeSocket, uid);
INFO_LOG(SCENET, "GameMode Scheduler (%d, %d) has ended", gameModeSocket, gameModeBuffSize);
}
static void __AdhocctlNotify(u64 userdata, int cyclesLate) {
@ -384,14 +407,10 @@ int ScheduleAdhocctlState(int event, int newState, int usec, const char* reason)
return 0;
}
int StartGameModeScheduler(int bufSize) {
if (gameModeSocket < 0)
return -1;
INFO_LOG(SCENET, "GameMode Scheduler (%d, %d) has started", gameModeSocket, bufSize);
u64 param = ((u64)__KernelGetCurThread()) << 32 | bufSize;
int StartGameModeScheduler() {
INFO_LOG(SCENET, "Initiating GameMode Scheduler");
u64 param = ((u64)__KernelGetCurThread()) << 32;
CoreTiming::ScheduleEvent(usToCycles(GAMEMODE_INIT_DELAY), gameModeNotifyEvent, param);
return 0;
}
@ -4148,22 +4167,17 @@ static int sceNetAdhocGameModeCreateMaster(u32 dataAddr, int size) {
hleEatMicro(1000);
SceNetEtherAddr localMac;
getLocalMac(&localMac);
u8* buf = (u8*)realloc(gameModeBuffer, size);
if (buf)
gameModeBuffer = buf;
gameModeBuffSize = std::max(gameModeBuffSize, size);
u8* data = (u8*)malloc(size);
if (data) {
Memory::Memcpy(data, dataAddr, size);
masterGameModeArea = { 0, size, dataAddr, CoreTiming::GetGlobalTimeUsScaled(), 1, 0, localMac, data };
// Socket's buffer size should fit the largest size from master/replicas, should we waited until master & all replicas to be created first before creating the socket? (ie. the first time UpdateMaster being called?)
gameModeSocket = sceNetAdhocPdpCreate((const char*)&localMac, ADHOC_GAMEMODE_PORT, size, 0);
StartGameModeScheduler(size);
StartGameModeScheduler();
// Block current thread to sync initial master data
if (gameModeSocket > 0 && replicaGameModeAreas.size() == (gameModeMacs.size() - 1)) {
auto sock = adhocSockets[gameModeSocket - 1];
__KernelWaitCurThread(WAITTYPE_NET, sock->data.pdp.id, 0, 0, false, "syncing master data");
if (replicaGameModeAreas.size() == (gameModeMacs.size() - 1)) {
__KernelWaitCurThread(WAITTYPE_NET, GAMEMODE_WAITID, 0, 0, false, "syncing master data");
DEBUG_LOG(SCENET, "GameMode: Blocking Thread %d to Sync initial Master data", __KernelGetCurThread());
}
return hleLogDebug(SCENET, 0, "success"); // returned an id just like CreateReplica? always return 0?
@ -4209,6 +4223,8 @@ static int sceNetAdhocGameModeCreateReplica(const char *mac, u32 dataAddr, int s
}
int ret = 0;
gameModeBuffSize = std::max(gameModeBuffSize, size);
u8* data = (u8*)malloc(size);
if (data) {
Memory::Memcpy(data, dataAddr, size);
@ -4218,9 +4234,8 @@ static int sceNetAdhocGameModeCreateReplica(const char *mac, u32 dataAddr, int s
ret = gma.id; // Valid id for replica is higher than 0?
// Block current thread to sync initial master data
if (gameModeSocket > 0 && replicaGameModeAreas.size() == (gameModeMacs.size() - 1)) {
auto sock = adhocSockets[gameModeSocket - 1];
__KernelWaitCurThread(WAITTYPE_NET, sock->data.pdp.id, ret, 0, false, "syncing master data");
if (replicaGameModeAreas.size() == (gameModeMacs.size() - 1)) {
__KernelWaitCurThread(WAITTYPE_NET, GAMEMODE_WAITID, ret, 0, false, "syncing master data");
DEBUG_LOG(SCENET, "GameMode: Blocking Thread %d to Sync initial Master data", __KernelGetCurThread());
}
return hleLogSuccessInfoI(SCENET, ret, "success");