Fix 16 pilots + 1 cameraship failing to launch
A full 16-'Mech roster plus a cameraship silently refused to launch: the console
sat in nLaunchState 3 ("loading") forever with no crash and no error. 15 mechs +
camera worked, and 16 mechs with no camera worked.
Two independent bugs, both counting the cameraship against the 16 'Mech slots.
1. Session capacity (broke all-human rosters)
CTCL_DefaultHostSetup derived the camera reserve from
CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount(). Those counters read the CTCL
tesla table, which is only populated when CTCL_IsConsoleOrCOOP() is true --
i.e. only on the console. But the machine that creates the network session is
the cameraship pod (CTCL_DoMission sets g_nServer = nCameraship, and that pod
runs CTCL_DoCreateGame -> CTCL_DefaultHostSetup(0) -> Mech4CreateGame ->
gos_CreateGame(..., Environment.NetworkMaxPlayers, ...)).
On that pod both counters return 0, so the reserve collapsed to +0 and the
session was created with dwMaxPlayers = 16. The 17th connection was refused,
CTCL_CheckServerReady never saw nCount == g_nTeslas + 1, and the launch hung.
Fixed by reserving with a constant, MW4_CAMERASHIP_RESERVE (4, matching
MAX_CAMERAS), which is valid on every machine regardless of the tesla table.
2. Bot admission (broke any roster containing bots)
MW4Shell::AddBot rejects when (player_count + bot_count) >= m_maxPlayers.
player_count is the DirectPlay player count, which includes the cameraship
connection, so with m_maxPlayers = 16 the last bot was silently refused.
g_nBOTs then never matched the connected lancemates and the same readiness
check spun forever.
Fixed by subtracting cameraship participants from player_count under CTCL,
via a new CTCL_CountCameraShipsInGame() helper (non-bot entries with
m_nMechIndex == 0). Cameraships hold a network slot but pilot no 'Mech, so
they must not consume a 'Mech slot.
Also applies the constant reserve in the PLAYER_LIMIT_PARAMETER path, guarded by
!CTCL_IsNone() so a standalone non-pod host keeps its exact configured limit.
This supersedes commit f76dc05f, which had the right formula but evaluated it on
the console rather than on the pod that actually creates the session.
Note for later: m_maxPlayers is serialized in only 5 bits (MWApplication.cpp),
so 31 is the hard ceiling for any future player-cap work. See
RAISING-PLAYER-CAP.md.
Requires rebuild: MW4.exe (Release + Profile). No script or resource changes.
Verified: compiles clean, console launches. Pod testing pending.
Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
This commit is contained in:
co-authored by
Claude Opus 5
GitHub Copilot
parent
515adc2413
commit
29aee4f71b
@@ -57,6 +57,19 @@
|
||||
|
||||
#include "mechspecs.cpp"
|
||||
|
||||
// [16 pilots + 1 cameraship fix]
|
||||
//
|
||||
// A cameraship seat occupies a network (DirectPlay) slot but pilots no 'Mech, so slots must
|
||||
// be reserved for cameraships on top of the pilot cap, and cameraships must NOT be counted
|
||||
// against the 'Mech cap.
|
||||
//
|
||||
// The reserve has to be a CONSTANT rather than being derived from
|
||||
// (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount()): the CTCL tesla table is only populated
|
||||
// when CTCL_IsConsoleOrCOOP() is true (see ctcl.cpp), so on a pod - including the cameraship
|
||||
// pod, which is the machine that actually creates the network session in CTCL_DoCreateGame()
|
||||
// - both counters return 0 and the reserve collapsed to +0.
|
||||
#define MW4_CAMERASHIP_RESERVE 4 // must be >= MAX_CAMERAS in ctcl.cpp
|
||||
|
||||
// MSL 5.03 Mechview
|
||||
void __stdcall CTCL_AfterBeginScene();
|
||||
void __stdcall CTCL_UpdateMechView();
|
||||
@@ -1968,8 +1981,13 @@ int MW4Shell::SetNetworkMissionParamater(void * instance, int numParms, void **d
|
||||
case PLAYER_LIMIT_PARAMETER:
|
||||
params->m_playerLimit = INTPARM(1);
|
||||
Min_Clamp(params->m_playerLimit, Network::GetInstance()->GetPlayerCount());
|
||||
// Add camera slots on top of the pilot limit so cameraships can still connect
|
||||
Environment.NetworkMaxPlayers = params->m_playerLimit + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount());
|
||||
// [16 pilots + 1 cameraship fix] Add camera slots on top of the pilot limit so
|
||||
// cameraships can still connect. Uses the constant reserve for the same reason as
|
||||
// CTCL_DefaultHostSetup: the CTCL tesla counters are console-only and read 0 on a pod.
|
||||
// Only applied under CTCL - a standalone (non-pod) host must keep its exact limit.
|
||||
Environment.NetworkMaxPlayers = params->m_playerLimit;
|
||||
if (!CTCL_IsNone())
|
||||
Environment.NetworkMaxPlayers += MW4_CAMERASHIP_RESERVE;
|
||||
gos_NetServerCommands(gos_Commend_UpdateMaxPlayers,0);
|
||||
break;
|
||||
|
||||
@@ -9071,6 +9089,24 @@ int MW4Shell::LoadDefaultOptions()
|
||||
return 1;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// [16 pilots + 1 cameraship fix]
|
||||
// Number of cameraship participants in the current roster. Only meaningful on the server
|
||||
// pod, which is the only machine that holds the full g_aPlayerInfos roster (filled by
|
||||
// CSOC_Client::OnBOTS) and the only machine that calls AddBot in CTCL mode.
|
||||
// A cameraship entry is a non-bot player with no 'Mech (m_nMechIndex == 0).
|
||||
static int CTCL_CountCameraShipsInGame()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < g_nPlayerInfos; i++)
|
||||
{
|
||||
const SPlayerInfo& PI = g_aPlayerInfos[i];
|
||||
if (!PI.m_bBot && (PI.m_nMechIndex == 0))
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int _stdcall MW4Shell::AddBot(void *instance, int numParams, void* data[])
|
||||
@@ -9087,6 +9123,16 @@ int _stdcall MW4Shell::AddBot(void *instance, int numParams, void* data[])
|
||||
bot_count++;
|
||||
}
|
||||
player_count = Network::GetInstance()->GetPlayerCount();
|
||||
// [16 pilots + 1 cameraship fix] Cameraships hold a network slot but no 'Mech slot.
|
||||
// Counting them here capped pilots+cameras+bots at m_maxPlayers (16), so a full 16-'Mech
|
||||
// roster plus a cameraship silently lost its last bot; g_nBOTs then never matched the
|
||||
// connected lancemates and CTCL_CheckServerReady() spun forever without ever launching.
|
||||
if (CTCL_IsConsoleX())
|
||||
{
|
||||
player_count -= CTCL_CountCameraShipsInGame();
|
||||
if (player_count < 0)
|
||||
player_count = 0;
|
||||
}
|
||||
NetMissionParameters::MWNetMissionParameters *params = app->GetLocalNetParams();
|
||||
if (params->m_runDedicated)
|
||||
{
|
||||
@@ -13592,10 +13638,13 @@ void CTCL_API CTCL_DefaultHostSetup(int nMode)
|
||||
params->m_maxBots = 8;
|
||||
} else {
|
||||
params->m_maxPlayers = 16;
|
||||
// Reserve extra DirectPlay slots for cameraships: they share the session but are tracked
|
||||
// separately from pilot seats in CTCL (CTCL_GetTeslaCountAll - CTCL_GetTeslaCount = camera count).
|
||||
// Without this, cameraship connection is rejected by DirectPlay because slot 17 doesn't exist.
|
||||
Environment.NetworkMaxPlayers = params->m_maxPlayers + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount());
|
||||
// [16 pilots + 1 cameraship fix] Reserve network slots for cameraship seats on top of the
|
||||
// pilot cap. This runs on the cameraship pod too (via CTCL_DoCreateGame -> nMode 0), which
|
||||
// is the machine that creates the session with dwMaxPlayers = Environment.NetworkMaxPlayers.
|
||||
// Do NOT derive the reserve from the CTCL tesla counters here: that table is console-only,
|
||||
// so on the pod they both return 0, the reserve became +0, the session was created with
|
||||
// 16 slots, and the 17th connection was refused - the mission then never finished loading.
|
||||
Environment.NetworkMaxPlayers = params->m_maxPlayers + MW4_CAMERASHIP_RESERVE;
|
||||
params->m_maxBots = 16;
|
||||
}
|
||||
params->m_allow3rdPerson = 1;
|
||||
|
||||
Reference in New Issue
Block a user