forked from SwagSoftware/Kisak-Strike
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmm_session_offline_custom.cpp
332 lines (279 loc) · 9.84 KB
/
mm_session_offline_custom.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "mm_framework.h"
#include "fmtstr.h"
#include "netmessages_signon.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//
// CMatchSessionOfflineCustom
//
// Implementation of an offline session
// that allows customization before the actual
// game commences (like playing commentary mode
// or playing single-player)
//
CMatchSessionOfflineCustom::CMatchSessionOfflineCustom( KeyValues *pSettings ) :
m_pSettings( pSettings->MakeCopy() ),
m_autodelete_pSettings( m_pSettings ),
m_eState( STATE_INIT ),
m_bExpectingServerReload( false )
{
DevMsg( "Created CMatchSessionOfflineCustom:\n" );
KeyValuesDumpAsDevMsg( m_pSettings, 1 );
InitializeGameSettings();
}
CMatchSessionOfflineCustom::~CMatchSessionOfflineCustom()
{
DevMsg( "Destroying CMatchSessionOfflineCustom:\n" );
KeyValuesDumpAsDevMsg( m_pSettings, 1 );
}
KeyValues * CMatchSessionOfflineCustom::GetSessionSettings()
{
return m_pSettings;
}
void CMatchSessionOfflineCustom::UpdateSessionSettings( KeyValues *pSettings )
{
// Extend the update keys
g_pMMF->GetMatchTitleGameSettingsMgr()->ExtendGameSettingsUpdateKeys( m_pSettings, pSettings );
m_pSettings->MergeFrom( pSettings );
// Broadcast the update to everybody interested
MatchSession_BroadcastSessionSettingsUpdate( pSettings );
}
void CMatchSessionOfflineCustom::UpdateTeamProperties( KeyValues *pTeamProperties )
{
}
void CMatchSessionOfflineCustom::Command( KeyValues *pCommand )
{
char const *szCommand = pCommand->GetName();
if ( !Q_stricmp( "Start", szCommand ) && m_eState < STATE_RUNNING )
{
m_eState = STATE_RUNNING;
OnGamePrepareLobbyForGame();
UpdateSessionSettings( KeyValues::AutoDeleteInline( KeyValues::FromString(
"update",
" update { "
" server { "
" server listen "
" } "
" } "
) ) );
g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
"OnProfilesWriteOpportunity", "reason", "sessionstart"
) );
bool bResult = g_pMatchFramework->GetMatchTitle()->StartServerMap( m_pSettings );
if ( !bResult )
{
Warning( "Failed to start server map!\n" );
KeyValuesDumpAsDevMsg( m_pSettings, 1 );
Assert( 0 );
g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "error", "error", "nomap" ) );
}
Msg( "Succeeded in starting server map!\n" );
return;
}
if ( !Q_stricmp( "QueueConnect", szCommand ) )
{
char const *szConnectAddress = pCommand->GetString( "adronline", "0.0.0.0" );
uint64 uiReservationId = pCommand->GetUint64( "reservationid" );
bool bAutoCloseSession = pCommand->GetBool( "auto_close_session" );
Assert( bAutoCloseSession );
if ( bAutoCloseSession )
{
// Switch the state
m_eState = STATE_RUNNING;
MatchSession_PrepareClientForConnect( m_pSettings, uiReservationId );
// Close the session, potentially resetting a bunch of state
if ( bAutoCloseSession )
g_pMatchFramework->CloseSession();
// Determine reservation settings required
g_pMatchExtensions->GetINetSupport()->UpdateClientReservation( uiReservationId, 0ull );
// Issue the connect command
g_pMatchExtensions->GetIVEngineClient()->StartLoadingScreenForCommand( CFmtStr( "connect %s", szConnectAddress ) );
return;
}
}
//
// Let the title-specific matchmaking handle the command
//
CUtlVector< KeyValues * > arrPlayersUpdated;
arrPlayersUpdated.SetCount( m_pSettings->GetInt( "members/numPlayers", 0 ) );
memset( arrPlayersUpdated.Base(), 0, arrPlayersUpdated.Count() * sizeof( KeyValues * ) );
g_pMMF->GetMatchTitleGameSettingsMgr()->ExecuteCommand( pCommand, GetSessionSystemData(), m_pSettings, arrPlayersUpdated.Base() );
// Now notify the framework about player updated
for ( int k = 0; k < arrPlayersUpdated.Count(); ++ k )
{
if ( !arrPlayersUpdated[k] )
break;
// Notify the framework about player updated
KeyValues *kvEvent = new KeyValues( "OnPlayerUpdated" );
kvEvent->SetUint64( "xuid", arrPlayersUpdated[k]->GetUint64( "xuid" ) );
g_pMatchEventsSubscription->BroadcastEvent( kvEvent );
}
//
// Send the command as event for handling
//
KeyValues *pEvent = pCommand->MakeCopy();
pEvent->SetName( CFmtStr( "Command::%s", pCommand->GetName() ) );
g_pMatchEventsSubscription->BroadcastEvent( pEvent );
}
uint64 CMatchSessionOfflineCustom::GetSessionID()
{
return 0;
}
void CMatchSessionOfflineCustom::Update()
{
switch ( m_eState )
{
case STATE_INIT:
m_eState = STATE_CONFIG;
// Let everybody know that the session is now ready
g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "OnMatchSessionUpdate", "state", "ready", "transition", "offlineinit" ) );
break;
}
}
void CMatchSessionOfflineCustom::Destroy()
{
if ( m_eState == STATE_RUNNING )
{
g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" );
g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
"OnProfilesWriteOpportunity", "reason", "sessionend"
) );
}
delete this;
}
void CMatchSessionOfflineCustom::DebugPrint()
{
DevMsg( "CMatchSessionOfflineCustom [ state=%d ]\n", m_eState );
KeyValuesDumpAsDevMsg( m_pSettings, 1 );
}
void CMatchSessionOfflineCustom::OnEvent( KeyValues *pEvent )
{
char const *szEvent = pEvent->GetName();
if ( !Q_stricmp( "OnEngineClientSignonStateChange", szEvent ) )
{
int iOldState = pEvent->GetInt( "old", 0 );
int iNewState = pEvent->GetInt( "new", 0 );
if ( iOldState >= SIGNONSTATE_CONNECTED &&
iNewState < SIGNONSTATE_CONNECTED )
{
// Disconnecting from server
DevMsg( "OnEngineClientSignonStateChange\n" );
if ( m_bExpectingServerReload )
{
m_bExpectingServerReload = false;
DevMsg( " session was expecting server reload...\n" );
return;
}
g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) );
return;
}
}
else if ( !Q_stricmp( "OnEngineClientSignonStatePrepareChange", szEvent ) )
{
char const *szReason = pEvent->GetString( "reason" );
if ( !Q_stricmp( "reload", szReason ) )
{
Assert( !m_bExpectingServerReload );
m_bExpectingServerReload = true;
return;
}
else if ( !Q_stricmp( "load", szReason ) )
{
char const *szLevelName = g_pMatchExtensions->GetIVEngineClient()->GetLevelName();
if ( szLevelName && szLevelName[0] && g_pMatchExtensions->GetIVEngineClient()->IsConnected() )
{
Assert( !m_bExpectingServerReload );
m_bExpectingServerReload = true;
return;
}
}
}
else if ( !Q_stricmp( "OnEngineEndGame", szEvent ) )
{
DevMsg( "OnEngineEndGame\n" );
// Issue the disconnect command
g_pMatchExtensions->GetIVEngineClient()->ExecuteClientCmd( "disconnect" );
g_pMatchEventsSubscription->BroadcastEvent( new KeyValues( "mmF->CloseSession" ) );
return;
}
}
void CMatchSessionOfflineCustom::InitializeGameSettings()
{
// Since the session can be created with a minimal amount of data available
// the session object is responsible for initializing the missing data to defaults
// or saved values or values from gamer progress/profile or etc...
if ( KeyValues *kv = m_pSettings->FindKey( "system", true ) )
{
kv->SetString( "network", "offline" );
kv->SetString( "access", "public" );
}
if ( KeyValues *kv = m_pSettings->FindKey( "options", true ) )
{
kv->SetString( "server", "listen" );
}
if ( KeyValues *pMembers = m_pSettings->FindKey( "members", true ) )
{
pMembers->SetInt( "numMachines", 1 );
int numPlayers = 1;
#ifdef _GAMECONSOLE
numPlayers = XBX_GetNumGameUsers();
#endif
pMembers->SetInt( "numPlayers", numPlayers );
pMembers->SetInt( "numSlots", numPlayers );
if ( KeyValues *pMachine = pMembers->FindKey( "machine0", true ) )
{
IPlayerLocal *pPriPlayer = g_pPlayerManager->GetLocalPlayer( XBX_GetPrimaryUserId() );
pMachine->SetUint64( "id", ( pPriPlayer ? pPriPlayer->GetXUID() : INVALID_XUID ) );
pMachine->SetUint64( "flags", MatchSession_GetMachineFlags() );
pMachine->SetInt( "numPlayers", numPlayers );
pMachine->SetUint64( "dlcmask", g_pMatchFramework->GetMatchSystem()->GetDlcManager()->GetDataInfo()->GetUint64( "@info/installed" ) );
pMachine->SetString( "tuver", MatchSession_GetTuInstalledString() );
pMachine->SetInt( "ping", 0 );
for ( int k = 0; k < numPlayers; ++ k )
{
if ( KeyValues *pPlayer = pMachine->FindKey( CFmtStr( "player%d", k ), true ) )
{
int iController = 0;
#ifdef _GAMECONSOLE
iController = XBX_GetUserId( k );
#endif
IPlayerLocal *player = g_pPlayerManager->GetLocalPlayer( iController );
if ( player )
{
pPlayer->SetUint64( "xuid", player->GetXUID() );
pPlayer->SetString( "name", player->GetName() );
}
}
}
}
}
// Let the title extend the game settings
g_pMMF->GetMatchTitleGameSettingsMgr()->InitializeGameSettings( m_pSettings, "host" );
DevMsg( "CMatchSessionOfflineCustom::InitializeGameSettings adjusted settings:\n" );
KeyValuesDumpAsDevMsg( m_pSettings, 1 );
}
void CMatchSessionOfflineCustom::OnGamePrepareLobbyForGame()
{
// Remember which players will get updated
CUtlVector< KeyValues * > arrPlayersUpdated;
arrPlayersUpdated.SetCount( m_pSettings->GetInt( "members/numPlayers", 0 ) );
memset( arrPlayersUpdated.Base(), 0, arrPlayersUpdated.Count() * sizeof( KeyValues * ) );
g_pMMF->GetMatchTitleGameSettingsMgr()->PrepareLobbyForGame( m_pSettings, arrPlayersUpdated.Base() );
// Notify the framework of the updates
for ( int k = 0; k < arrPlayersUpdated.Count(); ++ k )
{
if ( !arrPlayersUpdated[k] )
break;
// Notify the framework about player updated
KeyValues *kvEvent = new KeyValues( "OnPlayerUpdated" );
kvEvent->SetUint64( "xuid", arrPlayersUpdated[k]->GetUint64( "xuid" ) );
g_pMatchEventsSubscription->BroadcastEvent( kvEvent );
}
// Let the title prepare for connect
MatchSession_PrepareClientForConnect( m_pSettings );
}