915 lines
27 KiB
C++
915 lines
27 KiB
C++
#include "stdafx.h"
|
|
#include "../../../Minecraft.World/Socket.h"
|
|
#include "../../../Minecraft.World/StringHelpers.h"
|
|
#include "PlatformNetworkManagerStub.h"
|
|
#include "../../Xbox/Network/NetworkPlayerXbox.h"
|
|
#ifdef _WINDOWS64
|
|
#include "../../Windows64/Network/WinsockNetLayer.h"
|
|
#include "../../Windows64/Windows64_Xuid.h"
|
|
#include "../../Minecraft.h"
|
|
#include "../../User.h"
|
|
#include "../../MinecraftServer.h"
|
|
#include "../../PlayerList.h"
|
|
#include <iostream>
|
|
#endif
|
|
|
|
extern int g_Win64RelayServerPort;
|
|
extern bool g_Win64LCENServer;
|
|
|
|
CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
|
|
|
|
void CPlatformNetworkManagerStub::NotifyPlayerJoined(IQNetPlayer* pQNetPlayer)
|
|
{
|
|
const char* pszDescription;
|
|
|
|
bool createFakeSocket = false;
|
|
bool localPlayer = false;
|
|
|
|
NetworkPlayerXbox* networkPlayer = static_cast<NetworkPlayerXbox*>(addNetworkPlayer(pQNetPlayer));
|
|
|
|
if (pQNetPlayer->IsLocal())
|
|
{
|
|
localPlayer = true;
|
|
if (pQNetPlayer->IsHost())
|
|
{
|
|
pszDescription = "local host";
|
|
m_machineQNetPrimaryPlayers.push_back(pQNetPlayer);
|
|
}
|
|
else
|
|
{
|
|
pszDescription = "local";
|
|
createFakeSocket = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pQNetPlayer->IsHost())
|
|
{
|
|
pszDescription = "remote host";
|
|
}
|
|
else
|
|
{
|
|
pszDescription = "remote";
|
|
if (m_pIQNet->IsHost())
|
|
createFakeSocket = true;
|
|
}
|
|
|
|
if (m_pIQNet->IsHost() && !m_bHostChanged)
|
|
{
|
|
bool systemHasPrimaryPlayer = false;
|
|
for (auto& pQNetPrimaryPlayer : m_machineQNetPrimaryPlayers)
|
|
{
|
|
if (pQNetPlayer->IsSameSystem(pQNetPrimaryPlayer))
|
|
{
|
|
systemHasPrimaryPlayer = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!systemHasPrimaryPlayer)
|
|
m_machineQNetPrimaryPlayers.push_back(pQNetPlayer);
|
|
}
|
|
}
|
|
|
|
g_NetworkManager.PlayerJoining(networkPlayer);
|
|
|
|
if (createFakeSocket && !m_bHostChanged)
|
|
g_NetworkManager.CreateSocket(networkPlayer, localPlayer);
|
|
|
|
app.DebugPrintf("Player 0x%p \"%ls\" joined; %s; voice %i; camera %i.\n",
|
|
pQNetPlayer,
|
|
pQNetPlayer->GetGamertag(),
|
|
pszDescription,
|
|
pQNetPlayer->HasVoice(),
|
|
pQNetPlayer->HasCamera());
|
|
|
|
if (m_pIQNet->IsHost())
|
|
SystemFlagAddPlayer(networkPlayer);
|
|
|
|
for (int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
|
|
{
|
|
if (playerChangedCallback[idx] != nullptr)
|
|
playerChangedCallback[idx](playerChangedCallbackParam[idx], networkPlayer, false);
|
|
}
|
|
|
|
if (m_pIQNet->GetState() == QNET_STATE_GAME_PLAY)
|
|
{
|
|
int localPlayerCount = 0;
|
|
for (unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
|
|
{
|
|
if (m_pIQNet->GetLocalPlayerByUserIndex(idx) != nullptr) ++localPlayerCount;
|
|
}
|
|
m_lastPlayerEventTimeStart = app.getAppTime();
|
|
}
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer* pQNetPlayer)
|
|
{
|
|
app.DebugPrintf("Player 0x%p \"%ls\" leaving.\n", pQNetPlayer, pQNetPlayer->GetGamertag());
|
|
|
|
INetworkPlayer* networkPlayer = getNetworkPlayer(pQNetPlayer);
|
|
if (networkPlayer == nullptr)
|
|
return;
|
|
|
|
Socket* socket = networkPlayer->GetSocket();
|
|
if (socket != nullptr)
|
|
{
|
|
if (m_pIQNet->IsHost())
|
|
{
|
|
g_NetworkManager.CloseConnection(networkPlayer);
|
|
socket->close(true);
|
|
}
|
|
}
|
|
|
|
if (m_pIQNet->IsHost())
|
|
SystemFlagRemovePlayer(networkPlayer);
|
|
|
|
g_NetworkManager.PlayerLeaving(networkPlayer);
|
|
|
|
for (int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
|
|
{
|
|
if (playerChangedCallback[idx] != nullptr)
|
|
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++)
|
|
playerChangedCallback[i] = nullptr;
|
|
|
|
m_bLeavingGame = false;
|
|
m_bLeaveGameOnTick = false;
|
|
m_bHostChanged = false;
|
|
|
|
m_bSearchResultsReady = false;
|
|
m_bSearchPending = false;
|
|
m_bIsOfflineGame = false;
|
|
|
|
#ifdef _WINDOWS64
|
|
m_bJoinPending = false;
|
|
#endif
|
|
|
|
m_pSearchParam = nullptr;
|
|
m_SessionsUpdatedCallback = nullptr;
|
|
|
|
for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
|
|
{
|
|
m_searchResultsCount[i] = 0;
|
|
m_lastSearchStartTime[i] = 0;
|
|
m_pSearchResults[i] = nullptr;
|
|
m_pQoSResult[i] = nullptr;
|
|
m_pCurrentSearchResults[i] = nullptr;
|
|
m_pCurrentQoSResult[i] = nullptr;
|
|
m_currentSearchResultsCount[i] = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::Terminate() {}
|
|
|
|
int CPlatformNetworkManagerStub::GetJoiningReadyPercentage() { return 100; }
|
|
int CPlatformNetworkManagerStub::CorrectErrorIDS(int IDS) { return IDS; }
|
|
|
|
bool CPlatformNetworkManagerStub::isSystemPrimaryPlayer(IQNetPlayer* pQNetPlayer) { return true; }
|
|
|
|
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 != nullptr && qnetPlayer->m_smallId == disconnectedSmallId)
|
|
{
|
|
NotifyPlayerLeaving(qnetPlayer);
|
|
qnetPlayer->m_smallId = 0;
|
|
qnetPlayer->m_isRemote = false;
|
|
qnetPlayer->m_isHostPlayer = false;
|
|
qnetPlayer->m_resolvedXuid = INVALID_XUID;
|
|
qnetPlayer->m_gamertag[0] = 0;
|
|
qnetPlayer->SetCustomDataValue(0);
|
|
|
|
// Recalculate s_playerCount: scan from the top, drop empty trailing slots.
|
|
while (IQNet::s_playerCount > 1 &&
|
|
IQNet::m_player[IQNet::s_playerCount - 1].GetCustomDataValue() == 0)
|
|
IQNet::s_playerCount--;
|
|
}
|
|
SystemFlagRemoveBySmallId(disconnectedSmallId);
|
|
}
|
|
}
|
|
|
|
// Client-side host disconnect detection.
|
|
if (_iQNetStubState == QNET_STATE_GAME_PLAY && !m_pIQNet->IsHost() && !m_bLeavingGame)
|
|
{
|
|
if (!WinsockNetLayer::IsConnected())
|
|
{
|
|
if (!m_bLeaveGameOnTick)
|
|
{
|
|
m_bLeaveGameOnTick = true;
|
|
g_NetworkManager.HandleDisconnect(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bLeaveGameOnTick = false;
|
|
}
|
|
}
|
|
|
|
// Async join finalization.
|
|
if (m_bJoinPending)
|
|
{
|
|
WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState();
|
|
|
|
if (state == WinsockNetLayer::eJoinState_Success)
|
|
{
|
|
if (!WinsockNetLayer::FinalizeJoin())
|
|
{
|
|
app.DebugPrintf("DoWork: FinalizeJoin failed\n");
|
|
m_bJoinPending = false;
|
|
return;
|
|
}
|
|
|
|
BYTE localSmallId = WinsockNetLayer::GetLocalSmallId();
|
|
if (localSmallId == 0 || localSmallId >= MINECRAFT_NET_MAX_PLAYERS)
|
|
{
|
|
app.DebugPrintf("DoWork: bad localSmallId=%d from FinalizeJoin\n", localSmallId);
|
|
m_bJoinPending = false;
|
|
return;
|
|
}
|
|
|
|
// Clear stale slots between host (0) and our slot so
|
|
// GetPlayerBySmallId can't resolve them to ghost players.
|
|
for (BYTE i = 1; i < localSmallId; i++)
|
|
{
|
|
IQNet::m_player[i].m_smallId = 0xFF;
|
|
IQNet::m_player[i].m_isRemote = false;
|
|
IQNet::m_player[i].m_isHostPlayer = false;
|
|
IQNet::m_player[i].m_resolvedXuid = INVALID_XUID;
|
|
IQNet::m_player[i].m_gamertag[0] = 0;
|
|
IQNet::m_player[i].SetCustomDataValue(0);
|
|
}
|
|
|
|
IQNet::m_player[localSmallId].m_smallId = localSmallId;
|
|
IQNet::m_player[localSmallId].m_isRemote = false;
|
|
IQNet::m_player[localSmallId].m_isHostPlayer = false;
|
|
IQNet::m_player[localSmallId].m_resolvedXuid = Win64Xuid::ResolvePersistentXuid();
|
|
|
|
Minecraft* pMinecraft = Minecraft::GetInstance();
|
|
wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str());
|
|
IQNet::s_playerCount = localSmallId + 1;
|
|
|
|
// Register host slot then our local slot so the socket and player
|
|
// objects exist before the recv thread dispatches any inbound packets.
|
|
NotifyPlayerJoined(&IQNet::m_player[0]);
|
|
NotifyPlayerJoined(&IQNet::m_player[localSmallId]);
|
|
|
|
// MUST be called after NotifyPlayerJoined: recv thread needs the
|
|
// INetworkPlayer sockets created above to route HandleDataReceived.
|
|
WinsockNetLayer::StartClientRecvThread();
|
|
|
|
m_pGameNetworkManager->StateChange_AnyToStarting();
|
|
m_bJoinPending = false;
|
|
}
|
|
else if (state == WinsockNetLayer::eJoinState_Failed ||
|
|
state == WinsockNetLayer::eJoinState_Rejected ||
|
|
state == WinsockNetLayer::eJoinState_Cancelled)
|
|
{
|
|
if (state == WinsockNetLayer::eJoinState_Rejected)
|
|
{
|
|
DisconnectPacket::eDisconnectReason reason = WinsockNetLayer::GetJoinRejectReason();
|
|
Minecraft::GetInstance()->connectionDisconnected(
|
|
ProfileManager.GetPrimaryPad(), reason);
|
|
}
|
|
m_bJoinPending = false;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::CanAcceptMoreConnections()
|
|
{
|
|
#ifdef _WINDOWS64
|
|
MinecraftServer* server = MinecraftServer::getInstance();
|
|
if (server == NULL) return true;
|
|
PlayerList* list = server->getPlayerList();
|
|
if (list == NULL) return true;
|
|
return static_cast<unsigned int>(list->players.size()) <
|
|
static_cast<unsigned int>(list->getMaxPlayers());
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
int CPlatformNetworkManagerStub::GetPlayerCount() { return m_pIQNet->GetPlayerCount(); }
|
|
bool CPlatformNetworkManagerStub::ShouldMessageForFullSession() { return false; }
|
|
int CPlatformNetworkManagerStub::GetOnlinePlayerCount() { return 1; }
|
|
int CPlatformNetworkManagerStub::GetLocalPlayerMask(int playerIndex) { return 1 << playerIndex; }
|
|
|
|
bool CPlatformNetworkManagerStub::AddLocalPlayerByUserIndex(int userIndex)
|
|
{
|
|
if (m_pIQNet->AddLocalPlayerByUserIndex(userIndex) != S_OK)
|
|
return false;
|
|
NotifyPlayerJoined(&IQNet::m_player[userIndex]);
|
|
return true;
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::RemoveLocalPlayerByUserIndex(int userIndex)
|
|
{
|
|
#ifdef _WINDOWS64
|
|
if (userIndex > 0 && userIndex < XUSER_MAX_COUNT && !m_pIQNet->IsHost())
|
|
{
|
|
IQNetPlayer* qp = &IQNet::m_player[userIndex];
|
|
if (qp->GetCustomDataValue() != 0)
|
|
NotifyPlayerLeaving(qp);
|
|
WinsockNetLayer::CloseSplitScreenConnection(userIndex);
|
|
qp->m_smallId = 0;
|
|
qp->m_isRemote = false;
|
|
qp->m_isHostPlayer = false;
|
|
qp->m_resolvedXuid = INVALID_XUID;
|
|
qp->m_gamertag[0] = 0;
|
|
qp->SetCustomDataValue(0);
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::IsInStatsEnabledSession() { return true; }
|
|
bool CPlatformNetworkManagerStub::SessionHasSpace(unsigned int spaceRequired) { return true; }
|
|
void CPlatformNetworkManagerStub::SendInviteGUI(int quadrant) {}
|
|
bool CPlatformNetworkManagerStub::IsAddingPlayer() { return false; }
|
|
|
|
bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost)
|
|
{
|
|
if (m_bLeavingGame) return true;
|
|
|
|
m_bLeavingGame = true;
|
|
m_bLeaveGameOnTick = false;
|
|
|
|
#ifdef _WINDOWS64
|
|
WinsockNetLayer::StopAdvertising();
|
|
#endif
|
|
|
|
if (m_pIQNet->IsHost() && g_NetworkManager.ServerStoppedValid())
|
|
{
|
|
m_pIQNet->EndGame();
|
|
g_NetworkManager.ServerStoppedWait();
|
|
g_NetworkManager.ServerStoppedDestroy();
|
|
}
|
|
else
|
|
{
|
|
m_pIQNet->EndGame();
|
|
}
|
|
|
|
for (auto& it : currentNetworkPlayers)
|
|
delete it;
|
|
currentNetworkPlayers.clear();
|
|
m_machineQNetPrimaryPlayers.clear();
|
|
SystemFlagReset();
|
|
|
|
#ifdef _WINDOWS64
|
|
WinsockNetLayer::Shutdown();
|
|
WinsockNetLayer::Initialize();
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::_LeaveGame(bool bMigrateHost, bool bLeaveRoom) { return true; }
|
|
|
|
void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate,
|
|
unsigned char publicSlots, unsigned char privateSlots)
|
|
{
|
|
SetLocalGame(!bOnlineGame);
|
|
SetPrivateGame(bIsPrivate);
|
|
SystemFlagReset();
|
|
|
|
localUsersMask |= GetLocalPlayerMask(g_NetworkManager.GetPrimaryPad());
|
|
|
|
m_bLeavingGame = false;
|
|
m_bLeaveGameOnTick = false;
|
|
|
|
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::m_player[0].m_resolvedXuid = Win64Xuid::GetLegacyEmbeddedHostXuid();
|
|
IQNet::s_playerCount = 1;
|
|
#endif
|
|
|
|
_HostGame(localUsersMask, publicSlots, privateSlots);
|
|
|
|
#ifdef _WINDOWS64
|
|
int port = WIN64_NET_DEFAULT_PORT;
|
|
const char* bindIp = nullptr;
|
|
if (g_Win64DedicatedServer)
|
|
{
|
|
if (g_Win64DedicatedServerPort > 0)
|
|
port = g_Win64DedicatedServerPort;
|
|
if (g_Win64DedicatedServerBindIP[0] != 0)
|
|
bindIp = g_Win64DedicatedServerBindIP;
|
|
}
|
|
|
|
if (!WinsockNetLayer::IsActive())
|
|
WinsockNetLayer::HostGame(port, bindIp);
|
|
|
|
if (WinsockNetLayer::IsActive())
|
|
{
|
|
bool enableLanAdvertising = !g_Win64DedicatedServer || g_Win64DedicatedServerLanAdvertise;
|
|
|
|
if (enableLanAdvertising)
|
|
{
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
WinsockNetLayer::StopAdvertising();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::_HostGame(int usersMask, unsigned char publicSlots, unsigned char privateSlots) {}
|
|
bool CPlatformNetworkManagerStub::_StartGame() { return true; }
|
|
|
|
int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int localUsersMask, int primaryUserIndex)
|
|
{
|
|
#ifdef _WINDOWS64
|
|
if (searchResult == nullptr)
|
|
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;
|
|
m_bLeaveGameOnTick = 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;
|
|
IQNet::m_player[0].m_resolvedXuid = Win64Xuid::GetLegacyEmbeddedHostXuid();
|
|
wcsncpy_s(IQNet::m_player[0].m_gamertag, 32, searchResult->data.hostName, _TRUNCATE);
|
|
|
|
WinsockNetLayer::StopDiscovery();
|
|
|
|
// Detect whether this session comes from the LCEN relay or is a direct TCP connection.
|
|
// Relay sessions have hostPort == g_Win64RelayServerPort (set in DiscoveryThreadProc).
|
|
// Direct servers (servers.db entries, LAN) use their actual port.
|
|
g_Win64LCENServer = (hostPort == g_Win64RelayServerPort);
|
|
|
|
if (!WinsockNetLayer::BeginJoinGame(hostIP, hostPort))
|
|
{
|
|
app.DebugPrintf("Win64: Failed to start async join to %s:%d\n", hostIP, hostPort);
|
|
return CGameNetworkManager::JOINGAME_FAIL_GENERAL;
|
|
}
|
|
|
|
m_bJoinPending = true;
|
|
return CGameNetworkManager::JOINGAME_PENDING;
|
|
#else
|
|
return CGameNetworkManager::JOINGAME_SUCCESS;
|
|
#endif
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::SetLocalGame(bool isLocal)
|
|
{
|
|
m_bIsOfflineGame = isLocal;
|
|
return true;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SetPrivateGame(bool isPrivate)
|
|
{
|
|
app.DebugPrintf("Setting as private game: %s\n", isPrivate ? "yes" : "no");
|
|
m_bIsPrivateGame = isPrivate;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::RegisterPlayerChangedCallback(int iPad,
|
|
void (*callback)(void*, INetworkPlayer*, bool), void* callbackParam)
|
|
{
|
|
playerChangedCallback[iPad] = callback;
|
|
playerChangedCallbackParam[iPad] = callbackParam;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::UnRegisterPlayerChangedCallback(int iPad,
|
|
void (*callback)(void*, INetworkPlayer*, bool), void* callbackParam)
|
|
{
|
|
if (playerChangedCallbackParam[iPad] == callbackParam)
|
|
{
|
|
playerChangedCallback[iPad] = nullptr;
|
|
playerChangedCallbackParam[iPad] = nullptr;
|
|
}
|
|
}
|
|
|
|
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 != nullptr && pNetworkPlayer->GetSocket() != nullptr)
|
|
Socket::addIncomingSocket(pNetworkPlayer->GetSocket());
|
|
}
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::UpdateAndSetGameSessionData(INetworkPlayer* pNetworkPlayerLeaving) {}
|
|
|
|
int CPlatformNetworkManagerStub::RemovePlayerOnSocketClosedThreadProc(void* lpParam)
|
|
{
|
|
INetworkPlayer* pNetworkPlayer = static_cast<INetworkPlayer*>(lpParam);
|
|
Socket* socket = pNetworkPlayer->GetSocket();
|
|
if (socket != nullptr)
|
|
{
|
|
socket->m_socketClosedEvent->WaitForSignal(INFINITE);
|
|
pNetworkPlayer->SetSocket(nullptr);
|
|
delete socket;
|
|
}
|
|
return g_pPlatformNetworkManager->RemoveLocalPlayer(pNetworkPlayer);
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::RemoveLocalPlayer(INetworkPlayer* pNetworkPlayer) { return true; }
|
|
|
|
CPlatformNetworkManagerStub::PlayerFlags::PlayerFlags(INetworkPlayer* pNetworkPlayer, unsigned int count)
|
|
{
|
|
count = (count + 8 - 1) & ~(8 - 1);
|
|
this->m_pNetworkPlayer = pNetworkPlayer;
|
|
this->flags = new unsigned char[count / 8];
|
|
memset(this->flags, 0, count / 8);
|
|
this->count = count;
|
|
this->m_smallId = (pNetworkPlayer && pNetworkPlayer->IsLocal()) ? 256 :
|
|
(pNetworkPlayer ? static_cast<int>(pNetworkPlayer->GetSmallId()) : -1);
|
|
}
|
|
|
|
CPlatformNetworkManagerStub::PlayerFlags::~PlayerFlags()
|
|
{
|
|
delete[] flags;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SystemFlagAddPlayer(INetworkPlayer* pNetworkPlayer)
|
|
{
|
|
PlayerFlags* newPlayerFlags = new PlayerFlags(pNetworkPlayer, m_flagIndexSize);
|
|
for (unsigned int i = 0; i < m_playerFlags.size(); i++)
|
|
{
|
|
if (pNetworkPlayer->IsSameSystem(m_playerFlags[i]->m_pNetworkPlayer))
|
|
{
|
|
memcpy(newPlayerFlags->flags, m_playerFlags[i]->flags, m_playerFlags[i]->count / 8);
|
|
break;
|
|
}
|
|
}
|
|
m_playerFlags.push_back(newPlayerFlags);
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SystemFlagRemovePlayer(INetworkPlayer* pNetworkPlayer)
|
|
{
|
|
for (unsigned int i = 0; i < m_playerFlags.size(); i++)
|
|
{
|
|
if (m_playerFlags[i]->m_pNetworkPlayer == pNetworkPlayer)
|
|
{
|
|
delete m_playerFlags[i];
|
|
m_playerFlags[i] = m_playerFlags.back();
|
|
m_playerFlags.pop_back();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SystemFlagRemoveBySmallId(int smallId)
|
|
{
|
|
if (smallId < 0) return;
|
|
for (unsigned int i = 0; i < m_playerFlags.size(); i++)
|
|
{
|
|
if (m_playerFlags[i]->m_smallId == smallId)
|
|
{
|
|
delete m_playerFlags[i];
|
|
m_playerFlags[i] = m_playerFlags.back();
|
|
m_playerFlags.pop_back();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SystemFlagReset()
|
|
{
|
|
for (unsigned int i = 0; i < m_playerFlags.size(); i++)
|
|
delete m_playerFlags[i];
|
|
m_playerFlags.clear();
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SystemFlagSet(INetworkPlayer* pNetworkPlayer, int index)
|
|
{
|
|
if (index < 0 || index >= m_flagIndexSize || pNetworkPlayer == nullptr) return;
|
|
for (unsigned int i = 0; i < m_playerFlags.size(); i++)
|
|
{
|
|
if (pNetworkPlayer->IsSameSystem(m_playerFlags[i]->m_pNetworkPlayer))
|
|
m_playerFlags[i]->flags[index / 8] |= (128 >> (index % 8));
|
|
}
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::SystemFlagGet(INetworkPlayer* pNetworkPlayer, int index)
|
|
{
|
|
if (index < 0 || index >= m_flagIndexSize || pNetworkPlayer == nullptr) return false;
|
|
for (unsigned int i = 0; i < m_playerFlags.size(); i++)
|
|
{
|
|
if (m_playerFlags[i]->m_pNetworkPlayer == pNetworkPlayer)
|
|
return ((m_playerFlags[i]->flags[index / 8] & (128 >> (index % 8))) != 0);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
wstring CPlatformNetworkManagerStub::GatherStats() { return L""; }
|
|
|
|
wstring CPlatformNetworkManagerStub::GatherRTTStats()
|
|
{
|
|
wstring stats(L"Rtt: ");
|
|
wchar_t stat[32];
|
|
for (unsigned int i = 0; i < GetPlayerCount(); ++i)
|
|
{
|
|
IQNetPlayer* pQNetPlayer = static_cast<NetworkPlayerXbox*>(GetPlayerByIndex(i))->GetQNetPlayer();
|
|
if (!pQNetPlayer->IsLocal())
|
|
{
|
|
ZeroMemory(stat, 32 * sizeof(WCHAR));
|
|
swprintf(stat, 32, L"%d: %d/", i, pQNetPlayer->GetCurrentRtt());
|
|
stats.append(stat);
|
|
}
|
|
}
|
|
return stats;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::TickSearch()
|
|
{
|
|
#ifdef _WINDOWS64
|
|
if (m_SessionsUpdatedCallback == nullptr) 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();
|
|
|
|
// Add sessions discovered via LAN broadcast or relay.
|
|
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 = static_cast<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;
|
|
|
|
// sessionId: for relay sessions hostIP is a non-numeric string so inet_addr
|
|
// returns INADDR_NONE — that's fine, it just gives a unique-ish key.
|
|
info->sessionId = static_cast<uint64_t>(inet_addr(lanSessions[i].hostIP)) |
|
|
(static_cast<uint64_t>(lanSessions[i].hostPort) << 32);
|
|
|
|
friendsSessions[0].push_back(info);
|
|
}
|
|
|
|
// Add servers from servers.db (manual / direct TCP entries).
|
|
if (std::FILE* file = std::fopen("servers.db", "rb"))
|
|
{
|
|
char magic[4] = {};
|
|
if (std::fread(magic, 1, 4, file) == 4 && memcmp(magic, "MCSV", 4) == 0)
|
|
{
|
|
uint32_t version = 0, count = 0;
|
|
std::fread(&version, sizeof(uint32_t), 1, file);
|
|
std::fread(&count, sizeof(uint32_t), 1, file);
|
|
|
|
if (version == 1)
|
|
{
|
|
for (uint32_t s = 0; s < count; s++)
|
|
{
|
|
uint16_t ipLen = 0, port = 0, nameLen = 0;
|
|
if (std::fread(&ipLen, sizeof(uint16_t), 1, file) != 1) break;
|
|
if (ipLen == 0 || ipLen > 256) break;
|
|
|
|
char ipBuf[257] = {};
|
|
if (std::fread(ipBuf, 1, ipLen, file) != ipLen) break;
|
|
if (std::fread(&port, sizeof(uint16_t), 1, file) != 1) break;
|
|
|
|
if (std::fread(&nameLen, sizeof(uint16_t), 1, file) != 1) break;
|
|
if (nameLen > 256) break;
|
|
|
|
char nameBuf[257] = {};
|
|
if (nameLen > 0)
|
|
{
|
|
if (std::fread(nameBuf, 1, nameLen, file) != nameLen) break;
|
|
}
|
|
|
|
wstring wName = convStringToWstring(nameBuf);
|
|
|
|
FriendSessionInfo* info = new FriendSessionInfo();
|
|
size_t nLen = wName.length();
|
|
info->displayLabel = new wchar_t[nLen + 1];
|
|
wcscpy_s(info->displayLabel, nLen + 1, wName.c_str());
|
|
info->displayLabelLength = static_cast<unsigned char>(nLen);
|
|
info->displayLabelViewableStartIndex = 0;
|
|
info->data.isReadyToJoin = true;
|
|
info->data.isJoinable = true;
|
|
strncpy_s(info->data.hostIP, sizeof(info->data.hostIP), ipBuf, _TRUNCATE);
|
|
info->data.hostPort = port;
|
|
// Direct servers: sessionId uses real IP + port.
|
|
info->sessionId = static_cast<uint64_t>(inet_addr(ipBuf)) |
|
|
(static_cast<uint64_t>(port) << 32);
|
|
friendsSessions[0].push_back(info);
|
|
}
|
|
}
|
|
}
|
|
std::fclose(file);
|
|
}
|
|
|
|
m_searchResultsCount[0] = static_cast<int>(friendsSessions[0].size());
|
|
|
|
if (m_SessionsUpdatedCallback != nullptr)
|
|
m_SessionsUpdatedCallback(m_pSearchParam);
|
|
#endif
|
|
}
|
|
|
|
int CPlatformNetworkManagerStub::SearchForGamesThreadProc(void* lpParameter) { return 0; }
|
|
|
|
void CPlatformNetworkManagerStub::SetSearchResultsReady(int resultCount)
|
|
{
|
|
m_bSearchResultsReady = true;
|
|
m_searchResultsCount[m_lastSearchPad] = resultCount;
|
|
}
|
|
|
|
vector<FriendSessionInfo*>* CPlatformNetworkManagerStub::GetSessionList(int iPad, int localPlayers, bool partyOnly)
|
|
{
|
|
vector<FriendSessionInfo*>* filteredList = new vector<FriendSessionInfo*>();
|
|
for (size_t i = 0; i < friendsSessions[0].size(); i++)
|
|
filteredList->push_back(new FriendSessionInfo(*friendsSessions[0][i]));
|
|
return filteredList;
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::GetGameSessionInfo(int iPad, SessionID sessionId, FriendSessionInfo* foundSessionInfo)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SetSessionsUpdatedCallback(
|
|
void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam)
|
|
{
|
|
m_SessionsUpdatedCallback = SessionsUpdatedCallback;
|
|
m_pSearchParam = pSearchParam;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::GetFullFriendSessionInfo(
|
|
FriendSessionInfo* foundSession,
|
|
void (*FriendSessionUpdatedFn)(bool success, void* pParam),
|
|
void* pParam)
|
|
{
|
|
FriendSessionUpdatedFn(true, pParam);
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::ForceFriendsSessionRefresh()
|
|
{
|
|
app.DebugPrintf("Resetting friends session search data\n");
|
|
for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
|
|
{
|
|
m_searchResultsCount[i] = 0;
|
|
m_lastSearchStartTime[i] = 0;
|
|
delete m_pSearchResults[i];
|
|
m_pSearchResults[i] = nullptr;
|
|
}
|
|
#ifdef _WINDOWS64
|
|
SearchForGames();
|
|
#endif
|
|
}
|
|
|
|
INetworkPlayer* CPlatformNetworkManagerStub::addNetworkPlayer(IQNetPlayer* pQNetPlayer)
|
|
{
|
|
NetworkPlayerXbox* pNetworkPlayer = new NetworkPlayerXbox(pQNetPlayer);
|
|
pQNetPlayer->SetCustomDataValue((ULONG_PTR)pNetworkPlayer);
|
|
currentNetworkPlayers.push_back(pNetworkPlayer);
|
|
return pNetworkPlayer;
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::removeNetworkPlayer(IQNetPlayer* pQNetPlayer)
|
|
{
|
|
INetworkPlayer* pNetworkPlayer = getNetworkPlayer(pQNetPlayer);
|
|
for (auto it = currentNetworkPlayers.begin(); it != currentNetworkPlayers.end(); it++)
|
|
{
|
|
if (*it == pNetworkPlayer)
|
|
{
|
|
currentNetworkPlayers.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
INetworkPlayer* CPlatformNetworkManagerStub::getNetworkPlayer(IQNetPlayer* pQNetPlayer)
|
|
{
|
|
return pQNetPlayer ? (INetworkPlayer*)(pQNetPlayer->GetCustomDataValue()) : nullptr;
|
|
}
|
|
|
|
INetworkPlayer* CPlatformNetworkManagerStub::GetLocalPlayerByUserIndex(int userIndex)
|
|
{
|
|
return getNetworkPlayer(m_pIQNet->GetLocalPlayerByUserIndex(userIndex));
|
|
}
|
|
|
|
INetworkPlayer* CPlatformNetworkManagerStub::GetPlayerByIndex(int playerIndex)
|
|
{
|
|
return getNetworkPlayer(m_pIQNet->GetPlayerByIndex(playerIndex));
|
|
}
|
|
|
|
INetworkPlayer* CPlatformNetworkManagerStub::GetPlayerByXuid(PlayerUID xuid)
|
|
{
|
|
return getNetworkPlayer(m_pIQNet->GetPlayerByXuid(xuid));
|
|
}
|
|
|
|
INetworkPlayer* CPlatformNetworkManagerStub::GetPlayerBySmallId(unsigned char smallId)
|
|
{
|
|
return getNetworkPlayer(m_pIQNet->GetPlayerBySmallId(smallId));
|
|
}
|
|
|
|
INetworkPlayer* CPlatformNetworkManagerStub::GetHostPlayer()
|
|
{
|
|
return getNetworkPlayer(m_pIQNet->GetHostPlayer());
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::IsHost()
|
|
{
|
|
return m_pIQNet->IsHost() && !m_bHostChanged;
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::JoinGameFromInviteInfo(int userIndex, int userMask, const INVITE_INFO* pInviteInfo)
|
|
{
|
|
return (m_pIQNet->JoinGameFromInviteInfo(userIndex, userMask, pInviteInfo) == S_OK);
|
|
}
|
|
|
|
void CPlatformNetworkManagerStub::SetSessionTexturePackParentId(int id) { m_hostGameSessionData.texturePackParentId = id; }
|
|
void CPlatformNetworkManagerStub::SetSessionSubTexturePackId(int id) { m_hostGameSessionData.subTexturePackId = id; }
|
|
void CPlatformNetworkManagerStub::Notify(int ID, ULONG_PTR Param) {}
|
|
|
|
bool CPlatformNetworkManagerStub::IsInSession()
|
|
{
|
|
return m_pIQNet->GetState() != QNET_STATE_IDLE;
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::IsInGameplay()
|
|
{
|
|
return m_pIQNet->GetState() == QNET_STATE_GAME_PLAY;
|
|
}
|
|
|
|
bool CPlatformNetworkManagerStub::IsReadyToPlayOrIdle() { return true; } |