diff --git a/Minecraft.Client/Build/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Build/Common/Network/GameNetworkManager.cpp index cc977f6f4..1aa62bb41 100644 --- a/Minecraft.Client/Build/Common/Network/GameNetworkManager.cpp +++ b/Minecraft.Client/Build/Common/Network/GameNetworkManager.cpp @@ -212,6 +212,17 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame } static __int64 sseed = seed; // Create static version so this will be valid until next call to this function & whilst thread is running + + // 4J Fix: Ensure host-local socket streams (s_hostInStream / s_hostOutStream) are always + // created before any Socket or Connection objects are allocated. Socket::Initialise normally + // runs on the server thread, but on certain builds the main thread can reach ClientConnection + // creation before that thread has a chance to execute, leaving the stream arrays NULL. + // Calling Initialise(NULL) here (with the server connection unknown yet) will create the + // stream objects on the very first call; all subsequent calls only reset the queue state. + // The server thread's later Initialise(connection) call will then correctly update + // s_serverConnection without touching the already-allocated stream objects. + Socket::Initialise(NULL); + ServerStoppedCreate(false); if( g_NetworkManager.IsHost() ) { diff --git a/Minecraft.World/Network/Socket.cpp b/Minecraft.World/Network/Socket.cpp index 801c6a61d..c6c16b824 100644 --- a/Minecraft.World/Network/Socket.cpp +++ b/Minecraft.World/Network/Socket.cpp @@ -16,14 +16,34 @@ Socket::SocketOutputStreamLocal *Socket::s_hostOutStream[2]; Socket::SocketInputStreamLocal *Socket::s_hostInStream[2]; ServerConnection *Socket::s_serverConnection = NULL; +void Socket::EnsureStreamsInitialised() +{ + // Thread-safe one-time initialisation via C++11 magic-statics guarantee. + // The lambda body runs exactly once no matter how many threads call concurrently. + static bool initialized = []() -> bool { + for( int i = 0; i < 2; i++ ) + { + InitializeCriticalSection(&Socket::s_hostQueueLock[i]); + s_hostOutStream[i] = new SocketOutputStreamLocal(i); + s_hostInStream[i] = new SocketInputStreamLocal(i); + } + return true; + }(); + (void)initialized; +} + void Socket::Initialise(ServerConnection *serverConnection) { s_serverConnection = serverConnection; + // Ensure the host-local stream objects exist (idempotent). + EnsureStreamsInitialised(); + // Only initialise everything else once - just setting up static data, one time xrnm things, thread for ticking sockets static bool init = false; if( init ) { + // Streams already exist – just reset queue state and re-open streams. for( int i = 0; i < 2; i++ ) { if(TryEnterCriticalSection(&s_hostQueueLock[i])) @@ -39,13 +59,8 @@ void Socket::Initialise(ServerConnection *serverConnection) return; } init = true; - - for( int i = 0; i < 2; i++ ) - { - InitializeCriticalSection(&Socket::s_hostQueueLock[i]); - s_hostOutStream[i] = new SocketOutputStreamLocal(i); - s_hostInStream[i] = new SocketInputStreamLocal(i); - } + // Streams are already guaranteed to exist via EnsureStreamsInitialised() above. + // Nothing more to do for the first call. } Socket::Socket(bool response) @@ -182,6 +197,11 @@ InputStream *Socket::getInputStream(bool isServerConnection) } else { + if( s_hostInStream[m_end] == NULL ) + { + app.DebugPrintf("SOCKET: Warning - s_hostInStream[%d] is NULL in getInputStream(); calling EnsureStreamsInitialised()\n", m_end); + EnsureStreamsInitialised(); + } return s_hostInStream[m_end]; } } @@ -216,7 +236,13 @@ Socket::SocketOutputStream *Socket::getOutputStream(bool isServerConnection) } else { - return s_hostOutStream[ 1 - m_end ]; + int outIdx = 1 - m_end; + if( s_hostOutStream[outIdx] == NULL ) + { + app.DebugPrintf("SOCKET: Warning - s_hostOutStream[%d] is NULL in getOutputStream(); calling EnsureStreamsInitialised()\n", outIdx); + EnsureStreamsInitialised(); + } + return s_hostOutStream[outIdx]; } } diff --git a/Minecraft.World/Network/Socket.h b/Minecraft.World/Network/Socket.h index b30e83962..a685fd835 100644 --- a/Minecraft.World/Network/Socket.h +++ b/Minecraft.World/Network/Socket.h @@ -117,6 +117,7 @@ public: void setPlayer(INetworkPlayer *player); public: + static void EnsureStreamsInitialised(); // 4J Fix: idempotent stream creation; safe to call before Initialise(connection) static void Initialise(ServerConnection *serverConnection); Socket(bool response = false); // 4J - Create a local socket, for end 0 or 1 of a connection Socket(INetworkPlayer *player, bool response = false, bool hostLocal = false); // 4J - Create a socket for an INetworkPlayer