aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Common
diff options
context:
space:
mode:
authorlspepinho <162769565+lspepinho@users.noreply.github.com>2026-03-02 20:30:22 -0300
committerGitHub <noreply@github.com>2026-03-03 06:30:22 +0700
commit8b28c20d7adc3824f96fbcc34ad65d778a97a05b (patch)
treee61705a557e4e064d707ec542c53dbdac1acbe09 /Minecraft.Client/Common
parent15129932da9442c2815974c519258345b22d5588 (diff)
Fixes for PR #96 (#170)
* Implement basic multiplayer functionality * Update README.md --------- Co-authored-by: Slenderman <ssimulpong@outlook.com>
Diffstat (limited to 'Minecraft.Client/Common')
-rw-r--r--Minecraft.Client/Common/Consoles_App.cpp2
-rw-r--r--Minecraft.Client/Common/Network/GameNetworkManager.cpp10
-rw-r--r--Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h1
-rw-r--r--Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp225
-rw-r--r--Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h3
-rw-r--r--Minecraft.Client/Common/Network/SessionInfo.h36
-rw-r--r--Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp9
7 files changed, 262 insertions, 24 deletions
diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp
index 38397814..0e02ab40 100644
--- a/Minecraft.Client/Common/Consoles_App.cpp
+++ b/Minecraft.Client/Common/Consoles_App.cpp
@@ -3402,7 +3402,7 @@ void CMinecraftApp::HandleXuiActions(void)
bool gameStarted = false;
for(int j = 0; j < pMinecraft->levels.length; j++)
{
- if (pMinecraft->levels.data[i] != NULL)
+ if (pMinecraft->levels.data[i] != nullptr)
{
gameStarted = true;
break;
diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Common/Network/GameNetworkManager.cpp
index 940a148e..b3fb5cd7 100644
--- a/Minecraft.Client/Common/Network/GameNetworkManager.cpp
+++ b/Minecraft.Client/Common/Network/GameNetworkManager.cpp
@@ -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;
@@ -1479,7 +1484,10 @@ void CGameNetworkManager::CreateSocket( INetworkPlayer *pNetworkPlayer, bool loc
Minecraft *pMinecraft = Minecraft::GetInstance();
Socket *socket = NULL;
- shared_ptr<MultiplayerLocalPlayer> mpPlayer = pMinecraft->localplayers[pNetworkPlayer->GetUserIndex()];
+ shared_ptr<MultiplayerLocalPlayer> mpPlayer = nullptr;
+ int userIdx = pNetworkPlayer->GetUserIndex();
+ if (userIdx >= 0 && userIdx < XUSER_MAX_COUNT)
+ mpPlayer = pMinecraft->localplayers[userIdx];
if( localPlayer && mpPlayer != NULL && mpPlayer->connection != NULL)
{
// If we already have a MultiplayerLocalPlayer here then we are doing a session type change
diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h b/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h
index 901e59e7..31c415a7 100644
--- a/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h
+++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h
@@ -84,6 +84,7 @@ public:
virtual void HandleSignInChange() = 0;
virtual bool _RunNetworkGame() = 0;
+ virtual void SetGamePlayState() {}
private:
virtual bool _LeaveGame(bool bMigrateHost, bool bLeaveRoom) = 0;
diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp
index b6b0fe12..10d1a6a5 100644
--- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp
+++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp
@@ -2,7 +2,12 @@
#include "..\..\..\Minecraft.World\Socket.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "PlatformNetworkManagerStub.h"
-#include "..\..\Xbox\Network\NetworkPlayerXbox.h" // TODO - stub version of this?
+#include "..\..\Xbox\Network\NetworkPlayerXbox.h"
+#ifdef _WINDOWS64
+#include "..\..\Windows64\Network\WinsockNetLayer.h"
+#include "..\..\Minecraft.h"
+#include "..\..\User.h"
+#endif
CPlatformNetworkManagerStub *g_pPlatformNetworkManager;
@@ -114,10 +119,43 @@ 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 +212,37 @@ 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()
{
+#ifdef _WINDOWS64
+ 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--;
+ }
+ }
+ }
+#endif
}
int CPlatformNetworkManagerStub::GetPlayerCount()
@@ -232,6 +301,10 @@ bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost)
m_bLeavingGame = true;
+#ifdef _WINDOWS64
+ WinsockNetLayer::StopAdvertising();
+#endif
+
// If we are the host wait for the game server to end
if(m_pIQNet->IsHost() && g_NetworkManager.ServerStoppedValid())
{
@@ -239,6 +312,22 @@ 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();
+
+#ifdef _WINDOWS64
+ WinsockNetLayer::Shutdown();
+ WinsockNetLayer::Initialize();
+#endif
+
return true;
}
@@ -262,7 +351,24 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame,
m_pIQNet->HostGame();
+#ifdef _WINDOWS64
+ 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;
+#endif
+
_HostGame( localUsersMask, publicSlots, privateSlots );
+
+#ifdef _WINDOWS64
+ 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
//#endif
}
@@ -275,9 +381,54 @@ bool CPlatformNetworkManagerStub::_StartGame()
return true;
}
-int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo *searchResult, int localUsersMask, int primaryUserIndex)
+int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int localUsersMask, int primaryUserIndex)
{
+#ifdef _WINDOWS64
+ 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_s(IQNet::m_player[0].m_gamertag, 32, searchResult->data.hostName, _TRUNCATE);
+
+ 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();
+ wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str());
+ IQNet::s_playerCount = localSmallId + 1;
+
+ NotifyPlayerJoined(&IQNet::m_player[0]);
+ NotifyPlayerJoined(&IQNet::m_player[localSmallId]);
+
+ m_pGameNetworkManager->StateChange_AnyToStarting();
+
return CGameNetworkManager::JOINGAME_SUCCESS;
+#else
+ return CGameNetworkManager::JOINGAME_SUCCESS;
+#endif
}
bool CPlatformNetworkManagerStub::SetLocalGame(bool isLocal)
@@ -315,6 +466,22 @@ void CPlatformNetworkManagerStub::HandleSignInChange()
bool CPlatformNetworkManagerStub::_RunNetworkGame()
{
+#ifdef _WINDOWS64
+ 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());
+ }
+ }
+ }
+#endif
return true;
}
@@ -503,10 +670,60 @@ wstring CPlatformNetworkManagerStub::GatherRTTStats()
void CPlatformNetworkManagerStub::TickSearch()
{
+#ifdef _WINDOWS64
+ if (m_SessionsUpdatedCallback == NULL)
+ return;
+
+ static DWORD lastSearchTime = 0;
+ DWORD now = GetTickCount();
+ if (now - lastSearchTime < 2000)
+ return;
+ lastSearchTime = now;
+
+ SearchForGames();
+#endif
}
void CPlatformNetworkManagerStub::SearchForGames()
{
+#ifdef _WINDOWS64
+ std::vector<Win64LANSession> lanSessions = WinsockNetLayer::GetDiscoveredSessions();
+
+ 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];
+ wcscpy_s(info->displayLabel, nameLen + 1, lanSessions[i].hostName);
+ 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_s(info->data.hostIP, sizeof(info->data.hostIP), lanSessions[i].hostIP, _TRUNCATE);
+ info->data.hostPort = lanSessions[i].hostPort;
+ wcsncpy_s(info->data.hostName, XUSER_NAME_SIZE, lanSessions[i].hostName, _TRUNCATE);
+ info->data.playerCount = lanSessions[i].playerCount;
+ info->data.maxPlayers = lanSessions[i].maxPlayers;
+
+ info->sessionId = (SessionID)((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);
+#endif
}
int CPlatformNetworkManagerStub::SearchForGamesThreadProc( void* lpParameter )
@@ -522,7 +739,9 @@ void CPlatformNetworkManagerStub::SetSearchResultsReady(int resultCount)
vector<FriendSessionInfo *> *CPlatformNetworkManagerStub::GetSessionList(int iPad, int localPlayers, bool partyOnly)
{
- vector<FriendSessionInfo *> *filteredList = new vector<FriendSessionInfo *>();;
+ vector<FriendSessionInfo*>* filteredList = new vector<FriendSessionInfo*>();
+ 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 f997dece..28953cec 100644
--- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h
+++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h
@@ -161,8 +161,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 31472a19..ce6365bc 100644
--- a/Minecraft.Client/Common/Network/SessionInfo.h
+++ b/Minecraft.Client/Common/Network/SessionInfo.h
@@ -23,9 +23,9 @@ typedef struct _GameSessionData
_GameSessionData()
{
netVersion = 0;
- memset(hostName,0,XUSER_NAME_SIZE);
- memset(players,0,MINECRAFT_NET_MAX_PLAYERS*sizeof(players[0]));
- memset(szPlayers,0,MINECRAFT_NET_MAX_PLAYERS*XUSER_NAME_SIZE);
+ memset(hostName, 0, XUSER_NAME_SIZE);
+ memset(players, 0, MINECRAFT_NET_MAX_PLAYERS * sizeof(players[0]));
+ memset(szPlayers, 0, MINECRAFT_NET_MAX_PLAYERS * XUSER_NAME_SIZE);
isJoinable = true;
m_uiGameHostSettings = 0;
texturePackParentId = 0;
@@ -50,7 +50,7 @@ typedef struct _GameSessionData
_GameSessionData()
{
netVersion = 0;
- memset(players,0,MINECRAFT_NET_MAX_PLAYERS*sizeof(players[0]));
+ memset(players, 0, MINECRAFT_NET_MAX_PLAYERS * sizeof(players[0]));
isJoinable = true;
m_uiGameHostSettings = 0;
texturePackParentId = 0;
@@ -63,12 +63,19 @@ typedef struct _GameSessionData
#else
typedef struct _GameSessionData
{
- unsigned short netVersion; // 2 bytes
- unsigned int m_uiGameHostSettings; // 4 bytes
- unsigned int texturePackParentId; // 4 bytes
- unsigned char subTexturePackId; // 1 byte
+ unsigned short netVersion;
+ unsigned int m_uiGameHostSettings;
+ unsigned int texturePackParentId;
+ unsigned char subTexturePackId;
- bool isReadyToJoin; // 1 byte
+ bool isReadyToJoin;
+ bool isJoinable;
+
+ char hostIP[64];
+ int hostPort;
+ wchar_t hostName[XUSER_NAME_SIZE];
+ unsigned char playerCount;
+ unsigned char maxPlayers;
_GameSessionData()
{
@@ -76,6 +83,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
@@ -91,7 +105,7 @@ public:
#elif defined(_DURANGO)
DQRNetworkManager::SessionSearchResult searchResult;
#endif
- wchar_t *displayLabel;
+ wchar_t* displayLabel;
unsigned char displayLabelLength;
unsigned char displayLabelViewableStartIndex;
GameSessionData data;
@@ -107,7 +121,7 @@ public:
~FriendSessionInfo()
{
- if(displayLabel!=NULL)
+ if (displayLabel != NULL)
delete displayLabel;
}
};
diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
index 4e48e395..2059c76f 100644
--- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
@@ -284,13 +284,8 @@ UIScene_LoadOrJoinMenu::~UIScene_LoadOrJoinMenu()
g_NetworkManager.SetSessionsUpdatedCallback( NULL, NULL );
app.SetLiveLinkRequired( false );
- if(m_currentSessions)
- {
- for(AUTO_VAR(it, m_currentSessions->begin()); it < m_currentSessions->end(); ++it)
- {
- delete (*it);
- }
- }
+ delete m_currentSessions;
+ m_currentSessions = NULL;
#if TO_BE_IMPLEMENTED
// Reset the background downloading, in case we changed it by attempting to download a texture pack