From 930a104e503fdfa65221f38074c7936d9ac1e794 Mon Sep 17 00:00:00 2001 From: NaN Date: Mon, 3 Aug 2026 16:53:58 -0400 Subject: [PATCH] feat: add PS4 networking support --- .../Common/Network/NetworkSocketLayer.cpp | 87 +++++++++++++++++-- .../Common/UI/UIScene_JoinMenu.cpp | 58 +++++++++---- .../Common/UI/UIScene_LoadOrJoinMenu.cpp | 23 +++-- .../Common/UI/UIScene_MainMenu.cpp | 18 +++- Minecraft.Client/Minecraft.Client.vcxproj | 5 +- .../Orbis/OrbisExtras/OrbisStubs.cpp | 27 +++--- Minecraft.World/Minecraft.World.vcxproj | 2 +- 7 files changed, 174 insertions(+), 46 deletions(-) diff --git a/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp b/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp index 22900158..abee0fd9 100644 --- a/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp +++ b/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp @@ -16,9 +16,11 @@ SOCKET NetworkSocketLayer::s_advertiseSock = -1; SOCKET NetworkSocketLayer::s_discoverySock = -1; #if defined __PS3__ +#define LCE_NET_ERRNO sys_net_errno int closesocket(int s) { return socketclose(s); }; void terminate_networking() { cellNetCtlTerm(); sys_net_finalize_network(); }; #elif defined __ORBIS__ +#define LCE_NET_ERRNO errno int closesocket(int s) { return sceNetSocketClose(s); }; int socketclose(int s) { return sceNetSocketClose(s); }; void terminate_networking() {}; @@ -60,10 +62,52 @@ std::vector NetworkSocketLayer::s_disconnectedSmallIds; CRITICAL_SECTION NetworkSocketLayer::s_freeSmallIdLock; std::vector NetworkSocketLayer::s_freeSmallIds; -bool g_MultiplayerHost = false; -bool g_MultiplayerJoin = true; -int g_MultiplayerPort = NETWORK_LAN_DEFAULT_PORT; -char g_MultiplayerIP[256] = "127.0.0.1"; +bool g_Win64MultiplayerHost = false; +#if defined __ORBIS__ +// Orbis has direct lan networking so it can bypass psn account checks +bool g_Win64MultiplayerJoin = true; +int g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT; +char g_Win64MultiplayerIP[256] = ""; +#else +bool g_Win64MultiplayerJoin = false; +int g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT; +char g_Win64MultiplayerIP[256] = "127.0.0.1"; +#endif + +#ifdef _WINDOWS64 +static int GetLocalIPv4Interfaces(SOCKET socketHandle, struct in_addr *localAddresses, + struct in_addr *broadcastAddresses, int capacity) +{ + INTERFACE_INFO interfaceList[32]; + DWORD bytesReturned = 0; + if(WSAIoctl(socketHandle, SIO_GET_INTERFACE_LIST, NULL, 0, interfaceList, + sizeof(interfaceList), &bytesReturned, NULL, NULL) == SOCKET_ERROR) + { + return 0; + } + + int interfaceCount = (int)(bytesReturned / sizeof(INTERFACE_INFO)); + int resultCount = 0; + for(int i = 0; i < interfaceCount && resultCount < capacity; ++i) + { + struct sockaddr_in *address = (struct sockaddr_in *)&interfaceList[i].iiAddress; + struct sockaddr_in *netmask = (struct sockaddr_in *)&interfaceList[i].iiNetmask; + if(address->sin_family != AF_INET) + continue; + + unsigned long hostAddress = ntohl(address->sin_addr.s_addr); + unsigned long hostNetmask = ntohl(netmask->sin_addr.s_addr); + if(hostAddress == 0 || (hostAddress & 0xff000000) == 0x7f000000 || hostNetmask == 0) + continue; + + localAddresses[resultCount] = address->sin_addr; + broadcastAddresses[resultCount].s_addr = htonl(hostAddress | ~hostNetmask); + ++resultCount; + } + + return resultCount; +} +#endif bool NetworkSocketLayer::Initialize() { @@ -555,6 +599,9 @@ bool NetworkSocketLayer::JoinGame(const char *ip, int port) struct sockaddr_in addr = {}; +#if defined(__ORBIS__) + addr.sin_len = sizeof(addr); +#endif addr.sin_family = AF_INET; addr.sin_port = htons((uint16_t)port); @@ -597,15 +644,16 @@ bool NetworkSocketLayer::JoinGame(const char *ip, int port) #endif iResult = connect(s_hostConnectionSocket, (struct sockaddr*)&addr, sizeof(addr)); + int connectError = iResult < 0 ? LCE_NET_ERRNO : 0; if (iResult < 0) { #if defined(__PS3__) - int err = sys_net_errno; + int err = connectError; if (err == SYS_NET_EINPROGRESS) { #elif defined(__ORBIS__) - int err = sce_net_errno; - if (err == SCE_NET_EINPROGRESS) + int err = connectError; + if (err == EINPROGRESS) { #endif fd_set writeFds, exceptFds; @@ -1205,8 +1253,31 @@ int NetworkSocketLayer::AdvertiseThreadProc(LPVOID param) data.gameHostSettings = htonl(data.gameHostSettings); data.texturePackParentId = htonl(data.texturePackParentId); - int sent = sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0, + int sent = -1; + +#ifdef _WINDOWS64 + struct in_addr localAddresses[32]; + struct in_addr broadcastAddresses[32]; + int interfaceCount = GetLocalIPv4Interfaces(s_advertiseSock, localAddresses, broadcastAddresses, 32); + for(int i = 0; i < interfaceCount; ++i) + { + broadcastAddr.sin_addr = broadcastAddresses[i]; + int interfaceSent = sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0, + (struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr)); + if(interfaceSent != SOCKET_ERROR) + sent = interfaceSent; + } + + if(interfaceCount == 0) + { + broadcastAddr.sin_addr.s_addr = INADDR_BROADCAST; + sent = sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0, + (struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr)); + } +#else + sent = sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0, (struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr)); +#endif #if defined _WINDOWS64 || defined _XBOX if (sent == SOCKET_ERROR && s_advertising) diff --git a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp index 86b3806b..7d19b290 100644 --- a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp @@ -7,6 +7,7 @@ #include "..\..\MinecraftServer.h" #include "..\..\..\Minecraft.World\net.minecraft.world.level.h" #include "..\..\..\Minecraft.World\net.minecraft.world.h" +#include "..\..\Common\Network\WinsockNetLayer.h" #define UPDATE_PLAYERS_TIMER_ID 0 #define UPDATE_PLAYERS_TIMER_TIME 30000 @@ -50,7 +51,6 @@ void UIScene_JoinMenu::tick() g_NetworkManager.GetFullFriendSessionInfo(m_selectedSession, &friendSessionUpdated, this); m_friendInfoRequestIssued = true; } - if( m_friendInfoUpdatedOK ) { m_friendInfoUpdatedOK = false; @@ -368,6 +368,12 @@ void UIScene_JoinMenu::checkPrivilegeCallback(LPVOID lpParam, bool hasPrivilege, void UIScene_JoinMenu::StartSharedLaunchFlow() { + const bool bManualJoin = (g_Win64MultiplayerJoin == true); + if (bManualJoin) + { + JoinGame(this); + return; + } #if defined DISABLE_PSN JoinGame(this); #else @@ -421,6 +427,12 @@ int UIScene_JoinMenu::StartGame_SignInReturned(void *pParam,bool bContinue, int // Shared function to join the game that is the same whether we used the sign-in UI or not void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) { + if (pClass == NULL) + { + return; + } + const bool bManualJoin = (g_Win64MultiplayerJoin == true); + DWORD dwSignedInUsers = 0; bool noPrivileges = false; DWORD dwLocalUsersMask = 0; @@ -428,10 +440,14 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) int iPadNotSignedInLive = -1; ProfileManager.SetLockedProfile(0); // TEMP! + if (bManualJoin) + { + isSignedInLive = true; + } // If we're in SD mode, then only the primary player gets to play if (app.IsLocalMultiplayerAvailable()) - { + { for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) { if(ProfileManager.IsSignedIn(index)) @@ -442,7 +458,7 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) iPadNotSignedInLive = index; } - if( !ProfileManager.AllowedToPlayMultiplayer(index) ) noPrivileges = true; + if( !bManualJoin && !ProfileManager.AllowedToPlayMultiplayer(index) ) noPrivileges = true; dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(index); isSignedInLive = isSignedInLive && ProfileManager.IsSignedInLive(index); } @@ -452,7 +468,7 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) { if(ProfileManager.IsSignedIn(ProfileManager.GetPrimaryPad())) { - if( !ProfileManager.AllowedToPlayMultiplayer(ProfileManager.GetPrimaryPad()) ) noPrivileges = true; + if( !bManualJoin && !ProfileManager.AllowedToPlayMultiplayer(ProfileManager.GetPrimaryPad()) ) noPrivileges = true; dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(ProfileManager.GetPrimaryPad()); #ifndef DISABLE_PSN @@ -467,7 +483,7 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) } // If this is an online game but not all players are signed in to Live, stop! - if (!isSignedInLive) + if (!bManualJoin && !isSignedInLive) { #ifdef __ORBIS__ // Check if PSN is unavailable because of age restriction @@ -497,14 +513,22 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) BOOL pccFriendsAllowed = TRUE; #if !defined(DISABLE_PSN) && (defined(__PS3__) || defined(__PSVITA__)) - if(isSignedInLive) + if(!bManualJoin && isSignedInLive) { ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),false,&noUGC,NULL,NULL); } #else - ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); - if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + if(!bManualJoin) + { + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + } #endif + if (bManualJoin) + { + noUGC = false; + noPrivileges = false; + } #ifdef __PSVITA__ @@ -534,13 +558,16 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) ui.RequestErrorMessage( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad()); } else - { -#if defined(__ORBIS__) || defined(__PSVITA__) - bool chatRestricted = false; - ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),false,&chatRestricted,NULL,NULL); - if(chatRestricted) { - ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, ProfileManager.GetPrimaryPad() ); +#if defined(__ORBIS__) || defined(__PSVITA__) + if(!bManualJoin) + { + bool chatRestricted = false; + ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),false,&chatRestricted,NULL,NULL); + if(chatRestricted) + { + ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, ProfileManager.GetPrimaryPad() ); + } } #endif CGameNetworkManager::eJoinGameResult result = g_NetworkManager.JoinGame( pClass->m_selectedSession, dwLocalUsersMask ); @@ -550,6 +577,7 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) if( result != CGameNetworkManager::JOINGAME_SUCCESS ) { + pClass->m_bIgnoreInput = false; int exitReasonStringId = -1; switch(result) { @@ -643,4 +671,4 @@ void UIScene_JoinMenu::handleTimerComplete(int id) } break; }; -} \ No newline at end of file +} diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp index 39bba779..f977ff91 100644 --- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp @@ -14,6 +14,7 @@ #include "..\..\TexturePackRepository.h" #include "..\..\TexturePack.h" #include "..\Network\SessionInfo.h" +#include "..\..\Common\Network\WinsockNetLayer.h" #if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) #include "Common\Network\Sony\SonyHttp.h" #include "Common\Network\Sony\SonyRemoteStorage.h" @@ -1385,20 +1386,24 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex) if( m_buttonListGames.getItemCount() > 0 && gameIndex < m_currentSessions->size() ) { #if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) + const bool bManualJoin = (g_Win64MultiplayerJoin == true); // 4J-PB - is the player allowed to join games? bool noUGC=false; bool bContentRestricted=false; - // we're online, since we are joining a game - ProfileManager.GetChatAndContentRestrictions(m_iPad,true,&noUGC,&bContentRestricted,NULL); + // A direct LAN join should probnot use PSN matchmaking or account privileges (nansess) + if(!bManualJoin) + { + ProfileManager.GetChatAndContentRestrictions(m_iPad,true,&noUGC,&bContentRestricted,NULL); + } #ifdef __ORBIS__ // 4J Stu - On PS4 we don't restrict playing multiplayer based on chat restriction, so remove this check noUGC = false; bool bPlayStationPlus=true; - int iPadWithNoPlaystationPlus=0; - bool isSignedInLive = true; + int iPadWithNoPlaystationPlus=-1; + bool isSignedInLive = true; int iPadNotSignedInLive = -1; for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { @@ -1414,6 +1419,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex) if(ProfileManager.HasPlayStationPlus(i)==false) { bPlayStationPlus=false; + iPadWithNoPlaystationPlus = (int)i; break; } } @@ -1427,7 +1433,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex) } #endif - if(noUGC) + if(!bManualJoin && noUGC) { // not allowed to join #ifndef __PSVITA__ @@ -1443,7 +1449,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex) m_bIgnoreInput=false; return; } - else if(bContentRestricted) + else if(!bManualJoin && bContentRestricted) { ui.RequestContentRestrictedMessageBox(); @@ -1452,7 +1458,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex) } #ifdef __ORBIS__ // If this is an online game but not all players are signed in to Live, stop! - else if (!isSignedInLive) + else if (!bManualJoin && !isSignedInLive) { UINT uiIDA[1]; uiIDA[0]=IDS_CONFIRM_OK; @@ -1471,7 +1477,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex) } return; } - else if(bPlayStationPlus==false) + else if(!bManualJoin && bPlayStationPlus==false) { if(ProfileManager.RequestingPlaystationPlus(iPadWithNoPlaystationPlus)) @@ -1480,6 +1486,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex) UINT uiIDA[1]; uiIDA[0]=IDS_OK; ui.RequestAlertMessage(IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL); + m_bIgnoreInput=false; return; } diff --git a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp index c9251291..8de760b5 100644 --- a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp @@ -8,6 +8,7 @@ #include "UIScene_MainMenu.h" #ifdef __ORBIS__ #include +#include "..\..\Common\Network\WinsockNetLayer.h" #endif Random *UIScene_MainMenu::random = new Random(); @@ -318,7 +319,16 @@ void UIScene_MainMenu::handlePress(F64 controlId, F64 childId) //CD - Added for audio ui.PlayUISFX(eSFX_Press); - ProfileManager.RefreshChatAndContentRestrictions(RefreshChatAndContentRestrictionsReturned_PlayGame, this); + if(g_Win64MultiplayerJoin) + { + // request only completes after the platform network timeout. + // this needs to be done before hand or else the PS4 crashes ill need to look more into this + CreateLoad_SignInReturned(this, true, primaryPad); + } + else + { + ProfileManager.RefreshChatAndContentRestrictions(RefreshChatAndContentRestrictionsReturned_PlayGame, this); + } } #else m_eAction=eAction_RunGame; @@ -1098,6 +1108,12 @@ void UIScene_MainMenu::RefreshChatAndContentRestrictionsReturned_PlayGame(void * int primaryPad = ProfileManager.GetPrimaryPad(); UIScene_MainMenu* pClass = (UIScene_MainMenu*)pParam; + const bool bManualJoin = (g_Win64MultiplayerJoin == true); + if (bManualJoin) + { + CreateLoad_SignInReturned(pClass, true, primaryPad); + return; + } int (*signInReturnedFunc) (LPVOID,const bool, const int iPad) = NULL; diff --git a/Minecraft.Client/Minecraft.Client.vcxproj b/Minecraft.Client/Minecraft.Client.vcxproj index 50472670..0124434b 100644 --- a/Minecraft.Client/Minecraft.Client.vcxproj +++ b/Minecraft.Client/Minecraft.Client.vcxproj @@ -1015,7 +1015,8 @@ xcopy /q /y /i /s /e $(ProjectDir)DurangoMedia\CU $(LayoutDir)Image\Loose\CUfalse $(OutDir)$(ProjectName).pch MultiThreaded - _FINAL_BUILD;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) + + _LARGE_WORLDS;_EXTENDED_ACHIEVEMENTS;_FINAL_BUILD;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) Disabled Windows64\Iggy\include;$(ProjectDir);%(AdditionalIncludeDirectories) true @@ -36126,4 +36127,4 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU - \ No newline at end of file + diff --git a/Minecraft.Client/Orbis/OrbisExtras/OrbisStubs.cpp b/Minecraft.Client/Orbis/OrbisExtras/OrbisStubs.cpp index 1cc40be5..37924651 100644 --- a/Minecraft.Client/Orbis/OrbisExtras/OrbisStubs.cpp +++ b/Minecraft.Client/Orbis/OrbisExtras/OrbisStubs.cpp @@ -619,7 +619,6 @@ DWORD GetFileAttributesA(LPCSTR lpFileName) SceFiosStat statData; if(sceFiosStatSync(NULL, filePath, &statData) != SCE_FIOS_OK) { - app.DebugPrintf("*** sceFiosStatSync Failed\n"); return -1; } if(statData.statFlags & SCE_FIOS_STATUS_DIRECTORY ) @@ -671,19 +670,25 @@ BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount) #ifndef _FINAL_BUILD -VOID OutputDebugStringW(LPCWSTR lpOutputString) -{ - wprintf(lpOutputString); +VOID OutputDebugStringW(LPCWSTR lpOutputString) +{ + if (lpOutputString != NULL) + wprintf(L"%ls", lpOutputString); + fflush(stdout); } -VOID OutputDebugStringA(LPCSTR lpOutputString) -{ - printf(lpOutputString); +VOID OutputDebugStringA(LPCSTR lpOutputString) +{ + if (lpOutputString != NULL) + printf("%s", lpOutputString); + fflush(stdout); } -VOID OutputDebugString(LPCSTR lpOutputString) -{ - printf(lpOutputString); +VOID OutputDebugString(LPCSTR lpOutputString) +{ + if (lpOutputString != NULL) + printf("%s", lpOutputString); + fflush(stdout); } #endif // _CONTENT_PACKAGE @@ -787,4 +792,4 @@ DWORD XGetLocale() DWORD XEnableGuestSignin(BOOL fEnable) { return 0; -} \ No newline at end of file +} diff --git a/Minecraft.World/Minecraft.World.vcxproj b/Minecraft.World/Minecraft.World.vcxproj index f9105bc4..4d02015f 100644 --- a/Minecraft.World/Minecraft.World.vcxproj +++ b/Minecraft.World/Minecraft.World.vcxproj @@ -858,7 +858,7 @@ false $(OutDir)$(ProjectName).pch MultiThreaded - _FINAL_BUILD;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) + _LARGE_WORLDS;_EXTENDED_ACHIEVEMENTS;_FINAL_BUILD;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) Disabled true false