diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index c5d96ef8..d4fa38c5 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -1941,7 +1941,7 @@ void ClientConnection::handlePreLogin(shared_ptr packet) isAtLeastOneFriend = TRUE; cantPlayContentRestricted= FALSE; -#if ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__) +#if !defined DISABLE_PSN && ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__) if(!g_NetworkManager.IsHost() && !app.GetGameHostOption(eGameHostOption_FriendsOfFriends)) { diff --git a/Minecraft.Client/Common/App_structs.h b/Minecraft.Client/Common/App_structs.h index bcbd4cb4..2adec86f 100644 --- a/Minecraft.Client/Common/App_structs.h +++ b/Minecraft.Client/Common/App_structs.h @@ -162,7 +162,7 @@ MOJANG_DATA; typedef struct { eDLCContentType eDLCType; -#if defined( __PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +#if !defined(DISABLE_PSN) && defined( __PS3__) || defined(__ORBIS__) || defined (__PSVITA__) char chImageURL[256];//SCE_NP_COMMERCE2_URL_LEN #else diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp index 267ed587..ad5513bc 100644 --- a/Minecraft.Client/Common/Consoles_App.cpp +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -5094,6 +5094,9 @@ void CMinecraftApp::NotificationsCallback(LPVOID pParam,DWORD dwNotification, un #if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ int CMinecraftApp::MustSignInFullVersionPurchaseReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else if(result==C4JStorage::EMessage_ResultAccept) { #ifdef __PS3__ @@ -5106,11 +5109,15 @@ int CMinecraftApp::MustSignInFullVersionPurchaseReturned(void *pParam,int iPad,C } return 0; +#endif } #if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ int CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else if(result==C4JStorage::EMessage_ResultAccept) { #ifdef __PS3__ @@ -5126,6 +5133,7 @@ int CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial(void *pParam,i app.SetAction(iPad,eAppAction_ExitWorldTrial); return 0; +#endif } #endif @@ -6761,7 +6769,7 @@ wstring CMinecraftApp::GetIconReplacement(unsigned int uiIcon) #endif } -#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) unordered_map CMinecraftApp::MojangData; unordered_map CMinecraftApp::DLCTextures_PackID; unordered_map CMinecraftApp::DLCInfo; @@ -6772,6 +6780,12 @@ unordered_map CMinecraftApp::DLCTextures_PackID; // for mash-up //unordered_map CMinecraftApp::DLCInfo_Trial; // full offerid, dlc_info unordered_map CMinecraftApp::DLCInfo_Full; // full offerid, dlc_info unordered_map CMinecraftApp::DLCInfo_SkinName; // skin name, full offer id +#elif defined(DISABLE_PSN) && defined(__PS3__) +unordered_map CMinecraftApp::MojangData; +unordered_map CMinecraftApp::DLCTextures_PackID; +unordered_map CMinecraftApp::DLCInfo_Trial; +unordered_map CMinecraftApp::DLCInfo_Full; +unordered_map CMinecraftApp::DLCInfo_SkinName; #else unordered_map CMinecraftApp::MojangData; unordered_map CMinecraftApp::DLCTextures_PackID; @@ -6854,7 +6868,7 @@ HRESULT CMinecraftApp::RegisterConfigValues(WCHAR *pType, int iValue) return hr; } -#if (defined _XBOX || defined _WINDOWS64) +#if (defined _XBOX || defined _WINDOWS64 || defined DISABLE_PSN) HRESULT CMinecraftApp::RegisterDLCData(WCHAR *pType, WCHAR *pBannerName, int iGender, __uint64 ullOfferID_Full, __uint64 ullOfferID_Trial, WCHAR *pFirstSkin, unsigned int uiSortIndex, int iConfig, WCHAR *pDataFile) { HRESULT hr=S_OK; @@ -7046,7 +7060,7 @@ HRESULT CMinecraftApp::RegisterDLCData(char *pchDLCName, unsigned int uiSortInde -#if defined( __PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined( __PS3__) || defined(__ORBIS__) || defined(__PSVITA__) bool CMinecraftApp::GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal) { AUTO_VAR(it, DLCInfo_SkinName.find(FirstSkin)); @@ -7314,7 +7328,7 @@ DLC_INFO *CMinecraftApp::GetDLCInfoForProductName(WCHAR *pwchProductName) return NULL; } -#elif defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +#elif !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) #else DLC_INFO *CMinecraftApp::GetDLCInfoForFullOfferID(ULONGLONG ullOfferID_Full) @@ -9425,7 +9439,7 @@ byteArray CMinecraftApp::getArchiveFile(const wstring &filename) // DLC -#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) int CMinecraftApp::GetDLCInfoCount() { return (int)DLCInfo.size(); diff --git a/Minecraft.Client/Common/Consoles_App.h b/Minecraft.Client/Common/Consoles_App.h index 34106437..3bae77c3 100644 --- a/Minecraft.Client/Common/Consoles_App.h +++ b/Minecraft.Client/Common/Consoles_App.h @@ -594,7 +594,7 @@ public: MOJANG_DATA *GetMojangDataForXuid(PlayerUID xuid); static HRESULT RegisterConfigValues(WCHAR *pType, int iValue); -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) HRESULT RegisterDLCData(char *pchDLCName, unsigned int uiSortIndex, char *pchImageURL); bool GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal); DLC_INFO *GetDLCInfoForTrialOfferID(ULONGLONG ullOfferID_Trial); @@ -631,7 +631,7 @@ private: std::vector vDLCCredits; -#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) static unordered_map MojangData; static unordered_map DLCTextures_PackID; // for mash-up packs & texture packs static unordered_map DLCInfo; @@ -642,6 +642,12 @@ private: //static unordered_map DLCInfo_Trial; // full offerid, dlc_info static unordered_map DLCInfo_Full; // full offerid, dlc_info static unordered_map DLCInfo_SkinName; // skin name, full offer id +#elif defined(DISABLE_PSN) && defined(__PS3__) + static unordered_map MojangData; + static unordered_map DLCTextures_PackID; // for mash-up packs & texture packs + static unordered_map DLCInfo_Trial; // full offerid, dlc_info + static unordered_map DLCInfo_Full; // full offerid, dlc_info + static unordered_map DLCInfo_SkinName; // skin name, full offer id #else static unordered_map MojangData; static unordered_map DLCTextures_PackID; // for mash-up packs & texture packs @@ -772,7 +778,7 @@ public: void ClearTMSPPFilesRetrieved(); unsigned int AddTMSPPFileTypeRequest(eDLCContentType eType, bool bPromote=false); int GetDLCInfoTexturesOffersCount(); -#if defined( __PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined( __PS3__) || defined(__ORBIS__) || defined(__PSVITA__) DLC_INFO *GetDLCInfo(int iIndex); DLC_INFO *GetDLCInfo(char *); DLC_INFO *GetDLCInfoFromTPackID(int iTPID); diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Common/Network/GameNetworkManager.cpp index 4f0e5ab7..490d0e0d 100644 --- a/Minecraft.Client/Common/Network/GameNetworkManager.cpp +++ b/Minecraft.Client/Common/Network/GameNetworkManager.cpp @@ -68,7 +68,7 @@ void CGameNetworkManager::Initialise() int flagIndexSize = LevelRenderer::getGlobalChunkCount() / (Level::maxBuildHeight / 16); // dividing here by number of renderer chunks in one column #ifdef _XBOX s_pPlatformNetworkManager = new CPlatformNetworkManagerXbox(); -#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ +#elif !defined(DISABLE_PSN) && defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ s_pPlatformNetworkManager = new CPlatformNetworkManagerSony(); #elif defined _DURANGO s_pPlatformNetworkManager = new CPlatformNetworkManagerDurango(); @@ -167,6 +167,11 @@ bool CGameNetworkManager::_RunNetworkGame(LPVOID lpParameter) return true; } } + else + { + // Client needs QNET_STATE_GAME_PLAY so that IsInGameplay() returns true + s_pPlatformNetworkManager->SetGamePlayState(); + } if( g_NetworkManager.IsLeavingGame() ) return false; @@ -336,10 +341,12 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame // 4J Stu - Wait a while to make sure that DLC is loaded. This is the last point before the network communication starts // so the latest we can check this +#ifndef DISABLE_PSN while( !app.DLCInstallProcessCompleted() && app.DLCInstallPending() && !g_NetworkManager.IsLeavingGame() ) { Sleep( 10 ); } +#endif if( g_NetworkManager.IsLeavingGame() ) { MinecraftServer::HaltServer(); @@ -496,7 +503,7 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame // The connections should tick at 20 per second Sleep(50); app.DebugPrintf("<***> %d %d %d %d %d\n",IsInSession(), !connection->isStarted(),!connection->isClosed(),ProfileManager.IsSignedIn(idx),!g_NetworkManager.IsLeavingGame()); -#if defined _XBOX || __PS3__ +#if defined _XBOX || defined __PS3__ && !defined DISABLE_PSN } while (IsInSession() && !connection->isStarted() && !connection->isClosed() && ProfileManager.IsSignedIn(idx) && !g_NetworkManager.IsLeavingGame() ); #else // TODO - This SHOULD be something just like the code above but temporarily changing here so that we don't have to depend on the profilemanager behaviour @@ -794,7 +801,7 @@ int CGameNetworkManager::JoinFromInvite_SignInReturned(void *pParam,bool bContin // Check if user-created content is allowed, as we cannot play multiplayer if it's not bool noUGC = false; -#if defined(__PS3__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__PSVITA__) ProfileManager.GetChatAndContentRestrictions(iPad,false,&noUGC,NULL,NULL); #elif defined(__ORBIS__) ProfileManager.GetChatAndContentRestrictions(iPad,false,NULL,&noUGC,NULL); @@ -1007,6 +1014,9 @@ int CGameNetworkManager::ExitAndJoinFromInviteThreadProc( void* lpParam ) // The pair of methods MustSignInReturned_0 & PSNSignInReturned_0 handle this int CGameNetworkManager::MustSignInReturned_0(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else if(result==C4JStorage::EMessage_ResultAccept) { #ifdef __PS3__ @@ -1025,10 +1035,14 @@ int CGameNetworkManager::MustSignInReturned_0(void *pParam,int iPad,C4JStorage:: } return 0; +#endif } int CGameNetworkManager::PSNSignInReturned_0(void* pParam, bool bContinue, int iPad) { +#ifdef DISABLE_PSN + return 0; +#else JoinFromInviteData *inviteData = (JoinFromInviteData *)pParam; // If the invite data isn't set up yet (indicated by it being all zeroes, easiest detected via the net version), then try and get it again... this can happen if we got @@ -1061,12 +1075,16 @@ int CGameNetworkManager::PSNSignInReturned_0(void* pParam, bool bContinue, int i } return 0; +#endif } // This case happens when we were in the main menus when we got an invite, and weren't signed in... now can proceed with the normal flow of code for this situation // The pair of methods MustSignInReturned_1 & PSNSignInReturned_1 handle this int CGameNetworkManager::MustSignInReturned_1(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else if(result==C4JStorage::EMessage_ResultAccept) { #ifdef __PS3__ @@ -1078,10 +1096,14 @@ int CGameNetworkManager::MustSignInReturned_1(void *pParam,int iPad,C4JStorage:: #endif } return 0; +#endif } int CGameNetworkManager::PSNSignInReturned_1(void* pParam, bool bContinue, int iPad) { +#ifdef DISABLE_PSN + return 0; +#else INVITE_INFO *inviteInfo = (INVITE_INFO *)pParam; // If the invite data isn't set up yet (indicated by it being all zeroes, easiest detected via the net version), then try and get it again... this can happen if we got @@ -1109,6 +1131,7 @@ int CGameNetworkManager::PSNSignInReturned_1(void* pParam, bool bContinue, int i } return 0; +#endif } #endif @@ -1446,7 +1469,7 @@ void CGameNetworkManager::StateChange_AnyToEnding(bool bStateWasPlaying) if(pNetworkPlayer != NULL && ProfileManager.IsSignedIn( i ) ) { app.DebugPrintf("Stats save for an offline game for the player at index %d\n", i ); - Minecraft::GetInstance()->forceStatsSave(pNetworkPlayer->GetUserIndex()); + //Minecraft::GetInstance()->forceStatsSave(pNetworkPlayer->GetUserIndex()); } } } @@ -1789,7 +1812,7 @@ void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO * #endif if( !g_NetworkManager.IsInSession() ) { -#if defined (__PS3__) || defined (__PSVITA__) +#if !defined(DISABLE_PSN) && defined (__PS3__) || defined (__PSVITA__) // PS3 is more complicated here - we need to make sure that the player is online. If they are then we can do the same as the xbox, if not we need to try and get them online and then, if they do sign in, go down the same path // Determine why they're not "signed in live" @@ -1939,7 +1962,7 @@ void CGameNetworkManager::HandleDisconnect(bool bLostRoomOnly) if((g_NetworkManager.GetLockedProfile()!=-1) && iPrimaryPlayer!=-1 && g_NetworkManager.IsInSession() ) { m_bLastDisconnectWasLostRoomOnly = bLostRoomOnly; -#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ +#if !defined(DISABLE_PSN) && defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ m_bSignedOutofPSN=bPSNSignout; #endif app.SetAction(iPrimaryPlayer,eAppAction_EthernetDisconnected); diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.h b/Minecraft.Client/Common/Network/GameNetworkManager.h index 2eda05c0..0e85c59c 100644 --- a/Minecraft.Client/Common/Network/GameNetworkManager.h +++ b/Minecraft.Client/Common/Network/GameNetworkManager.h @@ -6,7 +6,7 @@ using namespace std; #include "NetworkPlayerInterface.h" #ifdef _XBOX #include "..\..\Xbox\Network\PlatformNetworkManagerXbox.h" -#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ +#elif !defined DISABLE_PSN && defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ #include "..\..\Common\Network\Sony\PlatformNetworkManagerSony.h" #elif defined _DURANGO #include "..\..\Durango\Network\PlatformNetworkManagerDurango.h" @@ -32,7 +32,7 @@ class CGameNetworkManager { #ifdef _XBOX friend class CPlatformNetworkManagerXbox; -#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ +#elif !defined DISABLE_PSN && defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ friend class CPlatformNetworkManagerSony; #elif defined _DURANGO friend class CPlatformNetworkManagerDurango; diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h b/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h index a13443d1..d14e5fbf 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h @@ -84,7 +84,7 @@ public: virtual void HandleSignInChange() = 0; virtual bool _RunNetworkGame() = 0; - + virtual void SetGamePlayState() {} private: virtual bool _LeaveGame(bool bMigrateHost, bool bLeaveRoom) = 0; virtual void _HostGame(int usersMask, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0) = 0; diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp index 2c434d3c..21b26b7c 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -3,6 +3,11 @@ #include "..\..\..\Minecraft.World\StringHelpers.h" #include "PlatformNetworkManagerStub.h" #include "..\..\Xbox\Network\NetworkPlayerXbox.h" // TODO - stub version of this? +#include "..\..\Minecraft.h" +#include "..\..\User.h" +#if defined _WINDOWS64 || defined __PS3__ +#include "..\..\Common\Network\WinsockNetLayer.h" +#endif CPlatformNetworkManagerStub *g_pPlatformNetworkManager; @@ -114,10 +119,42 @@ void CPlatformNetworkManagerStub::NotifyPlayerJoined(IQNetPlayer *pQNetPlayer ) } } +void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer *pQNetPlayer) +{ + app.DebugPrintf("Player 0x%p \"%ls\" leaving.\n", pQNetPlayer, pQNetPlayer->GetGamertag()); + + INetworkPlayer *networkPlayer = getNetworkPlayer(pQNetPlayer); + if (networkPlayer == NULL) + return; + + Socket *socket = networkPlayer->GetSocket(); + if (socket != NULL) + { + if (m_pIQNet->IsHost()) + g_NetworkManager.CloseConnection(networkPlayer); + } + + if (m_pIQNet->IsHost()) + { + SystemFlagRemovePlayer(networkPlayer); + } + + g_NetworkManager.PlayerLeaving(networkPlayer); + + for (int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if (playerChangedCallback[idx] != NULL) + playerChangedCallback[idx](playerChangedCallbackParam[idx], networkPlayer, true); + } + + removeNetworkPlayer(pQNetPlayer); +} + bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkManager, int flagIndexSize) { m_pGameNetworkManager = pGameNetworkManager; m_flagIndexSize = flagIndexSize; + m_pIQNet = new IQNet(); g_pPlatformNetworkManager = this; for( int i = 0; i < XUSER_MAX_COUNT; i++ ) { @@ -174,6 +211,35 @@ bool CPlatformNetworkManagerStub::isSystemPrimaryPlayer(IQNetPlayer *pQNetPlayer // We call this twice a frame, either side of the render call so is a good place to "tick" things void CPlatformNetworkManagerStub::DoWork() { + extern QNET_STATE _iQNetStubState; + if (_iQNetStubState == QNET_STATE_SESSION_STARTING && app.GetGameStarted()) + { + _iQNetStubState = QNET_STATE_GAME_PLAY; + if (m_pIQNet->IsHost()) + WinsockNetLayer::UpdateAdvertiseJoinable(true); + } + if (_iQNetStubState == QNET_STATE_IDLE) + TickSearch(); + if (_iQNetStubState == QNET_STATE_GAME_PLAY && m_pIQNet->IsHost()) + { + BYTE disconnectedSmallId; + while (WinsockNetLayer::PopDisconnectedSmallId(&disconnectedSmallId)) + { + IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(disconnectedSmallId); + if (qnetPlayer != NULL && qnetPlayer->m_smallId == disconnectedSmallId) + { + NotifyPlayerLeaving(qnetPlayer); + qnetPlayer->m_smallId = 0; + qnetPlayer->m_isRemote = false; + qnetPlayer->m_isHostPlayer = false; + qnetPlayer->m_gamertag[0] = 0; + qnetPlayer->SetCustomDataValue(0); + WinsockNetLayer::PushFreeSmallId(disconnectedSmallId); + if (IQNet::s_playerCount > 1) + IQNet::s_playerCount--; + } + } + } } int CPlatformNetworkManagerStub::GetPlayerCount() @@ -231,6 +297,7 @@ bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost) if( m_bLeavingGame ) return true; m_bLeavingGame = true; + WinsockNetLayer::StopAdvertising(); // If we are the host wait for the game server to end if(m_pIQNet->IsHost() && g_NetworkManager.ServerStoppedValid()) @@ -239,6 +306,20 @@ bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost) g_NetworkManager.ServerStoppedWait(); g_NetworkManager.ServerStoppedDestroy(); } + else + { + m_pIQNet->EndGame(); + } + + for (AUTO_VAR(it, currentNetworkPlayers.begin()); it != currentNetworkPlayers.end(); it++) + delete *it; + currentNetworkPlayers.clear(); + m_machineQNetPrimaryPlayers.clear(); + SystemFlagReset(); + + WinsockNetLayer::Shutdown(); + WinsockNetLayer::Initialize(); + return true; } @@ -262,7 +343,20 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame, m_pIQNet->HostGame(); + IQNet::m_player[0].m_smallId = 0; + IQNet::m_player[0].m_isRemote = false; + IQNet::m_player[0].m_isHostPlayer = true; + IQNet::s_playerCount = 1; + _HostGame( localUsersMask, publicSlots, privateSlots ); + + int port = WIN64_NET_DEFAULT_PORT; + if (!WinsockNetLayer::IsActive()) + WinsockNetLayer::HostGame(port); + + const wchar_t *hostName = IQNet::m_player[0].m_gamertag; + unsigned int settings = app.GetGameHostOption(eGameHostOption_All); + WinsockNetLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION); //#endif } @@ -277,6 +371,47 @@ bool CPlatformNetworkManagerStub::_StartGame() int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo *searchResult, int localUsersMask, int primaryUserIndex) { + if (searchResult == NULL) + return CGameNetworkManager::JOINGAME_FAIL_GENERAL; + + const char *hostIP = searchResult->data.hostIP; + int hostPort = searchResult->data.hostPort; + + if (hostPort <= 0 || hostIP[0] == 0) + return CGameNetworkManager::JOINGAME_FAIL_GENERAL; + + m_bLeavingGame = false; + IQNet::s_isHosting = false; + m_pIQNet->ClientJoinGame(); + + IQNet::m_player[0].m_smallId = 0; + IQNet::m_player[0].m_isRemote = true; + IQNet::m_player[0].m_isHostPlayer = true; + wcsncpy(IQNet::m_player[0].m_gamertag, searchResult->data.hostName, 31); + + WinsockNetLayer::StopDiscovery(); + + if (!WinsockNetLayer::JoinGame(hostIP, hostPort)) + { + app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort); + return CGameNetworkManager::JOINGAME_FAIL_GENERAL; + } + + BYTE localSmallId = WinsockNetLayer::GetLocalSmallId(); + + IQNet::m_player[localSmallId].m_smallId = localSmallId; + IQNet::m_player[localSmallId].m_isRemote = false; + IQNet::m_player[localSmallId].m_isHostPlayer = false; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + wcsncpy(IQNet::m_player[localSmallId].m_gamertag, pMinecraft->user->name.c_str(), 32); + IQNet::s_playerCount = localSmallId + 1; + + NotifyPlayerJoined(&IQNet::m_player[0]); + NotifyPlayerJoined(&IQNet::m_player[localSmallId]); + + m_pGameNetworkManager->StateChange_AnyToStarting(); + return CGameNetworkManager::JOINGAME_SUCCESS; } @@ -315,6 +450,21 @@ void CPlatformNetworkManagerStub::HandleSignInChange() bool CPlatformNetworkManagerStub::_RunNetworkGame() { + extern QNET_STATE _iQNetStubState; + _iQNetStubState = QNET_STATE_GAME_PLAY; + + for (DWORD i = 0; i < IQNet::s_playerCount; i++) + { + if (IQNet::m_player[i].m_isRemote) + { + INetworkPlayer *pNetworkPlayer = getNetworkPlayer(&IQNet::m_player[i]); + if (pNetworkPlayer != NULL && pNetworkPlayer->GetSocket() != NULL) + { + Socket::addIncomingSocket(pNetworkPlayer->GetSocket()); + } + } + } + return true; } @@ -503,10 +653,90 @@ wstring CPlatformNetworkManagerStub::GatherRTTStats() void CPlatformNetworkManagerStub::TickSearch() { + if (m_SessionsUpdatedCallback == NULL) + return; + + static DWORD lastSearchTime = 0; + DWORD now = GetTickCount(); + if (now - lastSearchTime < 2000) + return; + lastSearchTime = now; + + SearchForGames(); } void CPlatformNetworkManagerStub::SearchForGames() { + std::vector lanSessions = WinsockNetLayer::GetDiscoveredSessions(); + + if (g_Win64MultiplayerJoin) + { + bool alreadyPresent = false; + for (size_t i = 0; i < lanSessions.size(); i++) + { + if (strcmp(lanSessions[i].hostIP, g_Win64MultiplayerIP) == 0 && + lanSessions[i].hostPort == g_Win64MultiplayerPort) + { + alreadyPresent = true; + break; + } + } + if (!alreadyPresent) + { + Win64LANSession manual; + memset(&manual, 0, sizeof(manual)); + strncpy(manual.hostIP, g_Win64MultiplayerIP, sizeof(manual.hostIP) - 1); + manual.hostIP[sizeof(manual.hostIP) - 1] = '\0'; + + manual.hostPort = g_Win64MultiplayerPort; + + swprintf(manual.hostName, 32, L"%hs:%d", g_Win64MultiplayerIP, g_Win64MultiplayerPort); + manual.hostName[31] = L'\0'; + manual.playerCount = 0; + manual.maxPlayers = MINECRAFT_NET_MAX_PLAYERS; + manual.isJoinable = true; + manual.lastSeenTick = GetTickCount(); + lanSessions.push_back(manual); + } + } + + for (size_t i = 0; i < friendsSessions[0].size(); i++) + delete friendsSessions[0][i]; + friendsSessions[0].clear(); + + for (size_t i = 0; i < lanSessions.size(); i++) + { + FriendSessionInfo *info = new FriendSessionInfo(); + size_t nameLen = wcslen(lanSessions[i].hostName); + info->displayLabel = new wchar_t[nameLen + 1]; + wcsncpy(info->displayLabel, lanSessions[i].hostName, nameLen); + info->displayLabel[nameLen] = L'\0'; + info->displayLabelLength = (unsigned char)nameLen; + info->displayLabelViewableStartIndex = 0; + + info->data.netVersion = lanSessions[i].netVersion; + info->data.m_uiGameHostSettings = lanSessions[i].gameHostSettings; + info->data.texturePackParentId = lanSessions[i].texturePackParentId; + info->data.subTexturePackId = lanSessions[i].subTexturePackId; + info->data.isReadyToJoin = lanSessions[i].isJoinable; + info->data.isJoinable = lanSessions[i].isJoinable; + strncpy(info->data.hostIP, lanSessions[i].hostIP, sizeof(info->data.hostIP) - 1); + info->data.hostIP[sizeof(info->data.hostIP) - 1] = '\0'; + info->data.hostPort = lanSessions[i].hostPort; + wcsncpy(info->data.hostName, lanSessions[i].hostName, XUSER_NAME_SIZE - 1); + info->data.hostName[XUSER_NAME_SIZE - 1] = L'\0'; + info->data.playerCount = lanSessions[i].playerCount; + info->data.maxPlayers = lanSessions[i].maxPlayers; + + info->sessionId = (ULONGLONG)((unsigned __int64)inet_addr(lanSessions[i].hostIP) | ((unsigned __int64)lanSessions[i].hostPort << 32)); + + friendsSessions[0].push_back(info); + } + + m_searchResultsCount[0] = (int)friendsSessions[0].size(); + + if (m_SessionsUpdatedCallback != NULL) + m_SessionsUpdatedCallback(m_pSearchParam); } int CPlatformNetworkManagerStub::SearchForGamesThreadProc( void* lpParameter ) @@ -522,7 +752,9 @@ void CPlatformNetworkManagerStub::SetSearchResultsReady(int resultCount) vector *CPlatformNetworkManagerStub::GetSessionList(int iPad, int localPlayers, bool partyOnly) { - vector *filteredList = new vector();; + vector *filteredList = new vector(); + for (size_t i = 0; i < friendsSessions[0].size(); i++) + filteredList->push_back(friendsSessions[0][i]); return filteredList; } diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h index a45a5e47..10215a01 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h @@ -23,7 +23,11 @@ public: virtual bool RemoveLocalPlayerByUserIndex( int userIndex ); virtual INetworkPlayer *GetLocalPlayerByUserIndex( int userIndex ); virtual INetworkPlayer *GetPlayerByIndex(int playerIndex); +#ifdef __PS3 + virtual INetworkPlayer * GetPlayerByXuid(PlayerUID* xuid) +#else virtual INetworkPlayer * GetPlayerByXuid(PlayerUID xuid); +#endif virtual INetworkPlayer * GetPlayerBySmallId(unsigned char smallId); virtual bool ShouldMessageForFullSession(); @@ -161,8 +165,9 @@ public: virtual void GetFullFriendSessionInfo( FriendSessionInfo *foundSession, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ); virtual void ForceFriendsSessionRefresh(); -private: +public: void NotifyPlayerJoined( IQNetPlayer *pQNetPlayer ); + void NotifyPlayerLeaving( IQNetPlayer *pQNetPlayer ); #ifndef _XBOX void FakeLocalPlayerJoined() { NotifyPlayerJoined(m_pIQNet->GetLocalPlayerByUserIndex(0)); } diff --git a/Minecraft.Client/Common/Network/SessionInfo.h b/Minecraft.Client/Common/Network/SessionInfo.h index ec5c4910..d029973d 100644 --- a/Minecraft.Client/Common/Network/SessionInfo.h +++ b/Minecraft.Client/Common/Network/SessionInfo.h @@ -32,7 +32,7 @@ typedef struct _GameSessionData subTexturePackId = 0; } } GameSessionData; -#elif defined __PS3__ || defined __ORBIS__ || defined(__PSVITA__) +#elif (defined __PS3__ && !defined DISABLE_PSN) || defined __ORBIS__ || defined(__PSVITA__) typedef struct _GameSessionData { unsigned short netVersion; // 2 bytes @@ -47,6 +47,11 @@ typedef struct _GameSessionData unsigned char playerCount; // 1 byte bool isReadyToJoin; // 1 byte + char hostIP[64]; // 64 bytes + int hostPort; // 4 bytes + wchar_t hostName[XUSER_NAME_SIZE]; // 64 bytes ( 32*2 ) + unsigned char maxPlayers; // 1 byte + _GameSessionData() { netVersion = 0; @@ -57,7 +62,11 @@ typedef struct _GameSessionData subTexturePackId = 0; playerCount = 0; isReadyToJoin = false; - + memset(hostIP, 0, sizeof(hostIP)); + hostPort = 0; + memset(hostName, 0, sizeof(hostName)); + playerCount = 0; + maxPlayers = MINECRAFT_NET_MAX_PLAYERS; } } GameSessionData; #else @@ -69,6 +78,13 @@ typedef struct _GameSessionData unsigned char subTexturePackId; // 1 byte bool isReadyToJoin; // 1 byte + bool isJoinable; // 1 byte + + char hostIP[64]; // 64 bytes + int hostPort; // 4 bytes + wchar_t hostName[XUSER_NAME_SIZE]; // 64 bytes ( 32*2 ) + unsigned char playerCount; // 1 byte + unsigned char maxPlayers; // 1 byte _GameSessionData() { @@ -76,6 +92,13 @@ typedef struct _GameSessionData m_uiGameHostSettings = 0; texturePackParentId = 0; subTexturePackId = 0; + isReadyToJoin = false; + isJoinable = true; + memset(hostIP, 0, sizeof(hostIP)); + hostPort = 0; + memset(hostName, 0, sizeof(hostName)); + playerCount = 0; + maxPlayers = MINECRAFT_NET_MAX_PLAYERS; } } GameSessionData; #endif @@ -86,7 +109,7 @@ public: SessionID sessionId; #ifdef _XBOX XSESSION_SEARCHRESULT searchResult; -#elif defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +#elif (defined __PS3__ && !defined DISABLE_PSN) || defined(__ORBIS__) || defined (__PSVITA__) SQRNetworkManager::SessionSearchResult searchResult; #elif defined(_DURANGO) DQRNetworkManager::SessionSearchResult searchResult; diff --git a/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.cpp b/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.cpp index 2908cd08..bad40654 100644 --- a/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.cpp +++ b/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "NetworkPlayerSony.h" +#ifndef DISABLE_PSN NetworkPlayerSony::NetworkPlayerSony(SQRNetworkPlayer *qnetPlayer) { @@ -135,3 +136,4 @@ int NetworkPlayerSony::GetTimeSinceLastChunkPacket_ms() __int64 currentTime = System::currentTimeMillis(); return (int)( currentTime - m_lastChunkPacketTime ); } +#endif \ No newline at end of file diff --git a/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.h b/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.h index 1e18f4b9..d4ae12fb 100644 --- a/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.h +++ b/Minecraft.Client/Common/Network/Sony/NetworkPlayerSony.h @@ -1,5 +1,5 @@ #pragma once - +#ifndef _DISABLE_PSN #include "..\..\Common\Network\NetworkPlayerInterface.h" #include "SQRNetworkPlayer.h" @@ -41,3 +41,4 @@ private: Socket *m_pSocket; __int64 m_lastChunkPacketTime; }; +#endif \ No newline at end of file diff --git a/Minecraft.Client/Common/Network/Sony/SQRNetworkManager.cpp b/Minecraft.Client/Common/Network/Sony/SQRNetworkManager.cpp index 66193dd5..1e33f260 100644 --- a/Minecraft.Client/Common/Network/Sony/SQRNetworkManager.cpp +++ b/Minecraft.Client/Common/Network/Sony/SQRNetworkManager.cpp @@ -1,5 +1,5 @@ #include "stdafx.h" - +#ifndef DISABLE_PSN #include "SQRNetworkManager.h" bool SQRNetworkManager::s_safeToRespondToGameBootInvite = false; @@ -80,4 +80,5 @@ void SQRNetworkManager::TickWriteAcks() } } LeaveCriticalSection(&m_csAckQueue); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp b/Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp index 9879aec1..9c486bd4 100644 --- a/Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp +++ b/Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#ifndef DISABLE_PSN #include "SQRNetworkPlayer.h" #ifdef __PS3__ @@ -609,3 +610,4 @@ bool SQRNetworkPlayer::IsMutedByLocalUser(int userIndex) return SonyVoiceChat::isMutedPlayer(pMan->m_roomSyncData.players[userIndex].m_roomMemberId); #endif } +#endif \ No newline at end of file diff --git a/Minecraft.Client/Common/Network/WinsockNetLayer.cpp b/Minecraft.Client/Common/Network/WinsockNetLayer.cpp new file mode 100644 index 00000000..3172609a --- /dev/null +++ b/Minecraft.Client/Common/Network/WinsockNetLayer.cpp @@ -0,0 +1,1073 @@ +#include "stdafx.h" + +#include "WinsockNetLayer.h" +#include "..\..\Common\Network\PlatformNetworkManagerStub.h" +#include "..\..\..\Minecraft.World\Socket.h" + +#if defined _WINDOWS64 +SOCKET WinsockNetLayer::s_listenSocket = INVALID_SOCKET; +SOCKET WinsockNetLayer::s_hostConnectionSocket = INVALID_SOCKET; +SOCKET WinsockNetLayer::s_advertiseSock = INVALID_SOCKET; +SOCKET WinsockNetLayer::s_discoverySock = INVALID_SOCKET; +#elif defined __PS3__ +SOCKET WinsockNetLayer::s_listenSocket = -1; +SOCKET WinsockNetLayer::s_hostConnectionSocket = -1; +SOCKET WinsockNetLayer::s_advertiseSock = -1; +SOCKET WinsockNetLayer::s_discoverySock = -1; + +int closesocket(int s) { return socketclose(s); }; +void WSACleanup() {}; +#endif + +C4JThread* WinsockNetLayer::s_acceptThread = NULL; +C4JThread* WinsockNetLayer::s_clientRecvThread = NULL; + +bool WinsockNetLayer::s_isHost = false; +bool WinsockNetLayer::s_connected = false; +bool WinsockNetLayer::s_active = false; +bool WinsockNetLayer::s_initialized = false; + +BYTE WinsockNetLayer::s_localSmallId = 0; +BYTE WinsockNetLayer::s_hostSmallId = 0; +BYTE WinsockNetLayer::s_nextSmallId = 1; + +CRITICAL_SECTION WinsockNetLayer::s_sendLock; +CRITICAL_SECTION WinsockNetLayer::s_connectionsLock; + +std::vector WinsockNetLayer::s_connections; + +C4JThread* WinsockNetLayer::s_advertiseThread = NULL; +volatile bool WinsockNetLayer::s_advertising = false; +Win64LANBroadcast WinsockNetLayer::s_advertiseData = {}; +CRITICAL_SECTION WinsockNetLayer::s_advertiseLock; +int WinsockNetLayer::s_hostGamePort = WIN64_NET_DEFAULT_PORT; + +C4JThread* WinsockNetLayer::s_discoveryThread = NULL; +volatile bool WinsockNetLayer::s_discovering = false; +CRITICAL_SECTION WinsockNetLayer::s_discoveryLock; +std::vector WinsockNetLayer::s_discoveredSessions; + +CRITICAL_SECTION WinsockNetLayer::s_disconnectLock; +std::vector WinsockNetLayer::s_disconnectedSmallIds; + +CRITICAL_SECTION WinsockNetLayer::s_freeSmallIdLock; +std::vector WinsockNetLayer::s_freeSmallIds; + +bool g_Win64MultiplayerHost = false; +bool g_Win64MultiplayerJoin = true; +int g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT; +char g_Win64MultiplayerIP[256] = "127.0.0.1"; + +bool WinsockNetLayer::Initialize() +{ + if (s_initialized) return true; +#if defined _WINDOWS64 + WSADATA wsaData; + int result = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (result != 0) + { + app.DebugPrintf("WSAStartup failed: %d\n", result); + return false; + } +#elif defined __PS3__ + int result = sys_net_initialize_network(); + if (result != 0) { + app.DebugPrintf("sys_net_initialize_network failed: %d\n", result); + return false; + } + + result = cellNetCtlInit(); + if (result < 0) { + app.DebugPrintf("cellNetCtlInit failed: %d\n", result); + sys_net_finalize_network(); + return false; + } +#endif + + InitializeCriticalSection(&s_sendLock); + InitializeCriticalSection(&s_connectionsLock); + InitializeCriticalSection(&s_advertiseLock); + InitializeCriticalSection(&s_discoveryLock); + InitializeCriticalSection(&s_disconnectLock); + InitializeCriticalSection(&s_freeSmallIdLock); + + s_initialized = true; + + StartDiscovery(); + + return true; +} + +void WinsockNetLayer::Shutdown() +{ + StopAdvertising(); + StopDiscovery(); + + s_active = false; + s_connected = false; + +#if defined _WINDOWS64 + if (s_listenSocket != INVALID_SOCKET) + { + closesocket(s_listenSocket); + s_listenSocket = INVALID_SOCKET; + } + + if (s_hostConnectionSocket != INVALID_SOCKET) + { + closesocket(s_hostConnectionSocket); + s_hostConnectionSocket = INVALID_SOCKET; + } +#elif defined __PS3__ + if (s_listenSocket >= 0) + { + socketclose(s_listenSocket); + s_listenSocket = -1; + } + + if (s_hostConnectionSocket >= 0) + { + socketclose(s_hostConnectionSocket); + s_hostConnectionSocket = -1; + } +#endif + + EnterCriticalSection(&s_connectionsLock); + + for (size_t i = 0; i < s_connections.size(); i++) + { + s_connections[i].active = false; +#if defined _WINDOWS64 + if (s_connections[i].tcpSocket != INVALID_SOCKET) +#elif defined __PS3__ + if (s_connections[i].tcpSocket >= 0) +#endif + { + closesocket(s_connections[i].tcpSocket); + } + } + s_connections.clear(); + LeaveCriticalSection(&s_connectionsLock); + + if (s_acceptThread != NULL) + { + s_acceptThread->WaitForCompletion(2000); + delete s_acceptThread; + s_acceptThread = NULL; + } + + if (s_clientRecvThread != NULL) + { + s_clientRecvThread->WaitForCompletion(2000); + delete s_clientRecvThread; + s_clientRecvThread = NULL; + } + + if (s_initialized) + { + DeleteCriticalSection(&s_sendLock); + DeleteCriticalSection(&s_connectionsLock); + DeleteCriticalSection(&s_advertiseLock); + DeleteCriticalSection(&s_discoveryLock); + DeleteCriticalSection(&s_disconnectLock); + s_disconnectedSmallIds.clear(); + DeleteCriticalSection(&s_freeSmallIdLock); + s_freeSmallIds.clear(); + WSACleanup(); + s_initialized = false; + } +} + +bool WinsockNetLayer::HostGame(int port) +{ + if (!s_initialized && !Initialize()) return false; + + s_isHost = true; + s_localSmallId = 0; + s_hostSmallId = 0; + s_nextSmallId = 1; + s_hostGamePort = port; + + EnterCriticalSection(&s_freeSmallIdLock); + s_freeSmallIds.clear(); + LeaveCriticalSection(&s_freeSmallIdLock); + + int iResult; +#if defined _WINDOWS64 + struct addrinfo hints = {}; + struct addrinfo *result = NULL; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + char portStr[16]; + sprintf_s(portStr, "%d", port); + + iResult = getaddrinfo(NULL, portStr, &hints, &result); + if (iResult != 0) + { + app.DebugPrintf("getaddrinfo failed: %d\n", iResult); + return false; + } + + s_listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (s_listenSocket == INVALID_SOCKET) + { + app.DebugPrintf("socket() failed: %d\n", WSAGetLastError()); + freeaddrinfo(result); + return false; + } +#elif defined __PS3__ + struct sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons((uint16_t)port); + + s_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s_listenSocket < 0) + { + app.DebugPrintf("socket() failed: %d\n", s_listenSocket); + return false; + } +#endif + + int opt = 1; + setsockopt(s_listenSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)); + +#if defined _WINDOWS64 + iResult = ::bind(s_listenSocket, result->ai_addr, (int)result->ai_addrlen); + freeaddrinfo(result); + if (iResult == SOCKET_ERROR) + { + app.DebugPrintf("bind() failed: %d\n", WSAGetLastError()); + closesocket(s_listenSocket); + s_listenSocket = INVALID_SOCKET; + return false; + } + + iResult = listen(s_listenSocket, SOMAXCONN); + if (iResult == SOCKET_ERROR) + { + app.DebugPrintf("listen() failed: %d\n", WSAGetLastError()); + closesocket(s_listenSocket); + s_listenSocket = INVALID_SOCKET; + return false; + } +#elif defined __PS3__ + iResult = ::bind(s_listenSocket, (struct sockaddr*)&addr, sizeof(addr)); + if (iResult < 0) + { + app.DebugPrintf("bind() failed: %d\n", iResult); + closesocket(s_listenSocket); + s_listenSocket = -1; + return false; + } + + iResult = listen(s_listenSocket, 5); + if (iResult < 0) + { + app.DebugPrintf("listen() failed: %d\n", iResult); + closesocket(s_listenSocket); + s_listenSocket = -1; + return false; + } +#endif + + s_active = true; + s_connected = true; + + s_acceptThread = new C4JThread(AcceptThreadProc, NULL, "AcceptThreadProc"); + s_acceptThread->Run(); + + app.DebugPrintf("LAN: Hosting on port %d\n", port); + return true; +} + +bool WinsockNetLayer::JoinGame(const char *ip, int port) +{ + if (!s_initialized && !Initialize()) return false; + + s_isHost = false; + s_hostSmallId = 0; + +#if defined _WINDOWS64 + struct addrinfo hints = {}; + struct addrinfo *result = NULL; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + char portStr[16]; + sprintf_s(portStr, "%d", port); + + int iResult = getaddrinfo(ip, portStr, &hints, &result); + if (iResult != 0) + { + app.DebugPrintf("getaddrinfo failed for %s:%d - %d\n", ip, port, iResult); + return false; + } + + s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (s_hostConnectionSocket == INVALID_SOCKET) + { + app.DebugPrintf("socket() failed: %d\n", WSAGetLastError()); + freeaddrinfo(result); + return false; + } + + int noDelay = 1; + setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay)); + + iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen); + freeaddrinfo(result); + if (iResult == SOCKET_ERROR) + { + app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, WSAGetLastError()); + closesocket(s_hostConnectionSocket); + s_hostConnectionSocket = INVALID_SOCKET; + return false; + } +#elif defined __PS3__ + struct sockaddr_in addr = {}; + + addr.sin_family = AF_INET; + addr.sin_port = htons((uint16_t)port); + + addr.sin_addr.s_addr = inet_addr(ip); + if (addr.sin_addr.s_addr == INADDR_NONE) + { + app.DebugPrintf("inet_addr failed for %s:%d\n", ip, port); + return false; + } + + int iResult = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + s_hostConnectionSocket = iResult; + if (s_hostConnectionSocket < 0) + { + app.DebugPrintf("socket() failed: %d\n", s_hostConnectionSocket); + return false; + } + + int noDelay = 1; + setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay)); + + iResult = connect(s_hostConnectionSocket, (struct sockaddr*)&addr, sizeof(addr)); + if (iResult < 0) + { + app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, s_hostConnectionSocket); + socketclose(s_hostConnectionSocket); + s_hostConnectionSocket = -1; + return false; + } +#endif + BYTE assignBuf[1]; + int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0); + if (bytesRecv != 1) + { + app.DebugPrintf("Failed to receive small ID assignment from host\n"); + closesocket(s_hostConnectionSocket); + s_hostConnectionSocket = INVALID_SOCKET; + return false; + } + s_localSmallId = assignBuf[0]; + + app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId); + + s_active = true; + s_connected = true; + + s_clientRecvThread = new C4JThread(ClientRecvThreadProc, NULL, "ClientRecvThreadProc"); + s_clientRecvThread->Run(); + + return true; +} + + +bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize) +{ +#if defined _WINDOWS64 + if (sock == INVALID_SOCKET || dataSize <= 0) return false; +#elif defined __PS3__ + if (sock < 0 || dataSize <= 0) return false; +#endif + + EnterCriticalSection(&s_sendLock); + + BYTE header[4]; + header[0] = (BYTE)((dataSize >> 24) & 0xFF); + header[1] = (BYTE)((dataSize >> 16) & 0xFF); + header[2] = (BYTE)((dataSize >> 8) & 0xFF); + header[3] = (BYTE)(dataSize & 0xFF); + + int totalSent = 0; + int toSend = 4; + while (totalSent < toSend) + { + int sent = send(sock, (const char *)header + totalSent, toSend - totalSent, 0); +#if defined _WINDOWS64 + if (sent == SOCKET_ERROR || sent == 0) +#elif defined __PS3__ + if (sent < 0 || sent == 0) +#endif + { + LeaveCriticalSection(&s_sendLock); + return false; + } + totalSent += sent; + } + + totalSent = 0; + while (totalSent < dataSize) + { + int sent = send(sock, (const char *)data + totalSent, dataSize - totalSent, 0); + +#if defined _WINDOWS64 + if (sent == SOCKET_ERROR || sent == 0) +#elif defined __PS3__ + if (sent < 0 || sent == 0) +#endif + { + LeaveCriticalSection(&s_sendLock); + return false; + } + totalSent += sent; + } + + LeaveCriticalSection(&s_sendLock); + return true; +} + +bool WinsockNetLayer::SendToSmallId(BYTE targetSmallId, const void *data, int dataSize) +{ + if (!s_active) return false; + + if (s_isHost) + { + SOCKET sock = GetSocketForSmallId(targetSmallId); +#if defined _WINDOWS64 + if (sock == INVALID_SOCKET) return false; +#elif defined __PS3__ + if (sock < 0) return false; +#endif + return SendOnSocket(sock, data, dataSize); + } + else + { + return SendOnSocket(s_hostConnectionSocket, data, dataSize); + } +} + +SOCKET WinsockNetLayer::GetSocketForSmallId(BYTE smallId) +{ + EnterCriticalSection(&s_connectionsLock); + for (size_t i = 0; i < s_connections.size(); i++) + { + if (s_connections[i].smallId == smallId && s_connections[i].active) + { + SOCKET sock = s_connections[i].tcpSocket; + LeaveCriticalSection(&s_connectionsLock); + return sock; + } + } + LeaveCriticalSection(&s_connectionsLock); +#if defined _WINDOWS64 + return INVALID_SOCKET; +#elif defined __PS3__ + return -1; +#endif +} + +static bool RecvExact(SOCKET sock, BYTE *buf, int len) +{ + int totalRecv = 0; + while (totalRecv < len) + { + int r = recv(sock, (char *)buf + totalRecv, len - totalRecv, 0); + if (r <= 0) return false; + totalRecv += r; + } + return true; +} + +void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char *data, unsigned int dataSize) +{ + INetworkPlayer *pPlayerFrom = g_NetworkManager.GetPlayerBySmallId(fromSmallId); + INetworkPlayer *pPlayerTo = g_NetworkManager.GetPlayerBySmallId(toSmallId); + + if (pPlayerFrom == NULL || pPlayerTo == NULL) return; + + if (s_isHost) + { + ::Socket *pSocket = pPlayerFrom->GetSocket(); + if (pSocket != NULL) + pSocket->pushDataToQueue(data, dataSize, false); + } + else + { + ::Socket *pSocket = pPlayerTo->GetSocket(); + if (pSocket != NULL) + pSocket->pushDataToQueue(data, dataSize, true); + } +} + +int WinsockNetLayer::AcceptThreadProc(LPVOID param) +{ + while (s_active) + { + SOCKET clientSocket = accept(s_listenSocket, NULL, NULL); +#if defined _WINDOWS64 + if (clientSocket == INVALID_SOCKET) + { + if (s_active) + app.DebugPrintf("accept() failed: %d\n", WSAGetLastError()); + break; + } +#elif __PS3__ + if (clientSocket < 0) + { + if (s_active) + app.DebugPrintf("accept() failed: %d\n", clientSocket); + break; + } +#endif + + int noDelay = 1; + setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay)); + + extern QNET_STATE _iQNetStubState; + if (_iQNetStubState != QNET_STATE_GAME_PLAY) + { + app.DebugPrintf("Win64 LAN: Rejecting connection, game not ready\n"); + closesocket(clientSocket); + continue; + } + + BYTE assignedSmallId; + EnterCriticalSection(&s_freeSmallIdLock); + if (!s_freeSmallIds.empty()) + { + assignedSmallId = s_freeSmallIds.back(); + s_freeSmallIds.pop_back(); + } + else if (s_nextSmallId < MINECRAFT_NET_MAX_PLAYERS) + { + assignedSmallId = s_nextSmallId++; + } + else + { + LeaveCriticalSection(&s_freeSmallIdLock); + app.DebugPrintf("Win64 LAN: Server full, rejecting connection\n"); + closesocket(clientSocket); + continue; + } + LeaveCriticalSection(&s_freeSmallIdLock); + + BYTE assignBuf[1] = { assignedSmallId }; + int sent = send(clientSocket, (const char *)assignBuf, 1, 0); + if (sent != 1) + { + app.DebugPrintf("Failed to send small ID to client\n"); + closesocket(clientSocket); + continue; + } + + Win64RemoteConnection conn; + conn.tcpSocket = clientSocket; + conn.smallId = assignedSmallId; + conn.active = true; + conn.recvThread = NULL; + + EnterCriticalSection(&s_connectionsLock); + s_connections.push_back(conn); + int connIdx = (int)s_connections.size() - 1; + LeaveCriticalSection(&s_connectionsLock); + + app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId); + + IQNetPlayer *qnetPlayer = &IQNet::m_player[assignedSmallId]; + + extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal); + Win64_SetupRemoteQNetPlayer(qnetPlayer, assignedSmallId, false, false); + + extern CPlatformNetworkManagerStub *g_pPlatformNetworkManager; + g_pPlatformNetworkManager->NotifyPlayerJoined(qnetPlayer); + + DWORD *threadParam = new DWORD; + *threadParam = connIdx; + C4JThread* hThread = new C4JThread(RecvThreadProc, threadParam, "RecvThreadProc"); + hThread->Run(); + + EnterCriticalSection(&s_connectionsLock); + if (connIdx < (int)s_connections.size()) + s_connections[connIdx].recvThread = hThread; + LeaveCriticalSection(&s_connectionsLock); + } + return 0; +} + +int WinsockNetLayer::RecvThreadProc(LPVOID param) +{ + DWORD connIdx = *(DWORD *)param; + delete (DWORD *)param; + + EnterCriticalSection(&s_connectionsLock); + if (connIdx >= (DWORD)s_connections.size()) + { + LeaveCriticalSection(&s_connectionsLock); + return 0; + } + SOCKET sock = s_connections[connIdx].tcpSocket; + BYTE clientSmallId = s_connections[connIdx].smallId; + LeaveCriticalSection(&s_connectionsLock); + + BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE]; + + while (s_active) + { + BYTE header[4]; + if (!RecvExact(sock, header, 4)) + { + app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (header)\n", clientSmallId); + break; + } + + int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3]; + + if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE) + { + app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d\n", packetSize, clientSmallId); + break; + } + + if (!RecvExact(sock, recvBuf, packetSize)) + { + app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId); + break; + } + + HandleDataReceived(clientSmallId, s_hostSmallId, recvBuf, packetSize); + } + + delete[] recvBuf; + + EnterCriticalSection(&s_connectionsLock); + for (size_t i = 0; i < s_connections.size(); i++) + { + if (s_connections[i].smallId == clientSmallId) + { + s_connections[i].active = false; + closesocket(s_connections[i].tcpSocket); + s_connections[i].tcpSocket = INVALID_SOCKET; + break; + } + } + LeaveCriticalSection(&s_connectionsLock); + + EnterCriticalSection(&s_disconnectLock); + s_disconnectedSmallIds.push_back(clientSmallId); + LeaveCriticalSection(&s_disconnectLock); + + return 0; +} + +bool WinsockNetLayer::PopDisconnectedSmallId(BYTE *outSmallId) +{ + bool found = false; + EnterCriticalSection(&s_disconnectLock); + if (!s_disconnectedSmallIds.empty()) + { + *outSmallId = s_disconnectedSmallIds.back(); + s_disconnectedSmallIds.pop_back(); + found = true; + } + LeaveCriticalSection(&s_disconnectLock); + return found; +} + +void WinsockNetLayer::PushFreeSmallId(BYTE smallId) +{ + EnterCriticalSection(&s_freeSmallIdLock); + s_freeSmallIds.push_back(smallId); + LeaveCriticalSection(&s_freeSmallIdLock); +} + +int WinsockNetLayer::ClientRecvThreadProc(LPVOID param) +{ + BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE]; + +#if defined _WINDOWS64 + while (s_active && s_hostConnectionSocket != INVALID_SOCKET) +#elif defined __PS3__ + while (s_active && s_hostConnectionSocket >= 0) +#endif + { + BYTE header[4]; + if (!RecvExact(s_hostConnectionSocket, header, 4)) + { + app.DebugPrintf("Win64 LAN: Disconnected from host (header)\n"); + break; + } + + int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3]; + + if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE) + { + app.DebugPrintf("Win64 LAN: Invalid packet size %d from host\n", packetSize); + break; + } + + if (!RecvExact(s_hostConnectionSocket, recvBuf, packetSize)) + { + app.DebugPrintf("Win64 LAN: Disconnected from host (body)\n"); + break; + } + + HandleDataReceived(s_hostSmallId, s_localSmallId, recvBuf, packetSize); + } + + delete[] recvBuf; + + s_connected = false; + return 0; +} + +bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer) +{ + if (s_advertising) return true; + if (!s_initialized) return false; + + EnterCriticalSection(&s_advertiseLock); + memset(&s_advertiseData, 0, sizeof(s_advertiseData)); + s_advertiseData.magic = WIN64_LAN_BROADCAST_MAGIC; + s_advertiseData.netVersion = netVer; + s_advertiseData.gamePort = (WORD)gamePort; + size_t converted = wcstombs(s_advertiseData.hostName, hostName, 32); + s_advertiseData.playerCount = 1; + s_advertiseData.maxPlayers = MINECRAFT_NET_MAX_PLAYERS; + s_advertiseData.gameHostSettings = gameSettings; + s_advertiseData.texturePackParentId = texPackId; + s_advertiseData.subTexturePackId = subTexId; + s_advertiseData.isJoinable = 0; + s_hostGamePort = gamePort; + LeaveCriticalSection(&s_advertiseLock); + + s_advertiseSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +#if defined _WINDOWS64 + if (s_advertiseSock == INVALID_SOCKET) + { + app.DebugPrintf("Win64 LAN: Failed to create advertise socket: %d\n", WSAGetLastError()); + return false; + } +#elif defined __PS3__ + if (s_advertiseSock < 0) + { + app.DebugPrintf("PS3 LAN: Failed to create advertise socket: %d\n", s_advertiseSock); + return false; + } +#endif + + BOOL broadcast = TRUE; + setsockopt(s_advertiseSock, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast)); + + s_advertising = true; + s_advertiseThread = new C4JThread(AdvertiseThreadProc, NULL, "AdvertiseThreadProc"); + s_advertiseThread->Run(); + app.DebugPrintf("Win64 LAN: Started advertising on UDP port %d\n", WIN64_LAN_DISCOVERY_PORT); + return true; +} + +void WinsockNetLayer::StopAdvertising() +{ + s_advertising = false; + +#if defined _WINDOWS64 + if (s_advertiseSock != INVALID_SOCKET) + { + closesocket(s_advertiseSock); + s_advertiseSock = INVALID_SOCKET; + } +#elif defined __PS3__ + if (s_advertiseSock >= 0) + { + closesocket(s_advertiseSock); + s_advertiseSock = -1; + } +#endif + + if (s_advertiseThread != NULL) + { + s_advertiseThread->WaitForCompletion(2000); + delete s_advertiseThread; + s_advertiseThread = NULL; + } +} + +void WinsockNetLayer::UpdateAdvertisePlayerCount(BYTE count) +{ + EnterCriticalSection(&s_advertiseLock); + s_advertiseData.playerCount = count; + LeaveCriticalSection(&s_advertiseLock); +} + +void WinsockNetLayer::UpdateAdvertiseJoinable(bool joinable) +{ + EnterCriticalSection(&s_advertiseLock); + s_advertiseData.isJoinable = joinable ? 1 : 0; + LeaveCriticalSection(&s_advertiseLock); +} + +int WinsockNetLayer::AdvertiseThreadProc(LPVOID param) +{ + struct sockaddr_in broadcastAddr; + memset(&broadcastAddr, 0, sizeof(broadcastAddr)); + broadcastAddr.sin_family = AF_INET; + broadcastAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT); + broadcastAddr.sin_addr.s_addr = INADDR_BROADCAST; + + while (s_advertising) + { + EnterCriticalSection(&s_advertiseLock); + Win64LANBroadcast data = s_advertiseData; + LeaveCriticalSection(&s_advertiseLock); + + data.magic = htonl(data.magic); + data.netVersion = htons(data.netVersion); + data.gamePort = htons(data.gamePort); + data.gameHostSettings = htonl(data.gameHostSettings); + data.texturePackParentId = htonl(data.texturePackParentId); + + int sent = sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0, + (struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr)); + +#if defined _WINDOWS64 + if (sent == SOCKET_ERROR && s_advertising) + { + app.DebugPrintf("Win64 LAN: Broadcast sendto failed: %d\n", WSAGetLastError()); + } +#elif defined __PS3__ + if (sent < 0 && s_advertising) + { + app.DebugPrintf("PS3 LAN: Broadcast sendto failed: %d\n", sent); + } +#endif + + C4JThread::Sleep(1000); + } + + return 0; +} + +bool WinsockNetLayer::StartDiscovery() +{ + if (s_discovering) return true; + if (!s_initialized) return false; + + s_discoverySock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +#if defined _WINDOWS64 + if (s_discoverySock == INVALID_SOCKET) + { + app.DebugPrintf("Win64 LAN: Failed to create discovery socket: %d\n", WSAGetLastError()); + return false; + } +#elif defined __PS3__ + app.DebugPrintf("Discovery socket: %d\n", s_discoverySock); + if (s_discoverySock < 0) + { + app.DebugPrintf("PS3 LAN: Failed to create discovery socket: %d\n", s_discoverySock); + cellNetCtlTerm(); + sys_net_finalize_network(); + return false; + } +#endif + + BOOL reuseAddr = TRUE; + setsockopt(s_discoverySock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseAddr, sizeof(reuseAddr)); + + struct sockaddr_in bindAddr; + memset(&bindAddr, 0, sizeof(bindAddr)); + bindAddr.sin_family = AF_INET; + bindAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT); + bindAddr.sin_addr.s_addr = INADDR_ANY; + +#if defined _WINDOWS64 + if (::bind(s_discoverySock, (struct sockaddr *)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) + { + app.DebugPrintf("Win64 LAN: Discovery bind failed: %d\n", WSAGetLastError()); + closesocket(s_discoverySock); + s_discoverySock = INVALID_SOCKET; + return false; + } +#elif defined __PS3__ + if (::bind(s_discoverySock, (struct sockaddr *)&bindAddr, sizeof(bindAddr)) < 0) + { + app.DebugPrintf("PS3 LAN: Discovery bind failed: %d\n", sys_net_errno); + socketclose(s_discoverySock); + s_discoverySock = -1; + return false; + } +#endif + DWORD timeout = 500; + setsockopt(s_discoverySock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)); + + s_discovering = true; + s_discoveryThread = new C4JThread(DiscoveryThreadProc, NULL, "DiscoveryThreadProc"); + s_discoveryThread->Run(); + + app.DebugPrintf("LAN: Listening for LAN games on UDP port %d\n", WIN64_LAN_DISCOVERY_PORT); + return true; +} + +void WinsockNetLayer::StopDiscovery() +{ + s_discovering = false; + +#if defined _WINDOWS64 + if (s_discoverySock != INVALID_SOCKET) + { + closesocket(s_discoverySock); + s_discoverySock = INVALID_SOCKET; + } +#elif defined __PS3__ + if (s_discoverySock >= 0) + { + socketclose(s_discoverySock); + s_discoverySock = -1; + } +#endif + + if (s_discoveryThread != NULL) + { + s_discoveryThread->WaitForCompletion(2000); + delete s_discoveryThread; + s_discoveryThread = NULL; + } + + EnterCriticalSection(&s_discoveryLock); + s_discoveredSessions.clear(); + LeaveCriticalSection(&s_discoveryLock); +} + +std::vector WinsockNetLayer::GetDiscoveredSessions() +{ + std::vector result; + EnterCriticalSection(&s_discoveryLock); + result = s_discoveredSessions; + LeaveCriticalSection(&s_discoveryLock); + return result; +} + +int WinsockNetLayer::DiscoveryThreadProc(LPVOID param) +{ + app.DebugPrintf("Discovery thread started\n"); + char recvBuf[512]; + + while (s_discovering) + { + struct sockaddr_in senderAddr; +#if defined _WINDOWS64 + int senderLen = sizeof(senderAddr); +#elif defined __PS3__ + socklen_t senderLen = sizeof(senderAddr); +#endif + + int recvLen = recvfrom(s_discoverySock, recvBuf, sizeof(recvBuf), 0, + (struct sockaddr *)&senderAddr, &senderLen); + +#ifdef _WINDOWS64 + if (recvLen == SOCKET_ERROR) + { + continue; + } +#elif defined __PS3__ + if (recvLen < 0) + { + continue; + } +#endif + + if (recvLen < (int)sizeof(Win64LANBroadcast)) + continue; + + Win64LANBroadcast *broadcast = (Win64LANBroadcast *)recvBuf; + + broadcast->magic = ntohl(broadcast->magic); + broadcast->netVersion = ntohs(broadcast->netVersion); + broadcast->gamePort = ntohs(broadcast->gamePort); + broadcast->gameHostSettings = ntohl(broadcast->gameHostSettings); + broadcast->texturePackParentId = ntohl(broadcast->texturePackParentId); + + if (broadcast->magic != WIN64_LAN_BROADCAST_MAGIC) + continue; + + char senderIP[64]; + inet_ntop(AF_INET, &senderAddr.sin_addr, senderIP, sizeof(senderIP)); + + DWORD now = GetTickCount(); + + EnterCriticalSection(&s_discoveryLock); + bool found = false; + for (size_t i = 0; i < s_discoveredSessions.size(); i++) + { + if (strcmp(s_discoveredSessions[i].hostIP, senderIP) == 0 && + s_discoveredSessions[i].hostPort == (int)broadcast->gamePort) + { + s_discoveredSessions[i].netVersion = broadcast->netVersion; + wcsncpy(s_discoveredSessions[i].hostName, broadcast->hostName, 31); + s_discoveredSessions[i].hostName[31] = L'\0'; + s_discoveredSessions[i].playerCount = broadcast->playerCount; + s_discoveredSessions[i].maxPlayers = broadcast->maxPlayers; + s_discoveredSessions[i].gameHostSettings = broadcast->gameHostSettings; + s_discoveredSessions[i].texturePackParentId = broadcast->texturePackParentId; + s_discoveredSessions[i].subTexturePackId = broadcast->subTexturePackId; + s_discoveredSessions[i].isJoinable = (broadcast->isJoinable != 0); + s_discoveredSessions[i].lastSeenTick = now; + found = true; + break; + } + } + + if (!found) + { + Win64LANSession session; + memset(&session, 0, sizeof(session)); + strncpy(session.hostIP, senderIP, sizeof(session.hostIP) - 1); + session.hostIP[sizeof(session.hostIP) - 1] = '\0'; + session.hostPort = (int)broadcast->gamePort; + session.netVersion = broadcast->netVersion; + mbstowcs(session.hostName, broadcast->hostName, 31); + + if (converted != (size_t)-1) + session.hostName[converted] = L'\0'; + else + session.hostName[0] = L'\0'; + session.playerCount = broadcast->playerCount; + session.maxPlayers = broadcast->maxPlayers; + session.gameHostSettings = broadcast->gameHostSettings; + session.texturePackParentId = broadcast->texturePackParentId; + session.subTexturePackId = broadcast->subTexturePackId; + session.isJoinable = (broadcast->isJoinable != 0); + session.lastSeenTick = now; + s_discoveredSessions.push_back(session); + + app.DebugPrintf("LAN: Discovered game \"%ls\" at %s:%d\n", + session.hostName, session.hostIP, session.hostPort); + } + + for (size_t i = s_discoveredSessions.size(); i > 0; i--) + { + if (now - s_discoveredSessions[i - 1].lastSeenTick > 5000) + { + app.DebugPrintf("LAN: Session \"%ls\" at %s timed out\n", + s_discoveredSessions[i - 1].hostName, s_discoveredSessions[i - 1].hostIP); + s_discoveredSessions.erase(s_discoveredSessions.begin() + (i - 1)); + } + } + + LeaveCriticalSection(&s_discoveryLock); + } + + return 0; +} diff --git a/Minecraft.Client/Common/Network/WinsockNetLayer.h b/Minecraft.Client/Common/Network/WinsockNetLayer.h new file mode 100644 index 00000000..45704a35 --- /dev/null +++ b/Minecraft.Client/Common/Network/WinsockNetLayer.h @@ -0,0 +1,162 @@ +#pragma once + +#if defined _WINDOWS64 +#include +#include +#elif defined __PS3__ +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include "..\..\Common\Network\NetworkPlayerInterface.h" + +#ifdef _WINDOWS64 +#pragma comment(lib, "Ws2_32.lib") +#endif + +#define WIN64_NET_DEFAULT_PORT 25565 +#define WIN64_NET_MAX_CLIENTS 7 +#define WIN64_NET_RECV_BUFFER_SIZE 65536 +#define WIN64_LAN_DISCOVERY_PORT 25566 +#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E + +#ifdef __PS3__ +typedef int SOCKET; +#define INVALID_SOCKET -1 +#endif + +class Socket; + +#pragma pack(push, 1) +struct Win64LANBroadcast +{ + DWORD magic; + WORD netVersion; + WORD gamePort; + char hostName[32]; + BYTE playerCount; + BYTE maxPlayers; + DWORD gameHostSettings; + DWORD texturePackParentId; + BYTE subTexturePackId; + BYTE isJoinable; +}; +#pragma pack(pop) + +struct Win64LANSession +{ + char hostIP[64]; + int hostPort; + wchar_t hostName[32]; + unsigned short netVersion; + unsigned char playerCount; + unsigned char maxPlayers; + unsigned int gameHostSettings; + unsigned int texturePackParentId; + unsigned char subTexturePackId; + bool isJoinable; + DWORD lastSeenTick; +}; + +struct Win64RemoteConnection +{ + SOCKET tcpSocket; + BYTE smallId; + C4JThread* recvThread; + volatile bool active; +}; + +class WinsockNetLayer +{ +public: + static bool Initialize(); + static void Shutdown(); + + static bool HostGame(int port); + static bool JoinGame(const char *ip, int port); + + static bool SendToSmallId(BYTE targetSmallId, const void *data, int dataSize); + static bool SendOnSocket(SOCKET sock, const void *data, int dataSize); + + static bool IsHosting() { return s_isHost; } + static bool IsConnected() { return s_connected; } + static bool IsActive() { return s_active; } + + static BYTE GetLocalSmallId() { return s_localSmallId; } + static BYTE GetHostSmallId() { return s_hostSmallId; } + + static SOCKET GetSocketForSmallId(BYTE smallId); + + static void HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char *data, unsigned int dataSize); + + static bool PopDisconnectedSmallId(BYTE *outSmallId); + static void PushFreeSmallId(BYTE smallId); + + static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer); + static void StopAdvertising(); + static void UpdateAdvertisePlayerCount(BYTE count); + static void UpdateAdvertiseJoinable(bool joinable); + + static bool StartDiscovery(); + static void StopDiscovery(); + static vector GetDiscoveredSessions(); + + static int GetHostPort() { return s_hostGamePort; } + +private: + static int AcceptThreadProc(void* param); + static int RecvThreadProc(void* param); + static int ClientRecvThreadProc(void* param); + static int AdvertiseThreadProc(void* param); + static int DiscoveryThreadProc(void* param); + + static SOCKET s_listenSocket; + static SOCKET s_hostConnectionSocket; + static C4JThread* s_acceptThread; + static C4JThread* s_clientRecvThread; + + static bool s_isHost; + static bool s_connected; + static bool s_active; + static bool s_initialized; + + static BYTE s_localSmallId; + static BYTE s_hostSmallId; + static BYTE s_nextSmallId; + + static CRITICAL_SECTION s_sendLock; + static CRITICAL_SECTION s_connectionsLock; + + static std::vector s_connections; + + static SOCKET s_advertiseSock; + static C4JThread* s_advertiseThread; + static volatile bool s_advertising; + static Win64LANBroadcast s_advertiseData; + static CRITICAL_SECTION s_advertiseLock; + static int s_hostGamePort; + + static SOCKET s_discoverySock; + static C4JThread* s_discoveryThread; + static volatile bool s_discovering; + static CRITICAL_SECTION s_discoveryLock; + static std::vector s_discoveredSessions; + + static CRITICAL_SECTION s_disconnectLock; + static std::vector s_disconnectedSmallIds; + + static CRITICAL_SECTION s_freeSmallIdLock; + static std::vector s_freeSmallIds; +}; + +extern bool g_Win64MultiplayerHost; +extern bool g_Win64MultiplayerJoin; +extern int g_Win64MultiplayerPort; +extern char g_Win64MultiplayerIP[256]; \ No newline at end of file diff --git a/Minecraft.Client/Common/UI/IUIScene_StartGame.cpp b/Minecraft.Client/Common/UI/IUIScene_StartGame.cpp index 8f159fc2..8c2f712b 100644 --- a/Minecraft.Client/Common/UI/IUIScene_StartGame.cpp +++ b/Minecraft.Client/Common/UI/IUIScene_StartGame.cpp @@ -54,7 +54,7 @@ void IUIScene_StartGame::HandleDLCMountingComplete() for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) { bTexturePackAlreadyListed=false; -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) char *pchName=app.GetDLCInfoTextures(i); pDLCInfo=app.GetDLCInfo(pchName); #elif defined _XBOX_ONE diff --git a/Minecraft.Client/Common/UI/UIScene_InGameInfoMenu.cpp b/Minecraft.Client/Common/UI/UIScene_InGameInfoMenu.cpp index 092b7156..c6211607 100644 --- a/Minecraft.Client/Common/UI/UIScene_InGameInfoMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_InGameInfoMenu.cpp @@ -502,6 +502,9 @@ UIScene_InGameInfoMenu::PlayerInfo *UIScene_InGameInfoMenu::BuildPlayerInfo(INet #if defined __PS3__ || defined __PSVITA__ int UIScene_InGameInfoMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else UIScene_InGameInfoMenu* pClass = (UIScene_InGameInfoMenu*)pParam; if(result==C4JStorage::EMessage_ResultAccept) @@ -514,6 +517,7 @@ int UIScene_InGameInfoMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStora } return 0; +#endif } int UIScene_InGameInfoMenu::ViewInvites_SignInReturned(void *pParam,bool bContinue, int iPad) diff --git a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp index 11db9c51..5abfb56f 100644 --- a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp @@ -59,7 +59,7 @@ void UIScene_JoinMenu::tick() m_buttonListPlayers.init(eControl_GamePlayers); -#if defined(__PS3__) || defined(__ORBIS__) || defined __PSVITA__ +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined __PSVITA__ for( int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++ ) { if( m_selectedSession->data.players[i] != NULL ) @@ -353,6 +353,9 @@ void UIScene_JoinMenu::checkPrivilegeCallback(LPVOID lpParam, bool hasPrivilege, void UIScene_JoinMenu::StartSharedLaunchFlow() { +#if defined DISABLE_PSN && defined __PS3__ + JoinGame(this); +#else if(!app.IsLocalMultiplayerAvailable()) { JoinGame(this); @@ -366,12 +369,17 @@ void UIScene_JoinMenu::StartSharedLaunchFlow() info.requireOnline = true; ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_QuadrantSignin,&info); } +#endif } int UIScene_JoinMenu::StartGame_SignInReturned(void *pParam,bool bContinue, int iPad) { UIScene_JoinMenu* pClass = (UIScene_JoinMenu*)ui.GetSceneFromCallbackId((size_t)pParam); +#if defined DISABLE_PSN && defined __PS3__ + JoinGame(pClass); + return 0; +#else if(pClass) { if(bContinue==true) @@ -392,6 +400,7 @@ int UIScene_JoinMenu::StartGame_SignInReturned(void *pParam,bool bContinue, int } } return 0; +#endif } // Shared function to join the game that is the same whether we used the sign-in UI or not @@ -431,7 +440,9 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) if( !ProfileManager.AllowedToPlayMultiplayer(ProfileManager.GetPrimaryPad()) ) noPrivileges = true; dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(ProfileManager.GetPrimaryPad()); +#ifndef DISABLE_PSN isSignedInLive = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()); +#endif #ifdef __PSVITA__ if(CGameNetworkManager::usingAdhocMode() && SQRNetworkManager_AdHoc_Vita::GetAdhocStatus()) isSignedInLive = true; @@ -470,7 +481,7 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) BOOL pccAllowed = TRUE; BOOL pccFriendsAllowed = TRUE; -#if defined(__PS3__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__PSVITA__) if(isSignedInLive) { ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),false,&noUGC,NULL,NULL); diff --git a/Minecraft.Client/Common/UI/UIScene_LeaderboardsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LeaderboardsMenu.cpp index c0bf18d5..656b9e0f 100644 --- a/Minecraft.Client/Common/UI/UIScene_LeaderboardsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_LeaderboardsMenu.cpp @@ -731,7 +731,7 @@ void UIScene_LeaderboardsMenu::CopyLeaderboardEntry(LeaderboardManager::ReadScor } } -#ifdef __PS3__ +#if !defined(DISABLE_PSN) && defined(__PS3__) // m_name can be unicode characters somehow for Japan - should use m_onlineID wstring wstr=convStringToWstring(statsRow->m_uid.getOnlineID()); swprintf(leaderboardEntry->m_gamerTag, XUSER_NAME_SIZE, L"%ls",wstr.c_str()); diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp index bbcdaf57..5b45e20b 100644 --- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp @@ -2385,6 +2385,9 @@ int UIScene_LoadOrJoinMenu::TexturePackDialogReturned(void *pParam,int iPad,C4JS #if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ int UIScene_LoadOrJoinMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else UIScene_LoadOrJoinMenu* pClass = (UIScene_LoadOrJoinMenu*)pParam; if(result==C4JStorage::EMessage_ResultAccept) @@ -2403,6 +2406,7 @@ int UIScene_LoadOrJoinMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStora } return 0; +#endif } int UIScene_LoadOrJoinMenu::PSN_SignInReturned(void *pParam,bool bContinue, int iPad) diff --git a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp index 0603360a..c9251291 100644 --- a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp @@ -550,6 +550,7 @@ int UIScene_MainMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EM { UIScene_MainMenu* pClass = (UIScene_MainMenu*)pParam; +#ifndef DISABLE_PSN if(result==C4JStorage::EMessage_ResultAccept) { #ifdef __PS3__ @@ -629,6 +630,9 @@ int UIScene_MainMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EM pClass->m_bIgnorePress=false; } } +#endif + CreateLoad_SignInReturned(pClass, true, 0); + pClass->m_bIgnorePress=false; return 0; } diff --git a/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp b/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp index ceb92473..eb2bd51b 100644 --- a/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp @@ -1029,6 +1029,9 @@ int UIScene_PauseMenu::BanGameDialogReturned(void *pParam,int iPad,C4JStorage::E #if defined(__PS3__) || defined (__PSVITA__) || defined(__ORBIS__) int UIScene_PauseMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)ui.GetSceneFromCallbackId((size_t)pParam); if(result==C4JStorage::EMessage_ResultAccept && pClass) { @@ -1091,6 +1094,7 @@ int UIScene_PauseMenu::MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::E } return 0; +#endif } int UIScene_PauseMenu::ViewLeaderboards_SignInReturned(void *pParam,bool bContinue, int iPad) @@ -1131,6 +1135,9 @@ int UIScene_PauseMenu::ViewLeaderboards_SignInReturned(void *pParam,bool bContin int UIScene_PauseMenu::WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { +#ifdef DISABLE_PSN + return 0; +#else UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)ui.GetSceneFromCallbackId((size_t)pParam); #ifdef __ORBIS__ @@ -1244,7 +1251,7 @@ int UIScene_PauseMenu::WarningTrialTexturePackReturned(void *pParam,int iPad,C4J } } #endif // - +#endif return 0; } diff --git a/Minecraft.Client/Common/UI/UIScene_SaveMessage.cpp b/Minecraft.Client/Common/UI/UIScene_SaveMessage.cpp index fa9cd6c5..5c27eee5 100644 --- a/Minecraft.Client/Common/UI/UIScene_SaveMessage.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SaveMessage.cpp @@ -110,7 +110,7 @@ void UIScene_SaveMessage::handlePress(F64 controlId, F64 childId) m_bIgnoreInput=true; -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) // wait for the profile to be read - this has been kicked off earlier, so should be read by now addTimer(PROFILE_LOADED_TIMER_ID,PROFILE_LOADED_TIMER_TIME); #else @@ -126,7 +126,7 @@ void UIScene_SaveMessage::handleTimerComplete(int id) { case PROFILE_LOADED_TIMER_ID: { -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) C4JStorage::eOptionsCallback eStatus=app.GetOptionsCallbackStatus(0); switch(eStatus) diff --git a/Minecraft.Client/Common/UI/UIScene_SkinSelectMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SkinSelectMenu.cpp index fdfbfdf9..7fd06a49 100644 --- a/Minecraft.Client/Common/UI/UIScene_SkinSelectMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SkinSelectMenu.cpp @@ -1518,7 +1518,7 @@ void UIScene_SkinSelectMenu::HandleDLCMountingComplete() void UIScene_SkinSelectMenu::showNotOnlineDialog(int iPad) { // need to be signed in to live. get them to sign in to online -#if defined(__PS3__) +#if !defined(DISABLE_PSN) && defined(__PS3__) SQRNetworkManager_PS3::AttemptPSNSignIn(NULL, this); #elif defined(__PSVITA__) diff --git a/Minecraft.Client/Extrax64Stubs.cpp b/Minecraft.Client/Extrax64Stubs.cpp index 7fff9b09..d8d4ca0b 100644 --- a/Minecraft.Client/Extrax64Stubs.cpp +++ b/Minecraft.Client/Extrax64Stubs.cpp @@ -5,6 +5,7 @@ #ifdef __PS3__ #include "PS3\Sentient\SentientManager.h" +#include "Common\Network\WinsockNetLayer.h" #include "StatsCounter.h" #include "PS3\Social\SocialManager.h" #include @@ -17,6 +18,7 @@ #include "Durango\DurangoExtras\xcompress.h" #elif defined _WINDOWS64 #include "Windows64\Sentient\SentientManager.h" +#include "Common\Network\WinsockNetLayer.h" #include "StatsCounter.h" #include "Windows64\Social\SocialManager.h" #include "Windows64\Sentient\DynamicConfigurations.h" @@ -168,8 +170,10 @@ void PIXSetMarkerDeprecated(int a, char *b, ...) {} bool IsEqualXUID(PlayerUID a, PlayerUID b) { -#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO) return (a == b); +#elif defined(DISABLE_PSN) && defined(__PS3__) + return (a.XUID == b.XUID); #else return false; #endif @@ -185,20 +189,23 @@ D3DXVECTOR3::D3DXVECTOR3() {} D3DXVECTOR3::D3DXVECTOR3(float x,float y,float z) : x(x), y(y), z(z) {} D3DXVECTOR3& D3DXVECTOR3::operator += ( CONST D3DXVECTOR3& add ) { x += add.x; y += add.y; z += add.z; return *this; } -BYTE IQNetPlayer::GetSmallId() { return 0; } +BYTE IQNetPlayer::GetSmallId() { return m_smallId; } void IQNetPlayer::SendData(IQNetPlayer *player, const void *pvData, DWORD dwDataSize, DWORD dwFlags) { - app.DebugPrintf("Sending from 0x%x to 0x%x %d bytes\n",this,player,dwDataSize); + if (WinsockNetLayer::IsActive()) + { + WinsockNetLayer::SendToSmallId(player->m_smallId, pvData, dwDataSize); + } } -bool IQNetPlayer::IsSameSystem(IQNetPlayer *player) { return true; } +bool IQNetPlayer::IsSameSystem(IQNetPlayer *player) { return (this == player) || (!m_isRemote && !player->m_isRemote); } DWORD IQNetPlayer::GetSendQueueSize( IQNetPlayer *player, DWORD dwFlags ) { return 0; } DWORD IQNetPlayer::GetCurrentRtt() { return 0; } -bool IQNetPlayer::IsHost() { return this == &IQNet::m_player[0]; } +bool IQNetPlayer::IsHost() { return m_isHostPlayer; } bool IQNetPlayer::IsGuest() { return false; } -bool IQNetPlayer::IsLocal() { return true; } -PlayerUID IQNetPlayer::GetXuid() { return INVALID_XUID; } -LPCWSTR IQNetPlayer::GetGamertag() { static const wchar_t *test = L"stub"; return test; } -int IQNetPlayer::GetSessionIndex() { return 0; } +bool IQNetPlayer::IsLocal() { return !m_isRemote; } +PlayerUID IQNetPlayer::GetXuid() { return (PlayerUID)(0xe000d45248242f2e + m_smallId); } +LPCWSTR IQNetPlayer::GetGamertag() { return m_gamertag; } +int IQNetPlayer::GetSessionIndex() { return m_smallId; } bool IQNetPlayer::IsTalking() { return false; } bool IQNetPlayer::IsMutedByLocalUser(DWORD dwUserIndex) { return false; } bool IQNetPlayer::HasVoice() { return false; } @@ -211,23 +218,104 @@ ULONG_PTR IQNetPlayer::GetCustomDataValue() { return m_customData; } -IQNetPlayer IQNet::m_player[4]; +IQNetPlayer IQNet::m_player[MINECRAFT_NET_MAX_PLAYERS]; +DWORD IQNet::s_playerCount = 1; +bool IQNet::s_isHosting = true; -bool _bQNetStubGameRunning = false; +QNET_STATE _iQNetStubState = QNET_STATE_IDLE; + +void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal) +{ + player->m_smallId = smallId; + player->m_isRemote = !isLocal; + player->m_isHostPlayer = isHost; + swprintf(player->m_gamertag, 32, L"Player%d", smallId); + if (smallId >= IQNet::s_playerCount) + IQNet::s_playerCount = smallId + 1; +} HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex){ return S_OK; } IQNetPlayer *IQNet::GetHostPlayer() { return &m_player[0]; } -IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex) { return &m_player[dwUserIndex]; } -IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex) { return &m_player[0]; } -IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId){ return &m_player[0]; } -IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid){ return &m_player[0]; } -DWORD IQNet::GetPlayerCount() { return 1; } -QNET_STATE IQNet::GetState() { return _bQNetStubGameRunning ? QNET_STATE_GAME_PLAY : QNET_STATE_IDLE; } -bool IQNet::IsHost() { return true; } -HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo) { return S_OK; } -void IQNet::HostGame() { _bQNetStubGameRunning = true; } -void IQNet::EndGame() { _bQNetStubGameRunning = false; } +IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex) +{ + if (s_isHosting) + { + if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS && !m_player[dwUserIndex].m_isRemote) + return &m_player[dwUserIndex]; + return NULL; + } + if (dwUserIndex != 0) + return NULL; + for (DWORD i = 0; i < s_playerCount; i++) + { + if (!m_player[i].m_isRemote) + return &m_player[i]; + } + return NULL; +} +static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index) +{ + if (index == 0) return true; + return (p->GetCustomDataValue() != 0); +} +IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex) +{ + DWORD found = 0; + for (DWORD i = 0; i < s_playerCount; i++) + { + if (Win64_IsActivePlayer(&m_player[i], i)) + { + if (found == dwPlayerIndex) return &m_player[i]; + found++; + } + } + return &m_player[0]; +} +IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId) +{ + for (DWORD i = 0; i < s_playerCount; i++) + { + if (m_player[i].m_smallId == SmallId && Win64_IsActivePlayer(&m_player[i], i)) return &m_player[i]; + } + return NULL; +} +IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid) +{ + for (DWORD i = 0; i < s_playerCount; i++) + { + if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i]; + } + return &m_player[0]; +} +DWORD IQNet::GetPlayerCount() +{ + DWORD count = 0; + for (DWORD i = 0; i < s_playerCount; i++) + { + if (Win64_IsActivePlayer(&m_player[i], i)) count++; + } + return count; +} +QNET_STATE IQNet::GetState() { return _iQNetStubState; } +bool IQNet::IsHost() { return s_isHosting; } +HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo) { return S_OK; } +void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; } +void IQNet::ClientJoinGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = false; } +void IQNet::EndGame() +{ + _iQNetStubState = QNET_STATE_IDLE; + s_isHosting = false; + s_playerCount = 1; + for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++) + { + m_player[i].m_smallId = 0; + m_player[i].m_isRemote = false; + m_player[i].m_isHostPlayer = false; + m_player[i].m_gamertag[0] = 0; + m_player[i].SetCustomDataValue(0); + } +} DWORD MinecraftDynamicConfigurations::GetTrialTime() { return DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME; } void XSetThreadProcessor(HANDLE a, int b) {} @@ -448,6 +536,8 @@ void C_4JProfile::Initialise( DWORD dwTitleID, pGameSettings->ucTutorialCompletion[28] |= 1<<0; } } +#endif +#if defined _WINDOWS64 || (defined(__PS3__) && defined(DISABLE_PSN)) void C_4JProfile::SetTrialTextStringTable(CXuiStringTable *pStringTable,int iAccept,int iReject) {} void C_4JProfile::SetTrialAwardText(eAwardType AwardType,int iTitle,int iText) {} int C_4JProfile::GetLockedProfile() { return 0; } @@ -460,11 +550,24 @@ UINT C_4JProfile::DisplayOfflineProfile(int( *Func)(LPVOID,const bool, const UINT C_4JProfile::RequestConvertOfflineToGuestUI(int( *Func)(LPVOID,const bool, const int iPad),LPVOID lpParam,int iQuadrant) { return 0; } void C_4JProfile::SetPrimaryPlayerChanged(bool bVal) {} bool C_4JProfile::QuerySigninStatus(void) { return true; } -void C_4JProfile::GetXUID(int iPad, PlayerUID *pXuid,bool bOnlineXuid) {*pXuid = 0xe000d45248242f2e; } -BOOL C_4JProfile::AreXUIDSEqual(PlayerUID xuid1,PlayerUID xuid2) { return false; } +void C_4JProfile::GetXUID(int iPad, PlayerUID *pXuid,bool bOnlineXuid) +{ + if (iPad != 0) + { + // previously INVALID_XUID + *pXuid = 0; + return; + } + if (IQNet::s_isHosting) + *pXuid = 0xe000d45248242f2e; + else + *pXuid = 0xe000d45248242f2e + WinsockNetLayer::GetLocalSmallId(); +} +BOOL C_4JProfile::AreXUIDSEqual(PlayerUID xuid1,PlayerUID xuid2) { return xuid1 == xuid2; } BOOL C_4JProfile::XUIDIsGuest(PlayerUID xuid) { return false; } bool C_4JProfile::AllowedToPlayMultiplayer(int iProf) { return true; } - +#endif +#ifdef _WINDOWS64 #if defined(__ORBIS__) bool C_4JProfile::GetChatAndContentRestrictions(int iPad, bool thisQuadrantOnly, bool *pbChatRestricted,bool *pbContentRestricted,int *piAge) { @@ -487,8 +590,8 @@ char fakeGamerTag[32] = "PlayerName"; void SetFakeGamertag(char *name){ strcpy_s(fakeGamerTag, name); } char* C_4JProfile::GetGamertag(int iPad){ return fakeGamerTag; } #else -char* C_4JProfile::GetGamertag(int iPad){ return "PlayerName"; } -wstring C_4JProfile::GetDisplayName(int iPad){ return L"PlayerName"; } +char* C_4JProfile::GetGamertag(int iPad){ extern char g_Win64Username[17]; return g_Win64Username; } +wstring C_4JProfile::GetDisplayName(int iPad){ extern wchar_t g_Win64UsernameW[17]; return g_Win64UsernameW; } #endif bool C_4JProfile::IsFullVersion() { return s_bProfileIsFullVersion; } void C_4JProfile::SetSignInChangeCallback(void ( *Func)(LPVOID, bool, unsigned int),LPVOID lpParam) {} diff --git a/Minecraft.Client/Minecraft.Client.vcxproj b/Minecraft.Client/Minecraft.Client.vcxproj index bda9453c..61a84577 100644 --- a/Minecraft.Client/Minecraft.Client.vcxproj +++ b/Minecraft.Client/Minecraft.Client.vcxproj @@ -1201,7 +1201,7 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata" false $(OutDir)$(ProjectName).pch MultiThreadedDebug - _DEBUG_MENUS_ENABLED;_ITERATOR_DEBUG_LEVEL=0;_SECURE_SCL=0;%(PreprocessorDefinitions) + _DISABLE_PSN;_DEBUG_MENUS_ENABLED;_ITERATOR_DEBUG_LEVEL=0;_SECURE_SCL=0;%(PreprocessorDefinitions) Disabled PS3\Iggy\include;$(ProjectDir);%(AdditionalIncludeDirectories) true @@ -1570,7 +1570,7 @@ xcopy /q /y /i /s /e $(ProjectDir)DurangoMedia\CU $(LayoutDir)Image\Loose\CUfalse $(OutDir)$(ProjectName).pch MultiThreaded - _LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) + _DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) Disabled Windows64\Iggy\include;$(ProjectDir);%(AdditionalIncludeDirectories) true @@ -5102,6 +5102,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUtrue true true + true @@ -5124,7 +5125,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUtrue true true - true + false true true true @@ -5192,6 +5193,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUfalse false false + true true @@ -5333,7 +5335,9 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUfalse false false + false + @@ -20022,7 +20026,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUtrue true true - true + false true true true @@ -25262,6 +25266,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUtrue true true + true @@ -25282,7 +25287,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUtrue true true - true + false true true true @@ -25349,6 +25354,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUfalse false false + true true @@ -25489,7 +25495,9 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUfalse false false + false + @@ -34404,7 +34412,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUtrue true true - true + false true true true diff --git a/Minecraft.Client/Minecraft.Client.vcxproj.filters b/Minecraft.Client/Minecraft.Client.vcxproj.filters index ad3f55ca..681c8a46 100644 --- a/Minecraft.Client/Minecraft.Client.vcxproj.filters +++ b/Minecraft.Client/Minecraft.Client.vcxproj.filters @@ -3775,6 +3775,9 @@ PSVita + + Common\Source Files\Network + @@ -5919,6 +5922,9 @@ PSVita + + Common\Source Files\Network + diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 35261db8..ea9dedd6 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -3966,6 +3966,7 @@ void Minecraft::releaseLevel(int message) // time when exiting from an online game void Minecraft::forceStatsSave(int idx) { +#ifndef DISABLE_PSN //4J Gordon: Force a stats save stats[idx]->save(idx, true); @@ -3977,6 +3978,7 @@ void Minecraft::forceStatsSave(int idx) stats[idx]->saveLeaderboards(); ProfileManager.SetLockedProfile(tempLockedProfile); } +#endif } // 4J Added diff --git a/Minecraft.Client/PS3/Network/SQRNetworkManager_PS3.cpp b/Minecraft.Client/PS3/Network/SQRNetworkManager_PS3.cpp index 2f8f11ce..7bb28b0f 100644 --- a/Minecraft.Client/PS3/Network/SQRNetworkManager_PS3.cpp +++ b/Minecraft.Client/PS3/Network/SQRNetworkManager_PS3.cpp @@ -1,4 +1,6 @@ #include "stdafx.h" + +#ifndef DISABLE_PSN #include "SQRNetworkManager_PS3.h" #include "Common/Network/Sony/SQRNetworkPlayer.h" #ifdef __PS3__ @@ -3621,4 +3623,5 @@ int SQRNetworkManager_PS3::GetJoiningReadyPercentage() { return 100; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Minecraft.Client/PS3/Network/SonyCommerce_PS3.cpp b/Minecraft.Client/PS3/Network/SonyCommerce_PS3.cpp index 5bff016d..e84f8db6 100644 --- a/Minecraft.Client/PS3/Network/SonyCommerce_PS3.cpp +++ b/Minecraft.Client/PS3/Network/SonyCommerce_PS3.cpp @@ -1,5 +1,13 @@ #include "stdafx.h" +#ifdef DISABLE_PSN +// global func, so we can call from the profile lib +void SonyCommerce_UpgradeTrial() +{ + // we're now calling the app function here, which manages pending requests + app.UpgradeTrial(); +} +#else #include "SonyCommerce_PS3.h" #include "..\PS3Extras\ShutdownManager.h" #include @@ -1511,3 +1519,4 @@ void SonyCommerce_PS3::DownloadAlreadyPurchased( CallbackFunc cb, LPVOID lpParam +#endif \ No newline at end of file diff --git a/Minecraft.Client/PS3/Network/SonyVoiceChat.cpp b/Minecraft.Client/PS3/Network/SonyVoiceChat.cpp index 4cc65bfc..28d370e4 100644 --- a/Minecraft.Client/PS3/Network/SonyVoiceChat.cpp +++ b/Minecraft.Client/PS3/Network/SonyVoiceChat.cpp @@ -1,5 +1,5 @@ #include "stdafx.h" - +#ifndef DISABLE_PSN @@ -762,3 +762,4 @@ void SonyVoiceChat::setState( EAVCState state ) sm_state = state; printStateAndEvent(); } +#endif \ No newline at end of file diff --git a/Minecraft.Client/PS3/Network/SonyVoiceChat.h b/Minecraft.Client/PS3/Network/SonyVoiceChat.h index a2bcc4bd..2bcafe7a 100644 --- a/Minecraft.Client/PS3/Network/SonyVoiceChat.h +++ b/Minecraft.Client/PS3/Network/SonyVoiceChat.h @@ -1,5 +1,5 @@ #pragma once - +#ifndef _DISABLE_PSN #include #include #include @@ -154,4 +154,5 @@ private: static void printStateAndEvent(); -}; \ No newline at end of file +}; +#endif \ No newline at end of file diff --git a/Minecraft.Client/PS3/PS3_App.cpp b/Minecraft.Client/PS3/PS3_App.cpp index c5f99fbd..da01a307 100644 --- a/Minecraft.Client/PS3/PS3_App.cpp +++ b/Minecraft.Client/PS3/PS3_App.cpp @@ -10,7 +10,9 @@ #include "..\..\Minecraft.World\LevelSettings.h" #include "..\..\Minecraft.World\BiomeSource.h" #include "..\..\Minecraft.World\LevelType.h" +#ifndef DISABLE_PSN #include "..\..\PS3\Network\SonyCommerce_PS3.h" +#endif #include "..\..\Minecraft.World\StringHelpers.h" #include "PS3Extras\ShutdownManager.h" #include "PS3\Network\SonyRemoteStorage_PS3.h" @@ -560,6 +562,7 @@ void CConsoleMinecraftApp::TemporaryCreateGameStart() void CConsoleMinecraftApp::CommerceInit() { +#ifndef DISABLE_PSN m_bCommerceCategoriesRetrieved=false; m_bCommerceProductListRetrieved=false; m_bCommerceInitialised=false; @@ -572,10 +575,12 @@ void CConsoleMinecraftApp::CommerceInit() m_iCurrentCategory=0; m_iCurrentProduct=0; memset(m_pchSkuID,0,48); +#endif } void CConsoleMinecraftApp::CommerceTick() { +#ifndef DISABLE_PSN // only tick this if the primary user is signed in to the PSN if(ProfileManager.IsSignedInLive(0)) { @@ -695,6 +700,7 @@ void CConsoleMinecraftApp::CommerceTick() } } else +#endif { // was the primary player signed in and is now signed out? if(m_eCommerce_State!=eCommerce_State_Offline) diff --git a/Minecraft.Client/PS3/PS3_Minecraft.cpp b/Minecraft.Client/PS3/PS3_Minecraft.cpp index 784c8d64..6f6859aa 100644 --- a/Minecraft.Client/PS3/PS3_Minecraft.cpp +++ b/Minecraft.Client/PS3/PS3_Minecraft.cpp @@ -24,6 +24,7 @@ SYS_PROCESS_PARAM(1001, 0x10000); // thread priority, and stack size #include #include "PS3/Network/SonyRemoteStorage_PS3.h" +#include "..\..\Minecraft.Client\Common\Network\WinsockNetLayer.h" // define to use spurs (otherwise SPU threads or raw will be used) #define USE_SPURS @@ -35,6 +36,9 @@ SYS_PROCESS_PARAM(1001, 0x10000); // thread priority, and stack size #include #endif +#ifdef DISABLE_PSN +#include "../Passphrase/ps3__np_conf.h" +#endif /* Encrypted ID for protected data file (*) You must edit these binaries!! */ char secureFileId[CELL_SAVEDATA_SECUREFILEID_SIZE] = { @@ -519,7 +523,9 @@ void RegisterAwardsWithProfileManager() // Rich Presence init - number of presences, number of contexts //printf("Rich presence strings are hard coded on PS3 for now, must change this!\n"); ProfileManager.RichPresenceInit(-1,-1); // 4J-JEV - Presence and Context count not used. +#ifndef DISABLE_PSN ProfileManager.SetRichPresenceSettingFn(SQRNetworkManager_PS3::SetRichPresence); +#endif char *pchRichPresenceString; pchRichPresenceString=(char *)AddRichPresenceString(IDS_RICHPRESENCE_GAMESTATE); @@ -855,7 +861,9 @@ int main() app.CommerceInit(); // MGH - moved this here so GetCommerce isn't NULL // 4J-PB - Kick of the check for trial or full version - requires ui to be initialised +#ifndef DISABLE_PSN app.GetCommerce()->CheckForTrialUpgradeKey(); +#endif static bool bTrialTimerDisplayed=true; @@ -888,8 +896,13 @@ int main() // Initialise the profile manager with the game Title ID, Offer ID, a profile version number, and the number of profile values and settings +#ifndef DISABLE_PSN ProfileManager.Initialise(SQRNetworkManager_PS3::GetSceNpCommsId(), SQRNetworkManager_PS3::GetSceNpCommsSig(), +#else + ProfileManager.Initialise(&s_npCommunicationId, + &s_npCommunicationSignature, +#endif PROFILE_VERSION_10, NUM_PROFILE_VALUES, NUM_PROFILE_SETTINGS, @@ -1116,6 +1129,7 @@ int main() if(ShutdownManager::ShouldRun(ShutdownManager::eMainThread)) { g_NetworkManager.Initialise(); + WinsockNetLayer::Initialize(); g_NetworkManager.SetLocalGame(true); } diff --git a/Minecraft.Client/PS3/PS3_PlayerUID.h b/Minecraft.Client/PS3/PS3_PlayerUID.h index 63de6be8..73f0a482 100644 --- a/Minecraft.Client/PS3/PS3_PlayerUID.h +++ b/Minecraft.Client/PS3/PS3_PlayerUID.h @@ -2,6 +2,7 @@ #pragma once +//#include "stdafx.h" // Note - there are now 3 types of PlayerUID @@ -19,6 +20,7 @@ class PlayerUID CellSysutilUserId m_userID; // user logged on to the XMB public: + ULONGLONG XUID; class Hash { @@ -29,6 +31,8 @@ public: PlayerUID(); PlayerUID(CellSysutilUserId userID, SceNpOnlineId& onlineID, bool bSignedInPSN, int quadrant); PlayerUID(std::wstring fromString); + PlayerUID(ULONGLONG xuid) { XUID = xuid; } + operator ULONGLONG() const { return XUID; } bool operator==(const PlayerUID& rhs) const; bool operator!=(const PlayerUID& rhs); diff --git a/Minecraft.Client/PendingConnection.cpp b/Minecraft.Client/PendingConnection.cpp index ba93d016..b841ab84 100644 --- a/Minecraft.Client/PendingConnection.cpp +++ b/Minecraft.Client/PendingConnection.cpp @@ -157,6 +157,7 @@ void PendingConnection::handleLogin(shared_ptr packet) //if (true)// 4J removed !server->onlineMode) bool sentDisconnect = false; + bool nameTaken = false; if( sentDisconnect ) { @@ -168,7 +169,29 @@ void PendingConnection::handleLogin(shared_ptr packet) } else { - handleAcceptedLogin(packet); + vector > &pl = server->getPlayers()->players; + + for (unsigned int i = 0; i < pl.size(); i++) + { + if (pl[i] != NULL && pl[i]->name == name) + { + nameTaken = true; + break; + } + } + + if (nameTaken) + { + app.DebugPrintf("Rejecting duplicate name: %ls\n", name.c_str()); + + // to do: replace this with a dedicated duplicate name + // message + disconnect(DisconnectPacket::eDisconnect_Banned); + } + else + { + handleAcceptedLogin(packet); + } } //else { diff --git a/Minecraft.Client/PlayerList.cpp b/Minecraft.Client/PlayerList.cpp index 0deb99c9..21817080 100644 --- a/Minecraft.Client/PlayerList.cpp +++ b/Minecraft.Client/PlayerList.cpp @@ -25,9 +25,9 @@ #include "..\Minecraft.World\net.minecraft.world.level.saveddata.h" #include "..\Minecraft.World\JavaMath.h" #include "..\Minecraft.World\EntityIO.h" -#ifdef _XBOX +#if defined(_XBOX) || defined(_WINDOWS64) || defined(DISABLE_PSN) #include "Xbox\Network\NetworkPlayerXbox.h" -#elif defined(__PS3__) || defined(__ORBIS__) +#elif !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) #include "Common\Network\Sony\NetworkPlayerSony.h" #endif @@ -53,7 +53,11 @@ PlayerList::PlayerList(MinecraftServer *server) //int viewDistance = server->settings->getInt(L"view-distance", 10); +#ifdef _WINDOWS64 + maxPlayers = MINECRAFT_NET_MAX_PLAYERS; +#else maxPlayers = server->settings->getInt(L"max-players", 20); +#endif doWhiteList = false; InitializeCriticalSection(&m_kickPlayersCS); @@ -90,7 +94,7 @@ void PlayerList::placeNewPlayer(Connection *connection, shared_ptr player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_HOST,1); } -#if defined(__PS3__) || defined(__ORBIS__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) // PS3 networking library doesn't automatically assign PlayerUIDs to the network players for anything remote, so need to tell it what to set from the data in this packet now if( !g_NetworkManager.IsLocalGame() ) { @@ -99,6 +103,13 @@ void PlayerList::placeNewPlayer(Connection *connection, shared_ptr ((NetworkPlayerSony *)networkPlayer)->SetUID( packet->m_onlineXuid ); } } +#elif defined(_WINDOWS64) || defined(DISABLE_PSN) + if (networkPlayer != NULL && !networkPlayer->IsLocal()) + { + NetworkPlayerXbox *nxp = (NetworkPlayerXbox *)networkPlayer; + IQNetPlayer *qnp = nxp->GetQNetPlayer(); + wcsncpy(qnp->m_gamertag, player->name.c_str(), 32); + } #endif // 4J Stu - TU-1 hotfix @@ -469,6 +480,7 @@ void PlayerList::remove(shared_ptr player) //4J Stu - We don't want to save the map data for guests, so when we are sure that the player is gone delete the map if(player->isGuest()) playerIo->deleteMapFilesForPlayer(player); ServerLevel *level = player->getLevel(); + level->getTracker()->removeEntity(player); if (player->riding != NULL) { // remove mount first because the player unmounts when being @@ -497,7 +509,7 @@ void PlayerList::remove(shared_ptr player) shared_ptr PlayerList::getPlayerForLogin(PendingConnection *pendingConnection, const wstring& userName, PlayerUID xuid, PlayerUID onlineXuid) { - if (players.size() >= maxPlayers) + if (players.size() >= (unsigned int)MINECRAFT_NET_MAX_PLAYERS) { pendingConnection->disconnect(DisconnectPacket::eDisconnect_ServerFull); return shared_ptr(); @@ -510,9 +522,14 @@ shared_ptr PlayerList::getPlayerForLogin(PendingConnection *pendin // Work out the base server player settings INetworkPlayer *networkPlayer = pendingConnection->connection->getSocket()->getPlayer(); - if(networkPlayer != NULL && !networkPlayer->IsHost()) + if (networkPlayer != NULL) { - player->enableAllPlayerPrivileges( app.GetGameHostOption(eGameHostOption_TrustPlayers)>0 ); + if (!networkPlayer->IsHost()) + player->enableAllPlayerPrivileges( app.GetGameHostOption(eGameHostOption_TrustPlayers)>0 ); + + PlayerUID realXuid = networkPlayer->GetUID(); + player->setXuid(realXuid); + player->setOnlineXuid(realXuid); } // 4J Added diff --git a/Minecraft.Client/Windows64/Windows64_App.cpp b/Minecraft.Client/Windows64/Windows64_App.cpp index 50f66826..0d1bd4ca 100644 --- a/Minecraft.Client/Windows64/Windows64_App.cpp +++ b/Minecraft.Client/Windows64/Windows64_App.cpp @@ -55,7 +55,8 @@ void CConsoleMinecraftApp::TemporaryCreateGameStart() Minecraft *pMinecraft=Minecraft::GetInstance(); app.ReleaseSaveThumbnail(); ProfileManager.SetLockedProfile(0); - pMinecraft->user->name = L"Windows"; + extern wchar_t g_Win64UsernameW[17]; + pMinecraft->user->name = g_Win64UsernameW; app.ApplyGameSettingsChanged(0); ////////////////////////////////////////////////////////////////////////////////////////////// From CScene_MultiGameJoinLoad::OnInit diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp index 0aae8055..24bbae9e 100644 --- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp @@ -36,6 +36,7 @@ #include "Resource.h" #include "..\..\Minecraft.World\compression.h" #include "..\..\Minecraft.World\OldChunkStorage.h" +#include "..\..\Minecraft.Client\Common\Network\WinsockNetLayer.h" #include "Xbox/resource.h" @@ -68,6 +69,9 @@ DWORD dwProfileSettingsA[NUM_PROFILE_VALUES]= #endif }; +char g_Win64Username[17] = {0}; +wchar_t g_Win64UsernameW[17] = {0}; + //------------------------------------------------------------------------------------- // Time Since fAppTime is a float, we need to keep the quadword app time // as a LARGE_INTEGER so that we don't lose precision after running @@ -76,8 +80,8 @@ DWORD dwProfileSettingsA[NUM_PROFILE_VALUES]= BOOL g_bWidescreen = TRUE; -int g_iScreenWidth = 1920; -int g_iScreenHeight = 1080; +int g_iScreenWidth = 1280; +int g_iScreenHeight = 720; void DefineActions(void) { @@ -629,8 +633,58 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, //g_iScreenWidth = 960; //g_iScreenHeight = 544; } + + char cmdLineA[1024]; + strncpy_s(cmdLineA, sizeof(cmdLineA), lpCmdLine, _TRUNCATE); + + char *nameArg = strstr(cmdLineA, "-name "); + if (nameArg) + { + nameArg += 6; + while (*nameArg == ' ') nameArg++; + char nameBuf[17]; + int n = 0; + while (nameArg[n] && nameArg[n] != ' ' && n < 16) { nameBuf[n] = nameArg[n]; n++; } + nameBuf[n] = 0; + strncpy_s(g_Win64Username, 17, nameBuf, _TRUNCATE); + } + + char *ipArg = strstr(cmdLineA, "-ip "); + if (ipArg) + { + ipArg += 4; + while (*ipArg == ' ') ipArg++; + char ipBuf[256]; + int n = 0; + while (ipArg[n] && ipArg[n] != ' ' && n < 255) { ipBuf[n] = ipArg[n]; n++; } + ipBuf[n] = 0; + strncpy_s(g_Win64MultiplayerIP, 256, ipBuf, _TRUNCATE); + g_Win64MultiplayerJoin = true; + } + + char *portArg = strstr(cmdLineA, "-port "); + if (portArg) + { + portArg += 6; + while (*portArg == ' ') portArg++; + char portBuf[16]; + int n = 0; + while (portArg[n] && portArg[n] != ' ' && n < 15) { portBuf[n] = portArg[n]; n++; } + portBuf[n] = 0; + g_Win64MultiplayerPort = atoi(portBuf); + if (g_Win64MultiplayerPort <= 0) g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT; + } } + if (g_Win64Username[0] == 0) + { + DWORD sz = 17; + if (!GetUserNameA(g_Win64Username, &sz)) + strncpy_s(g_Win64Username, 17, "Player", _TRUNCATE); + g_Win64Username[16] = 0; + } + + MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, 17); // Initialize global strings MyRegisterClass(hInstance); @@ -793,7 +847,17 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, // ProfileManager for XN_LIVE_INVITE_ACCEPTED for QNet. g_NetworkManager.Initialise(); + for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++) + { + IQNet::m_player[i].m_smallId = (BYTE)i; + IQNet::m_player[i].m_isRemote = false; + IQNet::m_player[i].m_isHostPlayer = (i == 0); + swprintf_s(IQNet::m_player[i].m_gamertag, 32, L"Player%d", i); + } + extern wchar_t g_Win64UsernameW[17]; + wcscpy_s(IQNet::m_player[0].m_gamertag, 32, g_Win64UsernameW); + WinsockNetLayer::Initialize(); // 4J-PB moved further down //app.InitGameSettings(); @@ -937,6 +1001,9 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, // app.audio.PlaySound(); // } + bool isActive = (GetForegroundWindow() == g_hWnd) && + !IsIconic(g_hWnd); + app.UpdateTime(); PIXBeginNamedEvent(0,"Input manager tick"); InputManager.Tick(); @@ -964,7 +1031,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Network manager do work #1"); - // g_NetworkManager.DoWork(); + g_NetworkManager.DoWork(); PIXEndNamedEvent(); // LeaderboardManager::Instance()->Tick(); diff --git a/Minecraft.World/ConsoleSaveFile.h b/Minecraft.World/ConsoleSaveFile.h index c3370263..e4f403c8 100644 --- a/Minecraft.World/ConsoleSaveFile.h +++ b/Minecraft.World/ConsoleSaveFile.h @@ -30,7 +30,7 @@ public: virtual vector *getFilesWithPrefix(const wstring &prefix) = 0; virtual vector *getRegionFilesByDimension(unsigned int dimensionIndex) = 0; -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) virtual wstring getPlayerDataFilenameForLoad(const PlayerUID& pUID) = 0; virtual wstring getPlayerDataFilenameForSave(const PlayerUID& pUID) = 0; virtual vector *getValidPlayerDatFiles() = 0; diff --git a/Minecraft.World/ConsoleSaveFileConverter.cpp b/Minecraft.World/ConsoleSaveFileConverter.cpp index 7934d19d..a509fb4f 100644 --- a/Minecraft.World/ConsoleSaveFileConverter.cpp +++ b/Minecraft.World/ConsoleSaveFileConverter.cpp @@ -78,7 +78,7 @@ void ConsoleSaveFileConverter::ConvertSave(ConsoleSaveFile *sourceSave, ConsoleS } // MGH added - find any player data files and copy them across -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) vector* playerFiles = sourceSave->getValidPlayerDatFiles(); #else vector *playerFiles = sourceSave->getFilesWithPrefix( DirectoryLevelStorage::getPlayerDir() ); diff --git a/Minecraft.World/ConsoleSaveFileOriginal.cpp b/Minecraft.World/ConsoleSaveFileOriginal.cpp index d3e734e1..ec7ead0f 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.cpp +++ b/Minecraft.World/ConsoleSaveFileOriginal.cpp @@ -920,7 +920,7 @@ vector *ConsoleSaveFileOriginal::getRegionFilesByDimension(unsigned return NULL; } -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) wstring ConsoleSaveFileOriginal::getPlayerDataFilenameForLoad(const PlayerUID& pUID) { return header.getPlayerDataFilenameForLoad( pUID ); diff --git a/Minecraft.World/ConsoleSaveFileOriginal.h b/Minecraft.World/ConsoleSaveFileOriginal.h index fee8dc2e..39a56fa9 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.h +++ b/Minecraft.World/ConsoleSaveFileOriginal.h @@ -65,7 +65,7 @@ public: virtual vector *getFilesWithPrefix(const wstring &prefix); virtual vector *getRegionFilesByDimension(unsigned int dimensionIndex); -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) virtual wstring getPlayerDataFilenameForLoad(const PlayerUID& pUID); virtual wstring getPlayerDataFilenameForSave(const PlayerUID& pUID); virtual vector *getValidPlayerDatFiles(); diff --git a/Minecraft.World/DataInputStream.cpp b/Minecraft.World/DataInputStream.cpp index b1c5a77c..db9df5a5 100644 --- a/Minecraft.World/DataInputStream.cpp +++ b/Minecraft.World/DataInputStream.cpp @@ -519,7 +519,7 @@ int DataInputStream::readUTFChar() PlayerUID DataInputStream::readPlayerUID() { PlayerUID returnValue; -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) for(int idPos=0;idPos player) { CompoundTag *tag = new CompoundTag(); player->saveWithoutId(tag); -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) ConsoleSavePath realFile = ConsoleSavePath( m_saveFile->getPlayerDataFilenameForSave(playerXuid).c_str() ); #elif defined(_DURANGO) ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + player->getXuid().toString() + L".dat" ); @@ -442,7 +442,7 @@ CompoundTag *DirectoryLevelStorage::load(shared_ptr player) CompoundTag *DirectoryLevelStorage::loadPlayerDataTag(PlayerUID xuid) { // 4J Jev, removed try/catch. -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) ConsoleSavePath realFile = ConsoleSavePath( m_saveFile->getPlayerDataFilenameForLoad(xuid).c_str() ); #elif defined(_DURANGO) ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + xuid.toString() + L".dat" ); @@ -472,7 +472,7 @@ void DirectoryLevelStorage::clearOldPlayerFiles() { if(StorageManager.GetSaveDisabled() ) return; -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) vector *playerFiles = m_saveFile->getValidPlayerDatFiles(); #else vector *playerFiles = m_saveFile->getFilesWithPrefix( playerDir.getName() ); @@ -561,7 +561,7 @@ void DirectoryLevelStorage::resetNetherPlayerPositions() { if(app.GetResetNether()) { -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +#if !defined(DISABLE_PSN) && defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) vector *playerFiles = m_saveFile->getValidPlayerDatFiles(); #else vector *playerFiles = m_saveFile->getFilesWithPrefix( playerDir.getName() ); diff --git a/Minecraft.World/Minecraft.World.vcxproj b/Minecraft.World/Minecraft.World.vcxproj index 4169c2d7..6c0f5133 100644 --- a/Minecraft.World/Minecraft.World.vcxproj +++ b/Minecraft.World/Minecraft.World.vcxproj @@ -1197,7 +1197,7 @@ false $(OutDir)$(ProjectName).pch MultiThreaded - _LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) + _DEBUG_MENUS_ENABLED;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) Disabled true false diff --git a/Minecraft.World/compression.cpp b/Minecraft.World/compression.cpp index aa07c005..bada5069 100644 --- a/Minecraft.World/compression.cpp +++ b/Minecraft.World/compression.cpp @@ -334,8 +334,9 @@ HRESULT Compression::Decompress(void *pDestination, unsigned int *pDestSize, voi *pDestSize = (unsigned int)destSize; return ( ( res == Z_OK ) ? S_OK : -1 ); #elif defined __PS3__ - uint32_t destSize = (uint32_t)(*pDestSize); - bool res = EdgeZLib::Decompress(pDestination, &destSize, pSource, SrcSize); + uLongf destSize = (uLongf)(*pDestSize); + bool res = uncompress((Bytef*)pDestination, &destSize, (Bytef*)pSource, SrcSize); + *pDestSize = (unsigned int)destSize; return ( ( res ) ? S_OK : -1 ); #else diff --git a/Minecraft.World/x64headers/extraX64.h b/Minecraft.World/x64headers/extraX64.h index 0049ffbc..783834d9 100644 --- a/Minecraft.World/x64headers/extraX64.h +++ b/Minecraft.World/x64headers/extraX64.h @@ -11,6 +11,10 @@ #define MULTITHREAD_ENABLE +#ifdef __PS3__ +#define DISABLE_PSN +#endif + typedef unsigned char byte; const int XUSER_INDEX_ANY = 255; @@ -42,9 +46,15 @@ typedef SQRNetworkManager_Orbis::PresenceSyncInfo INVITE_INFO; #include #include #include "..\..\Minecraft.Client\PS3\PS3_PlayerUID.h" + +#ifndef DISABLE_PSN #include "..\..\Minecraft.Client\PS3\Network\SQRNetworkManager_PS3.h" typedef SQRNetworkManager::SessionID SessionID; typedef SQRNetworkManager::PresenceSyncInfo INVITE_INFO; +#else +typedef ULONGLONG SessionID; +class INVITE_INFO; +#endif #elif defined __PSVITA__ #include @@ -215,10 +225,17 @@ public: int GetUserIndex(); void SetCustomDataValue(ULONG_PTR ulpCustomDataValue); ULONG_PTR GetCustomDataValue(); + + BYTE m_smallId; + bool m_isRemote; + bool m_isHostPlayer; + wchar_t m_gamertag[32]; private: ULONG_PTR m_customData; }; +void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal); + const int QNET_GETSENDQUEUESIZE_SECONDARY_TYPE = 0; const int QNET_GETSENDQUEUESIZE_MESSAGES = 0; const int QNET_GETSENDQUEUESIZE_BYTES = 0; @@ -309,9 +326,12 @@ public: bool IsHost(); HRESULT JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo); void HostGame(); + void ClientJoinGame(); void EndGame(); - static IQNetPlayer m_player[4]; + static IQNetPlayer m_player[MINECRAFT_NET_MAX_PLAYERS]; + static DWORD s_playerCount; + static bool s_isHosting; }; #ifdef _DURANGO