forked from cafeberry/cafeberry
feat: add smartcmd dedicated server
major bug: when connecting to the server a second time, it gets softlocked and keeps repeating ticking connection A\n in debug logs until it times out.
This commit is contained in:
@@ -1,15 +1,27 @@
|
||||
#include "stdafx.h"
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "../../Minecraft.Server/ServerLogManager.h"
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Name: DebugSpewV()
|
||||
// Desc: Internal helper function
|
||||
//--------------------------------------------------------------------------------------
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
static VOID DebugSpewV( const CHAR* strFormat, const va_list pArgList )
|
||||
static VOID DebugSpewV( const CHAR* strFormat, va_list pArgList )
|
||||
{
|
||||
#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
|
||||
assert(0);
|
||||
#else
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
// Dedicated server routes legacy debug spew through ServerLogger to preserve CLI prompt handling.
|
||||
if (ServerRuntime::ServerLogManager::ShouldForwardClientDebugLogs())
|
||||
{
|
||||
ServerRuntime::ServerLogManager::ForwardClientDebugSpewLogV(strFormat, pArgList);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CHAR str[2048];
|
||||
// Use the secure CRT to avoid buffer overruns. Specify a count of
|
||||
// _TRUNCATE so that too long strings will be silently truncated
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
#include "GameRules\ConsoleGameRules.h"
|
||||
#include "GameRules\ConsoleSchematicFile.h"
|
||||
#include "..\User.h"
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\..\Minecraft.Server\ServerLogManager.h"
|
||||
#endif
|
||||
#include "..\\EntityRenderDispatcher.h"
|
||||
#include "..\TexturePackRepository.h"
|
||||
#include "..\DLCTexturePack.h"
|
||||
@@ -230,12 +233,21 @@ void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
|
||||
{
|
||||
|
||||
#ifndef _FINAL_BUILD
|
||||
char buf[1024];
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
vsnprintf(buf, sizeof(buf), szFormat, ap);
|
||||
va_end(ap);
|
||||
OutputDebugStringA(buf);
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
// Dedicated server routes client debug spew through ServerLogger so CLI output stays prompt-safe.
|
||||
if (ServerRuntime::ServerLogManager::ShouldForwardClientDebugLogs())
|
||||
{
|
||||
ServerRuntime::ServerLogManager::ForwardClientAppDebugLogV(szFormat, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), szFormat, ap);
|
||||
va_end(ap);
|
||||
OutputDebugStringA(buf);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -243,13 +255,22 @@ void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
|
||||
void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
|
||||
{
|
||||
#ifndef _FINAL_BUILD
|
||||
if(user == USER_NONE)
|
||||
return;
|
||||
char buf[1024];
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
vsnprintf(buf, sizeof(buf), szFormat, ap);
|
||||
va_end(ap);
|
||||
if(user == USER_NONE)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
// Dedicated server routes client debug spew through ServerLogger so CLI output stays prompt-safe.
|
||||
if (ServerRuntime::ServerLogManager::ShouldForwardClientDebugLogs())
|
||||
{
|
||||
ServerRuntime::ServerLogManager::ForwardClientUserDebugLogV(user, szFormat, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), szFormat, ap);
|
||||
va_end(ap);
|
||||
#ifdef __PS3__
|
||||
unsigned int writelen;
|
||||
sys_tty_write(SYS_TTYP_USER1 + ( user - 1 ), buf, strlen(buf), &writelen );
|
||||
|
||||
@@ -358,12 +358,24 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
|
||||
// PRIMARY PLAYER
|
||||
|
||||
vector<ClientConnection *> createdConnections;
|
||||
ClientConnection *connection;
|
||||
ClientConnection *connection = NULL;
|
||||
|
||||
if( g_NetworkManager.IsHost() )
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
{
|
||||
app.DebugPrintf("Dedicated server mode: skipping local host client connection\n");
|
||||
|
||||
// Keep telemetry behavior consistent with the host path.
|
||||
INT multiplayerInstanceId = TelemetryManager->GenerateMultiplayerInstanceId();
|
||||
TelemetryManager->SetMultiplayerInstanceId(multiplayerInstanceId);
|
||||
|
||||
app.SetGameMode( eMode_Multiplayer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
connection = new ClientConnection(minecraft, NULL);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(ProfileManager.GetLockedProfile());
|
||||
@@ -389,155 +401,159 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
|
||||
connection = new ClientConnection(minecraft, socket);
|
||||
}
|
||||
|
||||
if( !connection->createdOk )
|
||||
if (connection != NULL)
|
||||
{
|
||||
assert(false);
|
||||
delete connection;
|
||||
connection = NULL;
|
||||
MinecraftServer::HaltServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(minecraft->user->name) ) );
|
||||
|
||||
// Tick connection until we're ready to go. The stages involved in this are:
|
||||
// (1) Creating the ClientConnection sends a prelogin packet to the server
|
||||
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
|
||||
// (3) the server sends a login back, which is handled by the client connection to start the game
|
||||
if( !g_NetworkManager.IsHost() )
|
||||
{
|
||||
Minecraft::GetInstance()->progressRenderer->progressStart(IDS_PROGRESS_CONNECTING);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4J Stu - Host needs to generate a unique multiplayer id for sentient telemetry reporting
|
||||
INT multiplayerInstanceId = TelemetryManager->GenerateMultiplayerInstanceId();
|
||||
TelemetryManager->SetMultiplayerInstanceId(multiplayerInstanceId);
|
||||
}
|
||||
TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected();
|
||||
do
|
||||
{
|
||||
app.DebugPrintf("ticking connection A\n");
|
||||
connection->tick();
|
||||
|
||||
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
|
||||
// The connections should tick at 20 per second
|
||||
Sleep(50);
|
||||
} while ( (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame()) || tPack->isLoadingData() || (Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()) );
|
||||
ui.CleanUpSkinReload();
|
||||
|
||||
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
|
||||
// We need to break out of the above loop if m_bLeavingGame is set, and close the connection
|
||||
if( g_NetworkManager.IsLeavingGame() || !IsInSession() )
|
||||
{
|
||||
connection->close();
|
||||
}
|
||||
|
||||
if( connection->isStarted() && !connection->isClosed() )
|
||||
{
|
||||
createdConnections.push_back( connection );
|
||||
|
||||
int primaryPad = ProfileManager.GetPrimaryPad();
|
||||
app.SetRichPresenceContext(primaryPad,CONTEXT_GAME_STATE_BLANK);
|
||||
if (GetPlayerCount() > 1) // Are we offline or online, and how many players are there
|
||||
if( !connection->createdOk )
|
||||
{
|
||||
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
|
||||
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER,false);
|
||||
assert(false);
|
||||
delete connection;
|
||||
connection = NULL;
|
||||
MinecraftServer::HaltServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(minecraft->user->name) ) );
|
||||
|
||||
// Tick connection until we're ready to go. The stages involved in this are:
|
||||
// (1) Creating the ClientConnection sends a prelogin packet to the server
|
||||
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
|
||||
// (3) the server sends a login back, which is handled by the client connection to start the game
|
||||
if( !g_NetworkManager.IsHost() )
|
||||
{
|
||||
Minecraft::GetInstance()->progressRenderer->progressStart(IDS_PROGRESS_CONNECTING);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false);
|
||||
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1P,false);
|
||||
// 4J Stu - Host needs to generate a unique multiplayer id for sentient telemetry reporting
|
||||
INT multiplayerInstanceId = TelemetryManager->GenerateMultiplayerInstanceId();
|
||||
TelemetryManager->SetMultiplayerInstanceId(multiplayerInstanceId);
|
||||
}
|
||||
TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected();
|
||||
do
|
||||
{
|
||||
app.DebugPrintf("ticking connection A\n");
|
||||
connection->tick();
|
||||
|
||||
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
|
||||
// The connections should tick at 20 per second
|
||||
Sleep(50);
|
||||
} while ( (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame()) || tPack->isLoadingData() || (Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()) );
|
||||
ui.CleanUpSkinReload();
|
||||
|
||||
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
|
||||
// We need to break out of the above loop if m_bLeavingGame is set, and close the connection
|
||||
if( g_NetworkManager.IsLeavingGame() || !IsInSession() )
|
||||
{
|
||||
connection->close();
|
||||
}
|
||||
|
||||
|
||||
// ALL OTHER LOCAL PLAYERS
|
||||
for(int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
|
||||
if( connection->isStarted() && !connection->isClosed() )
|
||||
{
|
||||
// Already have setup the primary pad
|
||||
if(idx == ProfileManager.GetPrimaryPad() ) continue;
|
||||
|
||||
if( GetLocalPlayerByUserIndex(idx) != NULL && !ProfileManager.IsSignedIn(idx) )
|
||||
{
|
||||
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
|
||||
Socket *socket = pNetworkPlayer->GetSocket();
|
||||
app.DebugPrintf("Closing socket due to player %d not being signed in any more\n");
|
||||
if( !socket->close(false) ) socket->close(true);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// By default when we host we only have the local player, but currently allow multiple local players to join
|
||||
// when joining any other way, so just because they are signed in doesn't mean they are in the session
|
||||
// 4J Stu - If they are in the session, then we should add them to the game. Otherwise we won't be able to add them later
|
||||
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
|
||||
if( pNetworkPlayer == NULL )
|
||||
continue;
|
||||
|
||||
ClientConnection *connection;
|
||||
|
||||
Socket *socket = pNetworkPlayer->GetSocket();
|
||||
connection = new ClientConnection(minecraft, socket, idx);
|
||||
|
||||
minecraft->addPendingLocalConnection(idx, connection);
|
||||
//minecraft->createExtraLocalPlayer(idx, (convStringToWstring( ProfileManager.GetGamertag(idx) )).c_str(), idx, connection);
|
||||
|
||||
// Open the socket on the server end to accept incoming data
|
||||
Socket::addIncomingSocket(socket);
|
||||
|
||||
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(convStringToWstring( ProfileManager.GetGamertag(idx) )) ) );
|
||||
|
||||
createdConnections.push_back( connection );
|
||||
|
||||
// Tick connection until we're ready to go. The stages involved in this are:
|
||||
// (1) Creating the ClientConnection sends a prelogin packet to the server
|
||||
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
|
||||
// (3) the server sends a login back, which is handled by the client connection to start the game
|
||||
do
|
||||
int primaryPad = ProfileManager.GetPrimaryPad();
|
||||
app.SetRichPresenceContext(primaryPad,CONTEXT_GAME_STATE_BLANK);
|
||||
if (GetPlayerCount() > 1) // Are we offline or online, and how many players are there
|
||||
{
|
||||
// We need to keep ticking the connections for players that already logged in
|
||||
for(AUTO_VAR(it, createdConnections.begin()); it < createdConnections.end(); ++it)
|
||||
{
|
||||
(*it)->tick();
|
||||
}
|
||||
|
||||
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
|
||||
// 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 || 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
|
||||
} while (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame() );
|
||||
#endif
|
||||
|
||||
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
|
||||
// We need to break out of the above loop if m_bLeavingGame is set, and stop creating new connections
|
||||
// The connections in the createdConnections vector get closed at the end of the thread
|
||||
if( g_NetworkManager.IsLeavingGame() || !IsInSession() ) break;
|
||||
|
||||
if( ProfileManager.IsSignedIn(idx) && !connection->isClosed() )
|
||||
{
|
||||
app.SetRichPresenceContext(idx,CONTEXT_GAME_STATE_BLANK);
|
||||
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
|
||||
else ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYER,false);
|
||||
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
|
||||
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER,false);
|
||||
}
|
||||
else
|
||||
{
|
||||
connection->close();
|
||||
AUTO_VAR(it, find( createdConnections.begin(), createdConnections.end(), connection ));
|
||||
if(it != createdConnections.end() ) createdConnections.erase( it );
|
||||
if(IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false);
|
||||
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1P,false);
|
||||
}
|
||||
}
|
||||
|
||||
app.SetGameMode( eMode_Multiplayer );
|
||||
}
|
||||
else if ( connection->isClosed() || !IsInSession())
|
||||
{
|
||||
// assert(false);
|
||||
MinecraftServer::HaltServer();
|
||||
return false;
|
||||
|
||||
// ALL OTHER LOCAL PLAYERS
|
||||
for(int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
|
||||
{
|
||||
// Already have setup the primary pad
|
||||
if(idx == ProfileManager.GetPrimaryPad() ) continue;
|
||||
|
||||
if( GetLocalPlayerByUserIndex(idx) != NULL && !ProfileManager.IsSignedIn(idx) )
|
||||
{
|
||||
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
|
||||
Socket *socket = pNetworkPlayer->GetSocket();
|
||||
app.DebugPrintf("Closing socket due to player %d not being signed in any more\n");
|
||||
if( !socket->close(false) ) socket->close(true);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// By default when we host we only have the local player, but currently allow multiple local players to join
|
||||
// when joining any other way, so just because they are signed in doesn't mean they are in the session
|
||||
// 4J Stu - If they are in the session, then we should add them to the game. Otherwise we won't be able to add them later
|
||||
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
|
||||
if( pNetworkPlayer == NULL )
|
||||
continue;
|
||||
|
||||
ClientConnection *connection;
|
||||
|
||||
Socket *socket = pNetworkPlayer->GetSocket();
|
||||
connection = new ClientConnection(minecraft, socket, idx);
|
||||
|
||||
minecraft->addPendingLocalConnection(idx, connection);
|
||||
//minecraft->createExtraLocalPlayer(idx, (convStringToWstring( ProfileManager.GetGamertag(idx) )).c_str(), idx, connection);
|
||||
|
||||
// Open the socket on the server end to accept incoming data
|
||||
Socket::addIncomingSocket(socket);
|
||||
|
||||
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(convStringToWstring( ProfileManager.GetGamertag(idx) )) ) );
|
||||
|
||||
createdConnections.push_back( connection );
|
||||
|
||||
// Tick connection until we're ready to go. The stages involved in this are:
|
||||
// (1) Creating the ClientConnection sends a prelogin packet to the server
|
||||
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
|
||||
// (3) the server sends a login back, which is handled by the client connection to start the game
|
||||
do
|
||||
{
|
||||
// We need to keep ticking the connections for players that already logged in
|
||||
for(AUTO_VAR(it, createdConnections.begin()); it < createdConnections.end(); ++it)
|
||||
{
|
||||
(*it)->tick();
|
||||
}
|
||||
|
||||
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
|
||||
// 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 || 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
|
||||
} while (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame() );
|
||||
#endif
|
||||
|
||||
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
|
||||
// We need to break out of the above loop if m_bLeavingGame is set, and stop creating new connections
|
||||
// The connections in the createdConnections vector get closed at the end of the thread
|
||||
if( g_NetworkManager.IsLeavingGame() || !IsInSession() ) break;
|
||||
|
||||
if( ProfileManager.IsSignedIn(idx) && !connection->isClosed() )
|
||||
{
|
||||
app.SetRichPresenceContext(idx,CONTEXT_GAME_STATE_BLANK);
|
||||
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
|
||||
else ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYER,false);
|
||||
}
|
||||
else
|
||||
{
|
||||
connection->close();
|
||||
AUTO_VAR(it, find( createdConnections.begin(), createdConnections.end(), connection ));
|
||||
if(it != createdConnections.end() ) createdConnections.erase( it );
|
||||
}
|
||||
}
|
||||
|
||||
app.SetGameMode( eMode_Multiplayer );
|
||||
}
|
||||
else if ( connection->isClosed() || !IsInSession())
|
||||
{
|
||||
// assert(false);
|
||||
|
||||
MinecraftServer::HaltServer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -547,7 +563,7 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
|
||||
{
|
||||
(*it)->close();
|
||||
}
|
||||
// assert(false);
|
||||
//assert(false);
|
||||
MinecraftServer::HaltServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <string>
|
||||
#include "NetworkSocketLayer.h"
|
||||
#include "..\..\Common\Network\PlatformNetworkManager.h"
|
||||
#include "..\..\..\Minecraft.World\Socket.h"
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\..\..\Minecraft.Server\Access\Access.h"
|
||||
#include "..\..\..\Minecraft.Server\ServerLogManager.h"
|
||||
#endif
|
||||
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
static bool TryGetNumericRemoteIp(const sockaddr_in &remoteAddress, std::string *outIp);
|
||||
#endif
|
||||
|
||||
SOCKET NetworkSocketLayer::s_listenSocket = INVALID_SOCKET;
|
||||
SOCKET NetworkSocketLayer::s_hostConnectionSocket = INVALID_SOCKET;
|
||||
@@ -55,23 +64,26 @@ std::vector<LANSession> NetworkSocketLayer::s_discoveredSessions;
|
||||
CRITICAL_SECTION NetworkSocketLayer::s_disconnectLock;
|
||||
std::vector<BYTE> NetworkSocketLayer::s_disconnectedSmallIds;
|
||||
|
||||
CRITICAL_SECTION NetworkSocketLayer::s_pendingJoinLock;
|
||||
std::vector<BYTE> NetworkSocketLayer::s_pendingJoinSmallIds;
|
||||
|
||||
CRITICAL_SECTION NetworkSocketLayer::s_freeSmallIdLock;
|
||||
std::vector<BYTE> NetworkSocketLayer::s_freeSmallIds;
|
||||
|
||||
// only goes true on a successful Initialize(), and a failed one gets retried
|
||||
static bool s_locksCreated = false;
|
||||
#if defined _WINDOWS64
|
||||
#if !defined _WINDOWS64
|
||||
bool g_MultiplayerHost = true;
|
||||
bool g_MultiplayerJoin = false;
|
||||
#else
|
||||
bool g_MultiplayerHost = false;
|
||||
bool g_MultiplayerJoin = true;
|
||||
#endif
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
int g_DedicatedServerPort = NETWORK_LAN_DEFAULT_PORT;
|
||||
char g_DedicatedServerBindIP[256] = "";
|
||||
bool g_DedicatedServerLanAdvertise = true;
|
||||
#endif
|
||||
int g_MultiplayerPort = NETWORK_LAN_DEFAULT_PORT;
|
||||
char g_MultiplayerIP[256] = "192.168.0.69";
|
||||
char g_MultiplayerIP[256] = "192.168.8.27";
|
||||
|
||||
|
||||
bool NetworkSocketLayer::Initialize()
|
||||
@@ -86,7 +98,6 @@ bool NetworkSocketLayer::Initialize()
|
||||
InitializeCriticalSection(&s_advertiseLock);
|
||||
InitializeCriticalSection(&s_discoveryLock);
|
||||
InitializeCriticalSection(&s_disconnectLock);
|
||||
InitializeCriticalSection(&s_pendingJoinLock);
|
||||
InitializeCriticalSection(&s_freeSmallIdLock);
|
||||
|
||||
for (int i = 0; i < NETWORK_LAN_MAX_CLIENTS + 1; i++)
|
||||
@@ -139,7 +150,10 @@ bool NetworkSocketLayer::Initialize()
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
// Dedicated Server does not use LAN session discovery and therefore does not initiate discovery.
|
||||
#ifndef MINECRAFT_SERVER_BUILD
|
||||
StartDiscovery();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -224,8 +238,6 @@ void NetworkSocketLayer::Shutdown()
|
||||
DeleteCriticalSection(&s_discoveryLock);
|
||||
DeleteCriticalSection(&s_disconnectLock);
|
||||
s_disconnectedSmallIds.clear();
|
||||
DeleteCriticalSection(&s_pendingJoinLock);
|
||||
s_pendingJoinSmallIds.clear();
|
||||
DeleteCriticalSection(&s_freeSmallIdLock);
|
||||
s_freeSmallIds.clear();
|
||||
s_locksCreated = false;
|
||||
@@ -799,6 +811,12 @@ bool NetworkSocketLayer::JoinGame(const char *ip, int port)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear the recv timeout now that the handshake is complete.
|
||||
// The recv thread should block indefinitely waiting for data.
|
||||
DWORD noTimeout = 0;
|
||||
setsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&noTimeout, sizeof(noTimeout));
|
||||
|
||||
s_localSmallId = assignedSmallId;
|
||||
|
||||
app.DebugPrintf("LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
|
||||
@@ -907,6 +925,20 @@ SOCKET NetworkSocketLayer::GetSocketForSmallId(BYTE smallId)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Send reject handshake: sentinel 0xFF + DisconnectPacket wire format (1 byte id 255 + 4 byte big-endian reason). Then caller closes socket.
|
||||
static void SendRejectWithReason(SOCKET clientSocket, DisconnectPacket::eDisconnectReason reason)
|
||||
{
|
||||
BYTE buf[6];
|
||||
buf[0] = NETWORK_LAN_SMALLID_REJECT;
|
||||
buf[1] = (BYTE)255; // DisconnectPacket packet id
|
||||
int r = (int)reason;
|
||||
buf[2] = (BYTE)((r >> 24) & 0xff);
|
||||
buf[3] = (BYTE)((r >> 16) & 0xff);
|
||||
buf[4] = (BYTE)((r >> 8) & 0xff);
|
||||
buf[5] = (BYTE)(r & 0xff);
|
||||
send(clientSocket, (const char*)buf, sizeof(buf), 0);
|
||||
}
|
||||
|
||||
static bool RecvExact(SOCKET sock, BYTE *buf, int len)
|
||||
{
|
||||
int totalRecv = 0;
|
||||
@@ -919,6 +951,27 @@ static bool RecvExact(SOCKET sock, BYTE *buf, int len)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
static bool TryGetNumericRemoteIp(const sockaddr_in &remoteAddress, std::string *outIp)
|
||||
{
|
||||
if (outIp == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
outIp->clear();
|
||||
char ipBuffer[64] = {};
|
||||
const char *ip = inet_ntop(AF_INET, (void *)&remoteAddress.sin_addr, ipBuffer, sizeof(ipBuffer));
|
||||
if (ip == nullptr || ip[0] == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*outIp = ip;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NetworkSocketLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char *data, unsigned int dataSize)
|
||||
{
|
||||
INetworkPlayer *pPlayerFrom = g_NetworkManager.GetPlayerBySmallId(fromSmallId);
|
||||
@@ -951,9 +1004,15 @@ int NetworkSocketLayer::AcceptThreadProc(LPVOID param)
|
||||
while (s_active)
|
||||
{
|
||||
#ifdef __PSVITA__
|
||||
SOCKET clientSocket = accept(s_listenSocket, (SceNetSockaddr *)NULL, NULL);
|
||||
sockaddr_in remoteAddress;
|
||||
ZeroMemory(&remoteAddress, sizeof(remoteAddress));
|
||||
int remoteAddressLength = sizeof(remoteAddress);
|
||||
SOCKET clientSocket = accept(s_listenSocket, (SceNetSockaddr *)&remoteAddress, &remoteAddressLength);
|
||||
#else
|
||||
SOCKET clientSocket = accept(s_listenSocket, NULL, NULL);
|
||||
sockaddr_in remoteAddress;
|
||||
ZeroMemory(&remoteAddress, sizeof(remoteAddress));
|
||||
int remoteAddressLength = sizeof(remoteAddress);
|
||||
SOCKET clientSocket = accept(s_listenSocket, (sockaddr*)&remoteAddress, &remoteAddressLength);
|
||||
#endif
|
||||
#if defined _WINDOWS64 || defined _XBOX
|
||||
if (clientSocket == INVALID_SOCKET)
|
||||
@@ -974,10 +1033,28 @@ int NetworkSocketLayer::AcceptThreadProc(LPVOID param)
|
||||
int noDelay = 1;
|
||||
setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
extern QNET_STATE _iQNetStubState;
|
||||
if (_iQNetStubState != QNET_STATE_GAME_PLAY && _iQNetStubState != QNET_STATE_SESSION_STARTING)
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
std::string remoteIp;
|
||||
const bool hasRemoteIp = TryGetNumericRemoteIp(remoteAddress, &remoteIp);
|
||||
const char *remoteIpForLog = hasRemoteIp ? remoteIp.c_str() : "unknown";
|
||||
ServerRuntime::ServerLogManager::OnIncomingTcpConnection(remoteIpForLog);
|
||||
if (hasRemoteIp && ServerRuntime::Access::IsIpBanned(remoteIp))
|
||||
{
|
||||
ServerRuntime::ServerLogManager::OnRejectedTcpConnection(remoteIpForLog, ServerRuntime::ServerLogManager::eTcpRejectReason_BannedIp);
|
||||
SendRejectWithReason(clientSocket, DisconnectPacket::eDisconnect_Banned);
|
||||
closesocket(clientSocket);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern QNET_STATE _iQNetStubState;
|
||||
if (_iQNetStubState != QNET_STATE_GAME_PLAY)
|
||||
{
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
ServerRuntime::ServerLogManager::OnRejectedTcpConnection(remoteIpForLog, ServerRuntime::ServerLogManager::eTcpRejectReason_GameNotReady);
|
||||
#else
|
||||
app.DebugPrintf("Win64 LAN: Rejecting connection, game not ready\n");
|
||||
#endif
|
||||
closesocket(clientSocket);
|
||||
continue;
|
||||
}
|
||||
@@ -996,7 +1073,11 @@ int NetworkSocketLayer::AcceptThreadProc(LPVOID param)
|
||||
else
|
||||
{
|
||||
LeaveCriticalSection(&s_freeSmallIdLock);
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
ServerRuntime::ServerLogManager::OnRejectedTcpConnection(remoteIpForLog, ServerRuntime::ServerLogManager::eTcpRejectReason_ServerFull);
|
||||
#else
|
||||
app.DebugPrintf("Win64 LAN: Server full, rejecting connection\n");
|
||||
#endif
|
||||
closesocket(clientSocket);
|
||||
continue;
|
||||
}
|
||||
@@ -1026,16 +1107,19 @@ int NetworkSocketLayer::AcceptThreadProc(LPVOID param)
|
||||
conn.active = true;
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
ServerRuntime::ServerLogManager::OnAcceptedTcpConnection(assignedSmallId, remoteIpForLog);
|
||||
#else
|
||||
app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId);
|
||||
#endif
|
||||
|
||||
IQNetPlayer *qnetPlayer = &IQNet::m_player[assignedSmallId];
|
||||
IQNetPlayer* qnetPlayer = &IQNet::m_player[assignedSmallId];
|
||||
|
||||
extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal);
|
||||
extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer * player, BYTE smallId, bool isHost, bool isLocal);
|
||||
Win64_SetupRemoteQNetPlayer(qnetPlayer, assignedSmallId, false, false);
|
||||
|
||||
EnterCriticalSection(&s_pendingJoinLock);
|
||||
s_pendingJoinSmallIds.push_back(assignedSmallId);
|
||||
LeaveCriticalSection(&s_pendingJoinLock);
|
||||
extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
|
||||
g_pPlatformNetworkManager->NotifyPlayerJoined(qnetPlayer);
|
||||
|
||||
DWORD *threadParam = new DWORD;
|
||||
*threadParam = assignedSmallId;
|
||||
@@ -1142,20 +1226,6 @@ void NetworkSocketLayer::PushFreeSmallId(BYTE smallId)
|
||||
LeaveCriticalSection(&s_freeSmallIdLock);
|
||||
}
|
||||
|
||||
bool NetworkSocketLayer::PopPendingJoinSmallId(BYTE *outSmallId)
|
||||
{
|
||||
bool found = false;
|
||||
EnterCriticalSection(&s_pendingJoinLock);
|
||||
if (!s_pendingJoinSmallIds.empty())
|
||||
{
|
||||
*outSmallId = s_pendingJoinSmallIds.back();
|
||||
s_pendingJoinSmallIds.pop_back();
|
||||
found = true;
|
||||
}
|
||||
LeaveCriticalSection(&s_pendingJoinLock);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool NetworkSocketLayer::IsSmallIdConnected(BYTE smallId)
|
||||
{
|
||||
if (smallId >= NETWORK_LAN_MAX_CLIENTS + 1) return false;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#define NETWORK_LAN_DEFAULT_PORT 25565
|
||||
#define NETWORK_LAN_MAX_CLIENTS 7
|
||||
#define NETWORK_LAN_SMALLID_REJECT 0xFF
|
||||
#define NETWORK_LAN_RECV_BUFFER_SIZE 65536
|
||||
#define NETWORK_LAN_MAX_PACKET_SIZE (3 * 1024 * 1024)
|
||||
#define NETWORK_LAN_DISCOVERY_PORT 25566
|
||||
@@ -172,8 +173,6 @@ public:
|
||||
static void PushFreeSmallId(BYTE smallId);
|
||||
static void CloseConnectionBySmallId(BYTE smallId);
|
||||
|
||||
static bool PopPendingJoinSmallId(BYTE *outSmallId);
|
||||
|
||||
static bool IsSmallIdConnected(BYTE smallId);
|
||||
|
||||
static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer);
|
||||
@@ -230,9 +229,6 @@ private:
|
||||
static CRITICAL_SECTION s_disconnectLock;
|
||||
static std::vector<BYTE> s_disconnectedSmallIds;
|
||||
|
||||
static CRITICAL_SECTION s_pendingJoinLock;
|
||||
static std::vector<BYTE> s_pendingJoinSmallIds;
|
||||
|
||||
static CRITICAL_SECTION s_freeSmallIdLock;
|
||||
static std::vector<BYTE> s_freeSmallIds;
|
||||
};
|
||||
@@ -241,3 +237,9 @@ extern bool g_MultiplayerHost;
|
||||
extern bool g_MultiplayerJoin;
|
||||
extern int g_MultiplayerPort;
|
||||
extern char g_MultiplayerIP[256];
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
extern int g_DedicatedServerPort;
|
||||
extern char g_DedicatedServerBindIP[256];
|
||||
extern bool g_DedicatedServerLanAdvertise;
|
||||
#endif
|
||||
@@ -171,6 +171,7 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa
|
||||
|
||||
m_bLeavingGame = false;
|
||||
m_bLeaveGameOnTick = false;
|
||||
m_bLeaveGameOnTick = false;
|
||||
m_bHostChanged = false;
|
||||
|
||||
m_bSearchResultsReady = false;
|
||||
@@ -233,53 +234,56 @@ void CPlatformNetworkManagerStub::DoWork()
|
||||
BYTE disconnectedSmallId;
|
||||
while (NetworkSocketLayer::PopDisconnectedSmallId(&disconnectedSmallId))
|
||||
{
|
||||
if (disconnectedSmallId == 0) continue;
|
||||
if (NetworkSocketLayer::IsSmallIdConnected(disconnectedSmallId)) continue;
|
||||
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(disconnectedSmallId);
|
||||
if (qnetPlayer != NULL && qnetPlayer->m_smallId == 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; // TODO: implement
|
||||
qnetPlayer->m_gamertag[0] = 0;
|
||||
qnetPlayer->SetCustomDataValue(0);
|
||||
NetworkSocketLayer::PushFreeSmallId(disconnectedSmallId);
|
||||
if (IQNet::s_playerCount > 1)
|
||||
// Recalculate s_playerCount as the highest active slot + 1.
|
||||
// A blind decrement would hide players at higher-indexed slots when a
|
||||
// lower-indexed player disconnects first: GetPlayerBySmallId scans
|
||||
// [0, s_playerCount) so any slot at or above the decremented count
|
||||
// becomes invisible, causing its disconnect to be missed (ghost player).
|
||||
while (IQNet::s_playerCount > 1 &&
|
||||
IQNet::m_player[IQNet::s_playerCount - 1].GetCustomDataValue() == 0)
|
||||
IQNet::s_playerCount--;
|
||||
}
|
||||
}
|
||||
|
||||
BYTE joinedSmallId;
|
||||
while (NetworkSocketLayer::PopPendingJoinSmallId(&joinedSmallId))
|
||||
{
|
||||
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(joinedSmallId);
|
||||
if (qnetPlayer != NULL && qnetPlayer->m_smallId == joinedSmallId)
|
||||
{
|
||||
NotifyPlayerJoined(qnetPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
{
|
||||
IQNetPlayer *qp = &IQNet::m_player[i];
|
||||
if (qp->GetCustomDataValue() == 0)
|
||||
continue;
|
||||
INetworkPlayer *np = (INetworkPlayer *)qp->GetCustomDataValue();
|
||||
Socket *sock = np->GetSocket();
|
||||
if (sock != NULL && sock->isClosing())
|
||||
{
|
||||
NetworkSocketLayer::CloseConnectionBySmallId((BYTE)i);
|
||||
}
|
||||
// NOTE: Do NOT call PushFreeSmallId here. The old PlayerConnection's
|
||||
// write thread may still be alive (it dies in PlayerList::tick when
|
||||
// m_smallIdsToClose is processed). If we recycle the smallId now,
|
||||
// AcceptThread can reuse it for a new connection, and the old write
|
||||
// thread's getPlayer() lookup will resolve to the NEW player, sending
|
||||
// stale game packets to the new client's TCP socket — corrupting its
|
||||
// login handshake (bad packet id crash). PushFreeSmallId and
|
||||
// ClearSocketForSmallId are called from PlayerList::tick after the
|
||||
// old Connection threads are dead.
|
||||
//
|
||||
// Clear chunk visibility flags for this system so rejoin gets fresh chunk state.
|
||||
SystemFlagRemoveBySmallId(disconnectedSmallId);
|
||||
}
|
||||
}
|
||||
if (_iQNetStubState == QNET_STATE_GAME_PLAY && !m_pIQNet->IsHost())
|
||||
|
||||
// Client-side host disconnect detection:
|
||||
// if TCP is gone, propagate through normal network-disconnect flow so UI returns to menus.
|
||||
// The processing from the Xbox version will be reused.
|
||||
if (_iQNetStubState == QNET_STATE_GAME_PLAY && !m_pIQNet->IsHost() && !m_bLeavingGame)
|
||||
{
|
||||
if (!NetworkSocketLayer::IsConnected() && !g_NetworkManager.IsLeavingGame())
|
||||
if (!NetworkSocketLayer::IsConnected())
|
||||
{
|
||||
if (app.GetDisconnectReason() == DisconnectPacket::eDisconnect_None)
|
||||
app.SetDisconnectReason(DisconnectPacket::eDisconnect_Quitting);
|
||||
app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ExitWorld, (void *)TRUE);
|
||||
if (!m_bLeaveGameOnTick)
|
||||
{
|
||||
m_bLeaveGameOnTick = true;
|
||||
g_NetworkManager.HandleDisconnect(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bLeaveGameOnTick = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -354,6 +358,7 @@ bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost)
|
||||
if( m_bLeavingGame ) return true;
|
||||
|
||||
m_bLeavingGame = true;
|
||||
m_bLeaveGameOnTick = false;
|
||||
NetworkSocketLayer::StopAdvertising();
|
||||
|
||||
// If we are the host wait for the game server to end
|
||||
@@ -397,6 +402,7 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame,
|
||||
localUsersMask |= GetLocalPlayerMask( g_NetworkManager.GetPrimaryPad() );
|
||||
|
||||
m_bLeavingGame = false;
|
||||
m_bLeaveGameOnTick = false;
|
||||
|
||||
m_pIQNet->HostGame();
|
||||
|
||||
@@ -418,9 +424,25 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame,
|
||||
if (!NetworkSocketLayer::IsActive())
|
||||
NetworkSocketLayer::HostGame(port);
|
||||
|
||||
const wchar_t *hostName = IQNet::m_player[0].m_gamertag;
|
||||
unsigned int settings = app.GetGameHostOption(eGameHostOption_All);
|
||||
NetworkSocketLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION);
|
||||
if (NetworkSocketLayer::IsActive())
|
||||
{
|
||||
// For Dedicated Server, refer to `lan-advertise` in `server.properties`
|
||||
bool enableLanAdvertising = true;
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
enableLanAdvertising = g_DedicatedServerLanAdvertise;
|
||||
#endif
|
||||
|
||||
if (enableLanAdvertising)
|
||||
{
|
||||
const wchar_t* hostName = IQNet::m_player[0].m_gamertag;
|
||||
unsigned int settings = app.GetGameHostOption(eGameHostOption_All);
|
||||
NetworkSocketLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION);
|
||||
}
|
||||
else
|
||||
{
|
||||
NetworkSocketLayer::StopAdvertising();
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
@@ -626,6 +648,7 @@ CPlatformNetworkManagerStub::PlayerFlags::PlayerFlags(INetworkPlayer *pNetworkPl
|
||||
this->flags = new unsigned char [ count / 8 ];
|
||||
memset( this->flags, 0, count / 8 );
|
||||
this->count = count;
|
||||
this->m_smallId = (pNetworkPlayer && pNetworkPlayer->IsLocal()) ? 256 : (pNetworkPlayer ? (int)pNetworkPlayer->GetSmallId() : -1);
|
||||
}
|
||||
CPlatformNetworkManagerStub::PlayerFlags::~PlayerFlags()
|
||||
{
|
||||
@@ -663,6 +686,23 @@ void CPlatformNetworkManagerStub::SystemFlagRemovePlayer(INetworkPlayer *pNetwor
|
||||
}
|
||||
}
|
||||
|
||||
// Clear chunk flags for a system when they disconnect (by smallId). Call even when we don't find the player,
|
||||
// so we always clear and the smallId can be reused without stale "chunk seen" state.
|
||||
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++ )
|
||||
|
||||
@@ -99,12 +99,14 @@ private:
|
||||
INetworkPlayer *m_pNetworkPlayer;
|
||||
unsigned char *flags;
|
||||
unsigned int count;
|
||||
int m_smallId;
|
||||
PlayerFlags(INetworkPlayer *pNetworkPlayer, unsigned int count);
|
||||
~PlayerFlags();
|
||||
};
|
||||
vector<PlayerFlags *> m_playerFlags;
|
||||
void SystemFlagAddPlayer(INetworkPlayer *pNetworkPlayer);
|
||||
void SystemFlagRemovePlayer(INetworkPlayer *pNetworkPlayer);
|
||||
void SystemFlagRemoveBySmallId(int smallId);
|
||||
void SystemFlagReset();
|
||||
public:
|
||||
virtual void SystemFlagSet(INetworkPlayer *pNetworkPlayer, int index);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
param(
|
||||
[string]$OutDir,
|
||||
[string]$ProjectDir
|
||||
)
|
||||
|
||||
Write-Host "Server Postbuild: script started. Output Directory: $OutDir, Project Directory: $ProjectDir"
|
||||
|
||||
$directories = @(
|
||||
"Windows64\GameHDD",
|
||||
"Common\Media",
|
||||
"Common\res",
|
||||
"redist64"
|
||||
)
|
||||
|
||||
foreach ($dir in $directories) {
|
||||
New-Item -ItemType Directory -Path (Join-Path $OutDir $dir) -Force | Out-Null
|
||||
}
|
||||
|
||||
$folderCopies = @(
|
||||
@{ Source = "Common\Media"; Dest = "Common\Media" },
|
||||
@{ Source = "Common\res"; Dest = "Common\res" },
|
||||
@{ Source = "Common\Postbuilds\Contents\Windows64\redist64"; Dest = "redist64" }
|
||||
)
|
||||
|
||||
foreach ($copy in $folderCopies) {
|
||||
$src = Join-Path "$ProjectDir\..\Minecraft.Client" $copy.Source
|
||||
$dst = Join-Path $OutDir $copy.Dest
|
||||
|
||||
if (Test-Path $src) {
|
||||
xcopy /q /y /i /s /e /d "$src" "$dst" 2>$null
|
||||
}
|
||||
}
|
||||
|
||||
$fileCopies = @(
|
||||
@{ Source = "Common\Postbuilds\Contents\Windows64\Effects.msscmp"; Dest = "Effects.msscmp" },
|
||||
@{ Source = "Common\Postbuilds\Contents\Windows64\iggy_w64.dll"; Dest = "iggy_w64.dll" },
|
||||
@{ Source = "Common\Postbuilds\Contents\Windows64\mss64.dll"; Dest = "mss64.dll" }
|
||||
)
|
||||
|
||||
foreach ($copy in $fileCopies) {
|
||||
$src = Join-Path "$ProjectDir\..\Minecraft.Client" $copy.Source
|
||||
$dst = Join-Path $OutDir $copy.Dest
|
||||
if (Test-Path $src) {
|
||||
Copy-Item -Path $src -Destination $dst -Force
|
||||
}
|
||||
}
|
||||
|
||||
$deleteDirs = @(
|
||||
"Common\Media\Sound",
|
||||
"Common\Media\Graphics",
|
||||
"Common\Media\de-DE",
|
||||
"Common\Media\es-ES",
|
||||
"Common\Media\fr-FR",
|
||||
"Common\Media\it-IT",
|
||||
"Common\Media\ja-JP",
|
||||
"Common\Media\ko-KR",
|
||||
"Common\Media\pt-BR",
|
||||
"Common\Media\pt-PT",
|
||||
"Common\Media\zh-CHT"
|
||||
)
|
||||
|
||||
foreach ($dir in $deleteDirs) {
|
||||
$path = Join-Path $OutDir $dir
|
||||
if (Test-Path $path) {
|
||||
Remove-Item $path -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
$delDirs = @(
|
||||
"Common\Media",
|
||||
"Common\Media\font"
|
||||
)
|
||||
|
||||
foreach ($dir in $delDirs) {
|
||||
if ($delDirs -contains $dir) {
|
||||
$path = Join-Path $OutDir $dir
|
||||
if (Test-Path $path) {
|
||||
Get-ChildItem -Path $path -Recurse -Include *.swf, *.txt, *.resx, *.xml, *.loc, *.lang, *.col, *.h, *.xui, *.abc, "Mojang Font_7.ttf", "Mojang Font_11.ttf", MediaDurango.arc, MediaOrbis.arc, MediaPS3.arc, MediaPSVita.arc -File |
|
||||
Remove-Item -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user