Skip to content

Commit bddcf2e

Browse files
authored
Merge pull request #1030 from tsiakoulias/fix-dedicated-steam-activation-requestexperience-crash
Fix dedicated steam activation requestexperience crash
2 parents 1dd8ff8 + 382313a commit bddcf2e

5 files changed

Lines changed: 74 additions & 1 deletion

File tree

src/game/server/gameinterface.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
#include "missionchooser/iasw_mission_chooser_source.h"
112112
#include "matchmaking/swarm/imatchext_swarm.h"
113113
#include "asw_gamerules.h"
114+
#include "asw_player.h"
114115
#include "asw_util_shared.h"
115116
#include "iconsistency.h"
116117
#endif
@@ -613,6 +614,16 @@ static bool InitGameSystems( CreateInterfaceFn appSystemFactory )
613614

614615
CServerGameDLL g_ServerGameDLL;
615616
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerGameDLL, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL, g_ServerGameDLL);
617+
// Crash fix/hardening: the engine can call into game code during lobby soft-close -> restart
618+
// before Steam is fully activated for the new session. Track activation so code can safely
619+
// skip Steam calls until the engine signals readiness.
620+
static bool g_bRDSteamAPIActivated = false;
621+
static float g_flNextDeferredSteamStatsRequestTime = 0.0f;
622+
623+
bool RD_IsSteamAPIActivated()
624+
{
625+
return g_bRDSteamAPIActivated;
626+
}
616627

617628
bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory,
618629
CreateInterfaceFn physicsFactory, CreateInterfaceFn fileSystemFactory,
@@ -1064,6 +1075,7 @@ bool CServerGameDLL::SupportsSaveRestore()
10641075
bool CServerGameDLL::LevelInit( const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background )
10651076
{
10661077
VPROF("CServerGameDLL::LevelInit");
1078+
g_bRDSteamAPIActivated = false;
10671079
ResetWindspeed();
10681080
UpdateChapterRestrictions( pMapName );
10691081

@@ -1266,6 +1278,11 @@ void CServerGameDLL::ServerActivate( edict_t *pEdictList, int edictCount, int cl
12661278
void CServerGameDLL::GameServerSteamAPIActivated( void )
12671279
{
12681280
// the Steam API pointers used to be initialized here, but that happens automatically now.
1281+
// Crash fix/hardening: mark Steam as activated so code can safely call Steam APIs.
1282+
g_bRDSteamAPIActivated = true;
1283+
1284+
// If any players tried to request XP before Steam activation (restart/join window), retry now.
1285+
g_flNextDeferredSteamStatsRequestTime = 0.0f;
12691286
}
12701287

12711288
//-----------------------------------------------------------------------------
@@ -1281,6 +1298,42 @@ void CServerGameDLL::GameFrame( bool simulating )
12811298
if ( g_InRestore )
12821299
return;
12831300

1301+
// Crash fix/hardening: if we deferred any Steam stats requests because Steam wasn't activated
1302+
// yet (e.g. lobby soft-close -> restart), retry them once Steam is ready.
1303+
static const float k_flDeferredSteamStatsRequestTimeout = 30.0f;
1304+
if ( g_bRDSteamAPIActivated && gpGlobals && gpGlobals->curtime >= g_flNextDeferredSteamStatsRequestTime )
1305+
{
1306+
g_flNextDeferredSteamStatsRequestTime = gpGlobals->curtime + 1.0f;
1307+
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
1308+
{
1309+
CASW_Player *pPlayer = ToASW_Player( UTIL_PlayerByIndex( i ) );
1310+
if ( !pPlayer )
1311+
continue;
1312+
1313+
if ( pPlayer->m_bDeferredSteamStatsRequest && !pPlayer->m_bPendingSteamStats )
1314+
{
1315+
if ( pPlayer->m_flDeferredSteamStatsRequestStart < 0.0f )
1316+
{
1317+
pPlayer->m_flDeferredSteamStatsRequestStart = gpGlobals->curtime;
1318+
}
1319+
1320+
if ( ( gpGlobals->curtime - pPlayer->m_flDeferredSteamStatsRequestStart ) > k_flDeferredSteamStatsRequestTimeout )
1321+
{
1322+
pPlayer->m_bDeferredSteamStatsRequest = false;
1323+
pPlayer->m_flDeferredSteamStatsRequestStart = -1.0f;
1324+
continue;
1325+
}
1326+
1327+
pPlayer->RequestExperience();
1328+
if ( pPlayer->m_bPendingSteamStats )
1329+
{
1330+
pPlayer->m_bDeferredSteamStatsRequest = false;
1331+
pPlayer->m_flDeferredSteamStatsRequestStart = -1.0f;
1332+
}
1333+
}
1334+
}
1335+
}
1336+
12841337
#ifndef NO_STEAM
12851338
// All the calls to us from the engine prior to gameframe (like LevelInit & ServerActivate)
12861339
// are done before the engine has got the Steam API connected, so we have to wait until now to connect ourselves.
@@ -1518,6 +1571,7 @@ void CServerGameDLL::LevelShutdown( void )
15181571
MDLCACHE_CRITICAL_SECTION();
15191572
IGameSystem::LevelShutdownPreEntityAllSystems();
15201573

1574+
g_bRDSteamAPIActivated = false;
15211575
// YWB:
15221576
// This entity pointer is going away now and is corrupting memory on level transitions/restarts
15231577
CSoundEnt::ShutdownSoundEnt();

src/game/server/gameinterface.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
1+
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
22
//
33
// Purpose: Expose things from GameInterface.cpp. Mostly the engine interfaces.
44
//
@@ -211,6 +211,11 @@ class CMapLoadEntityFilter : public IMapEntityFilter
211211

212212
bool IsEngineThreaded();
213213

214+
// Crash fix support: during lobby soft-close -> restart, the engine can call into game code
215+
// (including PlayerSpawn) before Steam is fully activated for the new session.
216+
// This helper lets server-side code skip Steam calls until GameServerSteamAPIActivated fires.
217+
bool RD_IsSteamAPIActivated();
218+
214219
class CServerGameTags : public IServerGameTags
215220
{
216221
public:

src/game/server/swarm/asw_player.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,8 @@ CASW_Player::CASW_Player()
407407

408408
m_bPendingSteamStats = false;
409409
m_flPendingSteamStatsStart = 0.0f;
410+
m_bDeferredSteamStatsRequest = false;
411+
m_flDeferredSteamStatsRequestStart = -1.0f;
410412

411413
m_bWelcomed = false;
412414

src/game/server/swarm/asw_player.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ class CASW_Player : public CBaseMultiplayerPlayer, public IASWPlayerAnimStateHel
278278
bool m_bHasAwardedXP;
279279
bool m_bPendingSteamStats;
280280
float m_flPendingSteamStatsStart;
281+
bool m_bDeferredSteamStatsRequest;
282+
float m_flDeferredSteamStatsRequestStart;
281283
bool m_bSentPromotedMessage;
282284

283285
// static inventory (medals)

src/game/shared/swarm/asw_player_experience.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,16 @@ void CASW_Player::RequestExperience()
467467
#else
468468
if ( engine->IsDedicatedServer() )
469469
{
470+
// Crash fix/hardening: during lobby soft-close -> restart, PlayerSpawn can run before
471+
// Steam is activated for the new session. Avoid calling RequestUserStats until the
472+
// engine signals Steam readiness (GameServerSteamAPIActivated).
473+
if ( !RD_IsSteamAPIActivated() )
474+
{
475+
// Defer rather than skip: once Steam is activated, game code will retry this request.
476+
m_bDeferredSteamStatsRequest = true;
477+
return;
478+
}
479+
470480
Assert( SteamGameServerStats() );
471481
if ( SteamGameServerStats() )
472482
{

0 commit comments

Comments
 (0)