diff --git a/config/RMCP01/module/splits.txt b/config/RMCP01/module/splits.txt index 7f4e3a5c6..8a134e05c 100644 --- a/config/RMCP01/module/splits.txt +++ b/config/RMCP01/module/splits.txt @@ -164,6 +164,23 @@ ui/SectionAutogens.cpp: SectionDirector.o: .text start:0x001247CC end:0x00125B04 +net/NetManager.cpp: + .text start:0x00145770 end:0x00149E98 + .data start:0x0000DD90 end:0x0000DDC8 + .bss start:0x000049F8 end:0x00004A00 + +net/packets/ROOM.cpp: + .text start:0x0014A6D4 end:0x0014AFA0 + .bss start:0x00004A00 end:0x00004A10 + +net/packets/USER.cpp: + .text start:0x001523C4 end:0x00152DE0 + .bss start:0x00004A28 end:0x00004A30 + +net/packets/RACEHEADER1.cpp: + .text start:0x001536F0 end:0x00155184 + .bss start:0x00004A38 end:0x00004A40 + ObjKoopaFigure64.o: .text start:0x001CA560 end:0x001CADD0 diff --git a/config/RMCP01/module/symbols.txt b/config/RMCP01/module/symbols.txt index 42db4130a..b98dc2e9c 100644 --- a/config/RMCP01/module/symbols.txt +++ b/config/RMCP01/module/symbols.txt @@ -7184,33 +7184,33 @@ fn_1_145768 = .text:0x00145768; // type:function size:0x8 RKNetController_initStaticInstance = .text:0x00145770; // type:function size:0x88 scope:global align:4 fn_1_1457F8 = .text:0x001457F8; // type:function size:0x64 fn_1_14585C = .text:0x0014585C; // type:function size:0x598 -fn_1_145DF4 = .text:0x00145DF4; // type:function size:0xC -fn_1_145E00 = .text:0x00145E00; // type:function size:0xBC -fn_1_145EBC = .text:0x00145EBC; // type:function size:0xBC -fn_1_145F78 = .text:0x00145F78; // type:function size:0xBC -fn_1_146034 = .text:0x00146034; // type:function size:0xBC +scheduleShutdown__Q23Net10NetManagerFv = .text:0x00145DF4; // type:function size:0xC +startWWVSSearch__Q23Net10NetManagerFUc = .text:0x00145E00; // type:function size:0xBC +startRegionalVSSearch__Q23Net10NetManagerFUc = .text:0x00145EBC; // type:function size:0xBC +startWWBattleSearch__Q23Net10NetManagerFUc = .text:0x00145F78; // type:function size:0xBC +startRegionalBattleSearch__Q23Net10NetManagerFUc = .text:0x00146034; // type:function size:0xBC fn_1_1460F0 = .text:0x001460F0; // type:function size:0x130 fn_1_146220 = .text:0x00146220; // type:function size:0x130 -fn_1_146350 = .text:0x00146350; // type:function size:0xD4 -fn_1_146424 = .text:0x00146424; // type:function size:0xC0 -fn_1_1464E4 = .text:0x001464E4; // type:function size:0x58 -fn_1_14653C = .text:0x0014653C; // type:function size:0x18 -fn_1_146554 = .text:0x00146554; // type:function size:0x18 -fn_1_14656C = .text:0x0014656C; // type:function size:0x94 -fn_1_146600 = .text:0x00146600; // type:function size:0x7C -fn_1_14667C = .text:0x0014667C; // type:function size:0x5C -fn_1_1466D8 = .text:0x001466D8; // type:function size:0x60 +joinFriendRoom__Q23Net10NetManagerFUlUc = .text:0x00146350; // type:function size:0xD4 +createFriendRoom__Q23Net10NetManagerFUc = .text:0x00146424; // type:function size:0xC0 +resetRH1andROOM__Q23Net10NetManagerFv = .text:0x001464E4; // type:function size:0x58 +setToMMSuspensionUnk2__Q23Net10NetManagerFv = .text:0x0014653C; // type:function size:0x18 +setToMMSuspensionUnk3__Q23Net10NetManagerFv = .text:0x00146554; // type:function size:0x18 +setDisconnectInfo__Q23Net10NetManagerFQ23Net14DisconnectTypel = .text:0x0014656C; // type:function size:0x94 +getDisconnectInfo__Q23Net10NetManagerFv = .text:0x00146600; // type:function size:0x7C +resetDisconnectInfo__Q23Net10NetManagerFv = .text:0x0014667C; // type:function size:0x5C +getTimeDiff__Q23Net10NetManagerFv = .text:0x001466D8; // type:function size:0x60 fn_1_146738 = .text:0x00146738; // type:function size:0x58 fn_1_146790 = .text:0x00146790; // type:function size:0x28 fn_1_1467B8 = .text:0x001467B8; // type:function size:0x134 fn_1_1468EC = .text:0x001468EC; // type:function size:0xCC fn_1_1469B8 = .text:0x001469B8; // type:function size:0x30 -fn_1_1469E8 = .text:0x001469E8; // type:function size:0xA8 -fn_1_146A90 = .text:0x00146A90; // type:function size:0x2C -fn_1_146ABC = .text:0x00146ABC; // type:function size:0x90 -fn_1_146B4C = .text:0x00146B4C; // type:function size:0x40 +isConnectionStateIdleOrInMM__Q23Net10NetManagerFv = .text:0x001469E8; // type:function size:0xA8 +isTaskExist__Q23Net10NetManagerFv = .text:0x00146A90; // type:function size:0x2C +isConnectionStateIdle__Q23Net10NetManagerFv = .text:0x00146ABC; // type:function size:0x90 +hasFoundMatch__Q23Net10NetManagerFv = .text:0x00146B4C; // type:function size:0x40 fn_1_146B8C = .text:0x00146B8C; // type:function size:0xB8 -fn_1_146C44 = .text:0x00146C44; // type:function size:0xC +setConnectionStateIdle__Q23Net10NetManagerFv = .text:0x00146C44; // type:function size:0xC RKNetController_construct = .text:0x00146C50; // type:function size:0x3D8 scope:global align:4 fn_1_147028 = .text:0x00147028; // type:function size:0x40 fn_1_147068 = .text:0x00147068; // type:function size:0xE4 @@ -7221,15 +7221,15 @@ fn_1_1476FC = .text:0x001476FC; // type:function size:0x380 RKNetController_trySendNextRACEPacket = .text:0x00147A7C; // type:function size:0x1B4 scope:global align:4 fn_1_147C30 = .text:0x00147C30; // type:function size:0xE0 fn_1_147D10 = .text:0x00147D10; // type:function size:0x7C -fn_1_147D8C = .text:0x00147D8C; // type:function size:0x8 -fn_1_147D94 = .text:0x00147D94; // type:function size:0x84 +setConnectionState__Q23Net10NetManagerFQ33Net10NetManager15ConnectionState = .text:0x00147D8C; // type:function size:0x8 +getConnectionState__Q23Net10NetManagerFv = .text:0x00147D94; // type:function size:0x84 RKNetController_handleError = .text:0x00147E18; // type:function size:0x160 scope:global align:4 -fn_1_147F78 = .text:0x00147F78; // type:function size:0x88 -fn_1_148000 = .text:0x00148000; // type:function size:0x64 -fn_1_148064 = .text:0x00148064; // type:function size:0x80 -fn_1_1480E4 = .text:0x001480E4; // type:function size:0x68 -fn_1_14814C = .text:0x0014814C; // type:function size:0x8C -fn_1_1481D8 = .text:0x001481D8; // type:function size:0x68 +alloc__Q23Net10NetManagerFUll = .text:0x00147F78; // type:function size:0x88 +free__Q23Net10NetManagerFPv = .text:0x00148000; // type:function size:0x64 +SOAlloc__Q23Net10NetManagerFUlUl = .text:0x00148064; // type:function size:0x80 +SOFree__Q23Net10NetManagerFUlPv = .text:0x001480E4; // type:function size:0x68 +DWCAlloc__Q23Net10NetManagerFUlUll = .text:0x0014814C; // type:function size:0x8C +DWCFree__Q23Net10NetManagerFUlPv = .text:0x001481D8; // type:function size:0x68 fn_1_148240 = .text:0x00148240; // type:function size:0x20 fn_1_148260 = .text:0x00148260; // type:function size:0x104 fn_1_148364 = .text:0x00148364; // type:function size:0x50 @@ -7243,7 +7243,7 @@ fn_1_148568 = .text:0x00148568; // type:function size:0xC fn_1_148574 = .text:0x00148574; // type:function size:0x68 fn_1_1485DC = .text:0x001485DC; // type:function size:0x20C NetManager_connect = .text:0x001487E8; // type:function size:0x1A0 scope:global align:4 -fn_1_148988 = .text:0x00148988; // type:function size:0xA4 +initMMInfos__Q23Net10NetManagerFv = .text:0x00148988; // type:function size:0xA4 fn_1_148A2C = .text:0x00148A2C; // type:function size:0x1A0 fn_1_148BCC = .text:0x00148BCC; // type:function size:0xC4 fn_1_148C90 = .text:0x00148C90; // type:function size:0x12C @@ -7275,8 +7275,8 @@ fn_1_14A520 = .text:0x0014A520; // type:function size:0xA0 fn_1_14A5C0 = .text:0x0014A5C0; // type:function size:0x114 fn_1_14A6D4 = .text:0x0014A6D4; // type:function size:0xC4 fn_1_14A798 = .text:0x0014A798; // type:function size:0x40 -fn_1_14A7D8 = .text:0x0014A7D8; // type:function size:0x108 -fn_1_14A8E0 = .text:0x0014A8E0; // type:function size:0x84 +init__Q23Net11ROOMHandlerFQ23Net8RoomRole = .text:0x0014A7D8; // type:function size:0x108 +reset__Q23Net11ROOMHandlerFv = .text:0x0014A8E0; // type:function size:0x84 fn_1_14A964 = .text:0x0014A964; // type:function size:0x158 fn_1_14AABC = .text:0x0014AABC; // type:function size:0xF4 fn_1_14ABB0 = .text:0x0014ABB0; // type:function size:0x10 @@ -7406,7 +7406,7 @@ fn_1_1523C4 = .text:0x001523C4; // type:function size:0x80 fn_1_152444 = .text:0x00152444; // type:function size:0x54 fn_1_152498 = .text:0x00152498; // type:function size:0xF8 fn_1_152590 = .text:0x00152590; // type:function size:0x7C -fn_1_15260C = .text:0x0015260C; // type:function size:0xFC +update__Q23Net11USERHandlerFv = .text:0x0015260C; // type:function size:0xFC fn_1_152708 = .text:0x00152708; // type:function size:0x40 fn_1_152748 = .text:0x00152748; // type:function size:0x4 fn_1_15274C = .text:0x0015274C; // type:function size:0xEC @@ -7443,8 +7443,8 @@ fn_1_15358C = .text:0x0015358C; // type:function size:0x60 fn_1_1535EC = .text:0x001535EC; // type:function size:0x104 fn_1_1536F0 = .text:0x001536F0; // type:function size:0x194 fn_1_153884 = .text:0x00153884; // type:function size:0x44 -fn_1_1538C8 = .text:0x001538C8; // type:function size:0xC -fn_1_1538D4 = .text:0x001538D4; // type:function size:0x14C +setPrepared__Q23Net18RACEHEADER1HandlerFv = .text:0x001538C8; // type:function size:0xC +reset__Q23Net18RACEHEADER1HandlerFv = .text:0x001538D4; // type:function size:0x14C fn_1_153A20 = .text:0x00153A20; // type:function size:0x338 fn_1_153D58 = .text:0x00153D58; // type:function size:0xA4 fn_1_153DFC = .text:0x00153DFC; // type:function size:0x210 @@ -24514,15 +24514,15 @@ lbl_1_bss_4868 = .bss:0x00004868; // type:object size:0x8 lbl_1_bss_4870 = .bss:0x00004870; // type:object size:0x8 data:4byte lbl_1_bss_4878 = .bss:0x00004878; // type:object size:0x80 data:4byte lbl_1_bss_48F8 = .bss:0x000048F8; // type:object size:0x100 -lbl_1_bss_49F8 = .bss:0x000049F8; // type:object size:0x8 data:4byte -lbl_1_bss_4A00 = .bss:0x00004A00; // type:object size:0x8 data:4byte +spInstance__Q23Net10NetManager = .bss:0x000049F8; // type:object size:0x8 data:4byte +spInstance__Q23Net11ROOMHandler = .bss:0x00004A00; // type:object size:0x8 data:4byte lbl_1_bss_4A08 = .bss:0x00004A08; // type:object size:0x8 data:4byte lbl_1_bss_4A10 = .bss:0x00004A10; // type:object size:0x8 data:4byte lbl_1_bss_4A18 = .bss:0x00004A18; // type:object size:0x8 data:4byte lbl_1_bss_4A20 = .bss:0x00004A20; // type:object size:0x8 data:4byte -lbl_1_bss_4A28 = .bss:0x00004A28; // type:object size:0x8 data:4byte +spInstance__Q23Net11USERHandler = .bss:0x00004A28; // type:object size:0x8 data:4byte lbl_1_bss_4A30 = .bss:0x00004A30; // type:object size:0x8 data:4byte -lbl_1_bss_4A38 = .bss:0x00004A38; // type:object size:0x8 data:4byte +spInstance__Q23Net18RACEHEADER1Handler = .bss:0x00004A38; // type:object size:0x8 data:4byte lbl_1_bss_4A40 = .bss:0x00004A40; // type:object size:0x4 data:4byte lbl_1_bss_4A44 = .bss:0x00004A44; // type:object size:0x4 lbl_1_bss_4A48 = .bss:0x00004A48; // type:object size:0x8 diff --git a/configure.py b/configure.py index 5e8e58f52..283f5dee6 100755 --- a/configure.py +++ b/configure.py @@ -792,6 +792,11 @@ def MatchingFor(*versions): Object(Matching, "geo/BoxColManager.cpp"), Object(Matching, "geo/BoxColUnit.cpp"), + + Object(NonMatching, "net/NetManager.cpp"), + Object(NonMatching, "net/packets/USER.cpp"), + Object(NonMatching, "net/packets/RACEHEADER1.cpp"), + Object(NonMatching, "net/packets/ROOM.cpp"), ], }, { diff --git a/lib/dwc/common/dwc_error.c b/lib/dwc/common/dwc_error.c index eb3349fc1..8e8d84442 100644 --- a/lib/dwc/common/dwc_error.c +++ b/lib/dwc/common/dwc_error.c @@ -17,7 +17,7 @@ int DWC_GetLastError(int* errorCode) { return stDwcLastError; } -int DWC_GetLastErrorEx(int* errorCode, int* errorType) { +s32 DWC_GetLastErrorEx(s32* errorCode, u32* errorType) { if (errorCode) *errorCode = stDwcErrorCode; if (errorType) { diff --git a/lib/dwc/common/dwc_error.h b/lib/dwc/common/dwc_error.h index 3dc55672e..89a1a27ff 100644 --- a/lib/dwc/common/dwc_error.h +++ b/lib/dwc/common/dwc_error.h @@ -1,11 +1,13 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif int DWC_GetLastError(int* errorCode); -int DWC_GetLastErrorEx(int* errorCode, int* errorType); +s32 DWC_GetLastErrorEx(s32* errorCode, u32* errorType); void DWC_ClearError(); #ifdef __cplusplus diff --git a/src/net/DisconnectInfo.hpp b/src/net/DisconnectInfo.hpp new file mode 100644 index 000000000..d4ce3a032 --- /dev/null +++ b/src/net/DisconnectInfo.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace Net { + +// Each value yields a different error screen +enum DisconnectType { + DISCONNECT_TYPE_NONE = 0x0, + DISCONNECT_TYPE_ERROR_CODE = 0x1, // standard error code screen + DISCONNECT_TYPE_BAD_MII_NAME = 0x2, + DISCONNECT_TYPE_CANT_JOIN_FRIEND = 0x3, // sends user back to friend roster + DISCONNECT_TYPE_DISK_EJECTED = 0x4, // user ejected disk during login + DISCONNECT_TYPE_UNRECOVERABLE_ERROR = 0x5, // informs user to reboot +}; + +struct DisconnectInfo { + DisconnectType type; + s32 code; + + // reset() 805e3f4c +}; + +} // namespace Net diff --git a/src/net/NetManager.cpp b/src/net/NetManager.cpp new file mode 100644 index 000000000..a0eb3eab2 --- /dev/null +++ b/src/net/NetManager.cpp @@ -0,0 +1,288 @@ +#include "NetManager.hpp" + +#include "net/packets/ROOM.hpp" + +#include + +namespace Net { + +void NetManager::scheduleShutdown() { m_shutdownScheduled = true; } + +void NetManager::startWWVSSearch(u8 localPlayerCount) { + ConnectionState connState = getConnectionState(); + + // were online, start search/mm + if (connState == CONNECTION_STATE_IDLE) { + initMMInfos(); + m_roomType = ROOM_TYPE_VS_WW; + m_matchMakingInfos[0].m_localPlayerCount = localPlayerCount; + m_matchMakingInfos[1].m_localPlayerCount = localPlayerCount; + // allows the logic in RACEHEADER1Handler_calc() to run + RACEHEADER1Handler::getInstance()->setPrepared(); + } +} + +void NetManager::startRegionalVSSearch(u8 localPlayerCount) { + ConnectionState connState = getConnectionState(); + + if (connState == CONNECTION_STATE_IDLE) { + initMMInfos(); + m_roomType = ROOM_TYPE_VS_REGIONAL; + m_matchMakingInfos[0].m_localPlayerCount = localPlayerCount; + m_matchMakingInfos[1].m_localPlayerCount = localPlayerCount; + RACEHEADER1Handler::getInstance()->setPrepared(); + } +} + +void NetManager::startWWBattleSearch(u8 localPlayerCount) { + ConnectionState connState = getConnectionState(); + + if (connState == CONNECTION_STATE_IDLE) { + initMMInfos(); + m_matchMakingInfos[0].m_localPlayerCount = localPlayerCount; + m_matchMakingInfos[1].m_localPlayerCount = localPlayerCount; + m_roomType = ROOM_TYPE_BT_WW; + RACEHEADER1Handler::getInstance()->setPrepared(); + } +} + +void NetManager::startRegionalBattleSearch(u8 localPlayerCount) { + ConnectionState connState = getConnectionState(); + + if (connState == CONNECTION_STATE_IDLE) { + initMMInfos(); + m_matchMakingInfos[0].m_localPlayerCount = localPlayerCount; + m_matchMakingInfos[1].m_localPlayerCount = localPlayerCount; + m_roomType = ROOM_TYPE_BT_REGIONAL; + RACEHEADER1Handler::getInstance()->setPrepared(); + } +} + +void NetManager::joinFriendRoom(u32 friendRosterId, u8 localPlayerCount) { + ConnectionState connState = getConnectionState(); + + if (connState == CONNECTION_STATE_IDLE) { + initMMInfos(); + m_matchMakingInfos[0].m_hostFriendId = friendRosterId; + m_matchMakingInfos[1].m_hostFriendId = friendRosterId; + m_roomType = ROOM_TYPE_NONHOST_PRIVATE; + m_matchMakingInfos[0].m_localPlayerCount = localPlayerCount; + m_matchMakingInfos[1].m_localPlayerCount = localPlayerCount; + ROOMHandler::getInstance()->init(ROLE_GUEST); + } +} + +void NetManager::createFriendRoom(u8 localPlayerCount) { + ConnectionState connState = getConnectionState(); + + if (connState == CONNECTION_STATE_IDLE) { + initMMInfos(); + m_roomType = ROOM_TYPE_HOST_PRIVATE; + m_matchMakingInfos[0].m_localPlayerCount = localPlayerCount; + m_matchMakingInfos[1].m_localPlayerCount = localPlayerCount; + ROOMHandler::getInstance()->init(ROLE_HOST); + } +} + +void NetManager::resetRH1andROOM() { + if (RACEHEADER1Handler::getInstance() != nullptr) { + RACEHEADER1Handler::getInstance()->reset(); + } + if (ROOMHandler::getInstance() != nullptr) { + ROOMHandler::getInstance()->reset(); + } + m_mmSuspension = MM_SUSPENSION_ERROR; +} + +void NetManager::setToMMSuspensionUnk2() { + if (m_mmSuspension == MM_SUSPENSION_ERROR) { + return; + } + m_mmSuspension = MM_SUSPENSION_UNK2; +} + +void NetManager::setToMMSuspensionUnk3() { + if (m_mmSuspension == MM_SUSPENSION_ERROR) { + return; + } + m_mmSuspension = MM_SUSPENSION_UNK3; +} + +void NetManager::setDisconnectInfo(DisconnectType dcType, s32 errorCode) { + OSLockMutex(&m_mutex); + + if (dcType == DISCONNECT_TYPE_DISK_EJECTED) { + m_hasEjectedDisk = true; + } else if (m_disconnectInfo.type != DISCONNECT_TYPE_UNRECOVERABLE_ERROR) { + m_disconnectInfo.type = dcType; + m_disconnectInfo.code = errorCode; + switch (dcType) { + case DISCONNECT_TYPE_ERROR_CODE: + case DISCONNECT_TYPE_BAD_MII_NAME: + case DISCONNECT_TYPE_UNRECOVERABLE_ERROR: + m_connectionState = CONNECTION_STATE_ERROR; + break; + } + } + OSUnlockMutex(&m_mutex); +} + +DisconnectInfo NetManager::getDisconnectInfo() { + DisconnectInfo dcInfo; + + OSLockMutex(&m_mutex); + + if (m_disconnectInfo.type != DISCONNECT_TYPE_UNRECOVERABLE_ERROR && + m_hasEjectedDisk) { + dcInfo.type = DISCONNECT_TYPE_DISK_EJECTED; + dcInfo.code = 0; + + } else { + dcInfo.type = m_disconnectInfo.type; + dcInfo.code = m_disconnectInfo.code; + } + OSUnlockMutex(&m_mutex); + return dcInfo; +} + +void NetManager::resetDisconnectInfo() { + m_hasEjectedDisk = false; + OSLockMutex(&m_mutex); + if (m_disconnectInfo.type != DISCONNECT_TYPE_UNRECOVERABLE_ERROR) { + m_disconnectInfo.type = DISCONNECT_TYPE_NONE; + m_disconnectInfo.code = 0; + } + OSUnlockMutex(&m_mutex); +} + +s32 NetManager::getTimeDiff() { + s32 time = m_matchMakingInfos[m_currMMInfo].m_MMStartTime; + + // has to do u64 comparison + if (m_matchMakingInfos[m_currMMInfo].m_MMStartTime == 0) { + return 0; + } + + OSTime currTime = OSGetTime(); + return ((s32)currTime - time) / OS_TIMER_CLOCK; +} + +bool NetManager::isConnectionStateIdleOrInMM() { + bool idleOrMM = false; + ConnectionState connState = getConnectionState(); + + // had to write it slightly weird to match + if (connState >= CONNECTION_STATE_IDLE && + CONNECTION_STATE_IN_MM >= connState) { + idleOrMM = true; + } + return idleOrMM; +} + +bool NetManager::isTaskExist() { + // checks if we've requested mainNetworkLoop + return m_taskThread->isTaskExist() ? false : true; +} + +bool NetManager::isConnectionStateIdle() { + return getConnectionState() == CONNECTION_STATE_IDLE; +} + +bool NetManager::hasFoundMatch() { + bool inMatch = false; + + bool isMyAidInMatch = ((1 << m_matchMakingInfos[m_currMMInfo].m_myAid) & + m_matchMakingInfos[m_currMMInfo].m_fullAidBitmap); + // were in a match if my aid is in the room and we have connected to another + // console + if (isMyAidInMatch && + m_matchMakingInfos[m_currMMInfo].m_numConnectedConsoles > 1) { + inMatch = true; + } + return inMatch; +} + +void NetManager::setConnectionStateIdle() { + m_connectionState = CONNECTION_STATE_IDLE; +} + +void NetManager::setConnectionState(ConnectionState connState) { + m_connectionState = connState; +} + +NetManager::ConnectionState NetManager::getConnectionState() { + s32 code; + u32 type; + DWC_GetLastErrorEx(&code, &type); + + ConnectionState connState; + + // 4xxxx and 98xxx are sake erorrs, otherwise set connectionState + if ((code / 10000) == 4 || (code / 1000) == 98) { + connState = CONNECTION_STATE_SAKE_ERROR; + } else { + connState = m_connectionState; + } + + return connState; +} + +void* NetManager::alloc(u32 size, s32 alignment) { + void* block = nullptr; + if (size != 0) { + OSLockMutex(&m_mutex); + block = m_heap->alloc(size, alignment); + OSUnlockMutex(&m_mutex); + } + return block; +} + +void NetManager::free(void* block) { + if (block != nullptr) { + OSLockMutex(&m_mutex); + m_heap->free(block); + OSUnlockMutex(&m_mutex); + } +} + +void* NetManager::SOAlloc(u32 unk, u32 size) { + void* block = nullptr; + NetManager* netManager = spInstance; + if (size != 0) { + OSLockMutex(&netManager->m_mutex); + block = netManager->m_heap->alloc(size, 0x20); + OSUnlockMutex(&netManager->m_mutex); + } + return block; +} + +void NetManager::SOFree(u32 unk, void* block) { + NetManager* netManager = spInstance; + if (block != nullptr) { + OSLockMutex(&netManager->m_mutex); + netManager->m_heap->free(block); + OSUnlockMutex(&netManager->m_mutex); + } +} + +void* NetManager::DWCAlloc(u32 unk, u32 size, s32 alignment) { + void* block = nullptr; + NetManager* netManager = spInstance; + if (size != 0) { + OSLockMutex(&netManager->m_mutex); + block = netManager->m_heap->alloc(size, alignment); + OSUnlockMutex(&netManager->m_mutex); + } + return block; +} + +void NetManager::DWCFree(u32 unk, void* block) { + NetManager* netManager = spInstance; + if (block != nullptr) { + OSLockMutex(&netManager->m_mutex); + netManager->m_heap->free(block); + OSUnlockMutex(&netManager->m_mutex); + } +} + +} // namespace Net diff --git a/src/net/NetManager.hpp b/src/net/NetManager.hpp new file mode 100644 index 000000000..9641e6c93 --- /dev/null +++ b/src/net/NetManager.hpp @@ -0,0 +1,221 @@ +// Credits: Melg and CLF, used as reference for names. +// See bottom of file for the licenses +// https://github.com/MelgMKW/Pulsar/blob/main/GameSource/MarioKartWii/RKNet/RKNetController.hpp +// https://github.com/CLF78/OpenPayload/blob/master/payload/game/net/RKNetController.hpp + +#pragma once + +#include + +#include "net/DisconnectInfo.hpp" +#include "net/packets/RACEPacketHolder.hpp" + +#include +#include + +namespace Net { + +class NetManager { +public: + enum ConnectionState { + CONNECTION_STATE_SHUTDOWN = 0x0, // offline + CONNECTION_STATE_BEGIN_LOGIN = 0x1, + CONNECTION_STATE_CHECK_PROFANITY = 0x2, + CONNECTION_STATE_SOMETHING_GP_FRIENDS = + 0x3, // Friend related, needs better name + CONNECTION_STATE_SYNC_FRIENDS = 0x4, // checks if a friend has added back + CONNECTION_STATE_IDLE = 0x5, // online but not doing anything + CONNECTION_STATE_IN_MM = 0x6, // searching or in a room + CONNECTION_STATE_ERROR = 0x7, // non SAKE errors + CONNECTION_STATE_SAKE_ERROR = 0x8, // set when the EC is 4xxxx or 98xxx + }; + + enum RoomType { + ROOM_TYPE_NONE = 0x0, + ROOM_TYPE_VS_WW = 0x1, + ROOM_TYPE_VS_REGIONAL = 0x2, + ROOM_TYPE_BT_WW = 0x3, + ROOM_TYPE_BT_REGIONAL = 0x4, + ROOM_TYPE_HOST_PRIVATE = 0x5, + ROOM_TYPE_NONHOST_PRIVATE = 0x6, + ROOM_TYPE_JOINING_FRIEND_WW = 0x7, + ROOM_TYPE_JOINING_FRIEND_REGIONAL = 0x8, + }; + + // Certainly suspending MM related, but unsure about last two values + enum UnkMMSuspension { + MM_SUSPENSION_NONE = 0x0, + MM_SUSPENSION_ERROR = 0x1, // triggers a dc + MM_SUSPENSION_UNK2 = 0x2, // set when matchingSuspended is true + MM_SUSPENSION_UNK3 = 0x3, // set when matchingSuspended is false + }; + + void scheduleShutdown(); + + void startWWVSSearch(u8 localPlayerCount); + + void startRegionalVSSearch(u8 localPlayerCount); + + void startWWBattleSearch(u8 localPlayerCount); + + void startRegionalBattleSearch(u8 localPlayerCount); + + void joinFriendRoom(u32 friendRosterId, u8 localPlayerCount); + + void createFriendRoom(u8 localPlayerCount); + + void resetRH1andROOM(); + + void setDisconnectInfo(DisconnectType dcType, s32 errorCode); + + void setToMMSuspensionUnk2(); + + void setToMMSuspensionUnk3(); + + DisconnectInfo getDisconnectInfo(); + + void resetDisconnectInfo(); + + s32 getTimeDiff(); + + void initMMInfos(); + + bool isConnectionStateIdleOrInMM(); + + bool isTaskExist(); + + bool isConnectionStateIdle(); + + bool hasFoundMatch(); + + void setConnectionStateIdle(); + + void setConnectionState(ConnectionState connState); + + inline ConnectionState getConnectionState(); + + void* alloc(u32 size, s32 alignment); + + void free(void* block); + + // namesake of the alloc/free functions is the lib they're called by + static void* SOAlloc(u32 unk, u32 size); + + static void SOFree(u32 unk, void* block); + + static void* DWCAlloc(u32 unk, u32 size, s32 alignment); + + static void DWCFree(u32 unk, void* block); + +private: + struct MatchMakingInfo { + u64 m_MMStartTime; // gets set upon match making + u32 m_numConnectedConsoles; // number of non guest players + u32 m_playerCount; // players in room (includes guests) + u32 m_fullAidBitmap; // # bits is equal to num consoles, all 1 + u32 m_availableAidBitmap; // will equal the full bitmap by end of mm + u32 m_roomId; + s32 m_hostFriendId; // -1 if host isn't a friend + u8 m_localPlayerCount; + u8 m_myAid; + u8 m_hostAid; + u8 _23[0x53 - 0x23]; // some kind of localPlayerCount for each aid + bool m_matchingSuspended; // set when entering mm, cleared shortly after + u8 _54[0x58 - 0x54]; + }; + static_assert(sizeof(MatchMakingInfo) == 0x58); + + // Two vtables + void* m_vtable1; // offset 0xc is NetManager's dtor + void* m_vtable2; // unk dtor at 0xc, also present in FriendManager vtable + OSMutex m_mutex; + EGG::ExpHeap* m_heap; + EGG::TaskThread* m_taskThread; // runs the mainLoop + ConnectionState m_connectionState; + DisconnectInfo m_disconnectInfo; + u8 _0034[0x0038 - 0x0034]; // padding? + MatchMakingInfo m_matchMakingInfos[2]; + RoomType m_roomType; + UnkMMSuspension m_mmSuspension; + // points to RACE packets to be sent, two per aid + RACEPacketHolder* m_sendRACEPackets[2][12]; + // points to RACE packets to be recieved, two per aid + RACEPacketHolder* m_recvRACEPackets[2][12]; + // The RACE packet to be sent, formed from m_sendRACEPackets, one per aid + PacketHolder* m_outgoingRACEPacket[12]; + u64 m_timeOfLastSentRACE[12]; + u64 m_timeOfLastRecvRACE[12]; + u64 m_timeBetweenSendingPackets[12]; // time bewteen sent packets per aid + u64 m_timeBetweenRecvPackets[12]; // time between recieved packets per aid + u8 m_aidLastSentTo; // Aid of last player we sent to + u8 m_recvRACEPacketBuffer[12][0x2e0]; + u8 _25e1[0x25e4 - 0x25e1]; // padding + u8 _25e4[0x25ec - 0x25e4]; // Unknown struct + u8 _25ec[0x2754 - 0x25ec]; // Friend related struct + bool m_friendStatusChanged; // set when a friend adds back + bool m_shutdownScheduled; // set when logging off + bool m_shouldUpdateFriendStatus; + bool m_hasEjectedDisk; // triggers a dc screen + u8 _2759[0x275c - 0x2759]; + s32 m_badWordsNum; // number of bad words found in the profanity check + u8 _2760[0x2764 - 0x2760]; // unsure + s32 m_vr; + s32 m_br; + u32 m_lastSendIdx[12]; // idx of m_sendRACEPackets last sent per aid + // idx of m_recvRACEPackets last recvieved per packet per aid + u32 m_lastRecvIdx[12][8]; + s32 m_currMMInfo; // Current MM info used + u8 m_playerIdToAidMapping[12]; + u32 m_disconnectedAids; // disconnected if 1 << aid is 1 + u32 m_disconnectedPlayerIds; // disconnected if 1 << pid is 1 + u8 _2934[0x295c - 0x2934]; // elo based MM struct + u8 _295c[0x29c8 - 0x295c]; // some timers + + static NetManager* spInstance; +}; +static_assert(sizeof(NetManager) == 0x29c8); +} // namespace Net + +// MIT License + +// Copyright (c) 2023 MelgMKW + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// MIT License + +// Copyright (c) 2024 CLF78 + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. diff --git a/src/net/packets/EVENT.hpp b/src/net/packets/EVENT.hpp new file mode 100644 index 000000000..7567fbfb9 --- /dev/null +++ b/src/net/packets/EVENT.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace Net { + +struct EVENTPacket { + u8 _00[0xf8 - 0x00]; +}; +static_assert(sizeof(EVENTPacket) == 0xf8); + +class EVENTHandler { + u8 _0000[0x2b88 - 0x0000]; +}; +static_assert(sizeof(EVENTHandler) == 0x2b88); + +} diff --git a/src/net/packets/HEADER.hpp b/src/net/packets/HEADER.hpp new file mode 100644 index 000000000..5a9f6d997 --- /dev/null +++ b/src/net/packets/HEADER.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace Net { + +struct HEADERPacket { + u8 _00[0x10 - 0x00]; +}; +static_assert(sizeof(HEADERPacket) == 0x10); + +} diff --git a/src/net/packets/ITEM.hpp b/src/net/packets/ITEM.hpp new file mode 100644 index 000000000..3a9b85b78 --- /dev/null +++ b/src/net/packets/ITEM.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace Net { + +struct ITEMPacket { + u8 _0[0x8 - 0x0]; +}; +static_assert(sizeof(ITEMPacket) == 0x8); + +class ITEMHandler { + u8 _000[0x184 - 0x000]; +}; +static_assert(sizeof(ITEMHandler) == 0x184); + +} diff --git a/src/net/packets/PacketHolder.hpp b/src/net/packets/PacketHolder.hpp new file mode 100644 index 000000000..291d88e13 --- /dev/null +++ b/src/net/packets/PacketHolder.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace Net { + +template +class PacketHolder { +public: + PacketHolder(u32 bufferSize); + ~PacketHolder(); + + void reset(); + void copy(T *src, u32 len); + void append(T *src, u32 len); + +private: + T *packet; + u32 bufferSize; + u32 packetSize; + +}; + +} diff --git a/src/net/packets/RACEDATA.hpp b/src/net/packets/RACEDATA.hpp new file mode 100644 index 000000000..497e1bd51 --- /dev/null +++ b/src/net/packets/RACEDATA.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace Net { + +class RACEDATAPacket { + u8 _00[0x40 - 0x00]; +}; +static_assert(sizeof(RACEDATAPacket) == 0x40); + +} diff --git a/src/net/packets/RACEHEADER1.cpp b/src/net/packets/RACEHEADER1.cpp new file mode 100644 index 000000000..efa726f99 --- /dev/null +++ b/src/net/packets/RACEHEADER1.cpp @@ -0,0 +1,9 @@ +#include "RACEHEADER1.hpp" + +namespace Net { + +void RACEHEADER1Handler::setPrepared() { + m_prepared = true; +} + +} diff --git a/src/net/packets/RACEHEADER1.hpp b/src/net/packets/RACEHEADER1.hpp new file mode 100644 index 000000000..5d6b184bb --- /dev/null +++ b/src/net/packets/RACEHEADER1.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace Net { + +struct RACEHEADER1Packet { + u8 _00[0x28 - 0x00]; +}; +static_assert(sizeof(RACEHEADER1Packet) == 0x28); + +class RACEHEADER1Handler { +public: + static RACEHEADER1Handler *getInstance() { + return spInstance; + } + + void setPrepared(); + + void reset(); + +private: + bool m_prepared; + u8 _004[0x260 - 0x001]; + + static RACEHEADER1Handler *spInstance; +}; +static_assert(sizeof(RACEHEADER1Handler) == 0x260); + +} diff --git a/src/net/packets/RACEHEADER2.hpp b/src/net/packets/RACEHEADER2.hpp new file mode 100644 index 000000000..53c0c95d4 --- /dev/null +++ b/src/net/packets/RACEHEADER2.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace Net { + +struct RACEHEADER2Packet { + u8 _00[0x28 - 0x00]; +}; +static_assert(sizeof(RACEHEADER2Packet) == 0x28); + +} diff --git a/src/net/packets/RACEPacketHolder.hpp b/src/net/packets/RACEPacketHolder.hpp new file mode 100644 index 000000000..41ffc6f16 --- /dev/null +++ b/src/net/packets/RACEPacketHolder.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "net/packets/PacketHolder.hpp" +#include "net/packets/HEADER.hpp" +#include "net/packets/RACEHEADER1.hpp" +#include "net/packets/RACEHEADER2.hpp" +#include "net/packets/SELECT.hpp" +#include "net/packets/RACEDATA.hpp" +#include "net/packets/USER.hpp" +#include "net/packets/ITEM.hpp" +#include "net/packets/EVENT.hpp" + +#include + +namespace Net { + +class RACEPacketHolder { +private: + // Maybe this is an array? + PacketHolder *m_headerPacket; + PacketHolder *m_raceHeader1Packet; + PacketHolder *m_raceHeader2Packet; + PacketHolder *m_selectPacket; + PacketHolder *m_raceDataPacket; + PacketHolder *m_userPacket; + PacketHolder *m_itemPacket; + PacketHolder *m_eventPacket; + + // 0x8065a3dc + RACEPacketHolder(); + // 0x8065a474 + ~RACEPacketHolder(); +}; +static_assert(sizeof(RACEPacketHolder) == 0x20); + +} diff --git a/src/net/packets/ROOM.cpp b/src/net/packets/ROOM.cpp new file mode 100644 index 000000000..804697d3e --- /dev/null +++ b/src/net/packets/ROOM.cpp @@ -0,0 +1,5 @@ +#include "ROOM.hpp" + +namespace Net { + +} diff --git a/src/net/packets/ROOM.hpp b/src/net/packets/ROOM.hpp new file mode 100644 index 000000000..bbc48467c --- /dev/null +++ b/src/net/packets/ROOM.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace Net { + +enum RoomRole { + ROLE_HOST = 0x0, + ROLE_GUEST = 0x1, +}; + +// Credits: https://wiki.tockdom.com/wiki/Network_Protocol/ROOM +#pragma options align=packed +struct ROOMPacket { + // Message Type: + // 1: Starting room + // 2: Adding another as a friend + // 3: Someone joined room + // 4: Chat + u8 messageType; + + // These are parameters, but its use depends on the message type. + u16 _1; + u8 _3; +}; +#pragma options align=reset +static_assert(sizeof(ROOMPacket) == 0x4); + +class ROOMHandler { +public: + void init(RoomRole role); + + void reset(); + + static ROOMHandler *getInstance() { + return spInstance; + } + +private: + u8 _00[0x80 - 0x00]; + + static ROOMHandler *spInstance; +}; +static_assert(sizeof(ROOMHandler) == 0x80); + +} diff --git a/src/net/packets/SELECT.hpp b/src/net/packets/SELECT.hpp new file mode 100644 index 000000000..bf5d2955f --- /dev/null +++ b/src/net/packets/SELECT.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace Net { + +struct SELECTPacket { + u8 _00[0x38 - 0x00]; +}; +static_assert(sizeof(SELECTPacket) == 0x38); + +class SELECTHandler { + u8 _000[0x3f8 - 0x000]; +}; +static_assert(sizeof(SELECTHandler) == 0x3f8); + +} diff --git a/src/net/packets/USER.cpp b/src/net/packets/USER.cpp new file mode 100644 index 000000000..03f149e17 --- /dev/null +++ b/src/net/packets/USER.cpp @@ -0,0 +1,5 @@ +#include "USER.hpp" + +namespace Net { + +} diff --git a/src/net/packets/USER.hpp b/src/net/packets/USER.hpp new file mode 100644 index 000000000..a9d092be9 --- /dev/null +++ b/src/net/packets/USER.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace Net { + +struct USERPacket { + u8 _00[0xc0 - 0x00]; +}; +static_assert(sizeof(USERPacket) == 0xc0); + +class USERHandler { +public: + static USERHandler *getInstance() { + return spInstance; + } + + void update(); + +private: + + u8 _000[0x9f0 - 0x000]; + + static USERHandler *spInstance; +}; +static_assert(sizeof(USERHandler) == 0x9f0); + +}