]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/game/Game_network.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / game / Game_network.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "Game_local.h"
33
34 /*
35 ===============================================================================
36
37         Client running game code:
38         - entity events don't work and should not be issued
39         - entities should never be spawned outside idGameLocal::ClientReadSnapshot
40
41 ===============================================================================
42 */
43
44 // adds tags to the network protocol to detect when things go bad ( internal consistency )
45 // NOTE: this changes the network protocol
46 #ifndef ASYNC_WRITE_TAGS
47         #define ASYNC_WRITE_TAGS 0
48 #endif
49
50 idCVar net_clientShowSnapshot( "net_clientShowSnapshot", "0", CVAR_GAME | CVAR_INTEGER, "", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
51 idCVar net_clientShowSnapshotRadius( "net_clientShowSnapshotRadius", "128", CVAR_GAME | CVAR_FLOAT, "" );
52 idCVar net_clientSmoothing( "net_clientSmoothing", "0.8", CVAR_GAME | CVAR_FLOAT, "smooth other clients angles and position.", 0.0f, 0.95f );
53 idCVar net_clientSelfSmoothing( "net_clientSelfSmoothing", "0.6", CVAR_GAME | CVAR_FLOAT, "smooth self position if network causes prediction error.", 0.0f, 0.95f );
54 idCVar net_clientMaxPrediction( "net_clientMaxPrediction", "1000", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "maximum number of milliseconds a client can predict ahead of server." );
55 idCVar net_clientLagOMeter( "net_clientLagOMeter", "1", CVAR_GAME | CVAR_BOOL | CVAR_NOCHEAT | CVAR_ARCHIVE, "draw prediction graph" );
56
57 /*
58 ================
59 idGameLocal::InitAsyncNetwork
60 ================
61 */
62 void idGameLocal::InitAsyncNetwork( void ) {
63         int i, type;
64
65         for ( i = 0; i < MAX_CLIENTS; i++ ) {
66                 for ( type = 0; type < declManager->GetNumDeclTypes(); type++ ) {
67                         clientDeclRemap[i][type].Clear();
68                 }
69         }
70
71         memset( clientEntityStates, 0, sizeof( clientEntityStates ) );
72         memset( clientPVS, 0, sizeof( clientPVS ) );
73         memset( clientSnapshots, 0, sizeof( clientSnapshots ) );
74
75         eventQueue.Init();
76         savedEventQueue.Init();
77
78         entityDefBits = -( idMath::BitsForInteger( declManager->GetNumDecls( DECL_ENTITYDEF ) ) + 1 );
79         localClientNum = 0; // on a listen server SetLocalUser will set this right
80         realClientTime = 0;
81         isNewFrame = true;
82         clientSmoothing = net_clientSmoothing.GetFloat();
83 }
84
85 /*
86 ================
87 idGameLocal::ShutdownAsyncNetwork
88 ================
89 */
90 void idGameLocal::ShutdownAsyncNetwork( void ) {
91         entityStateAllocator.Shutdown();
92         snapshotAllocator.Shutdown();
93         eventQueue.Shutdown();
94         savedEventQueue.Shutdown();
95         memset( clientEntityStates, 0, sizeof( clientEntityStates ) );
96         memset( clientPVS, 0, sizeof( clientPVS ) );
97         memset( clientSnapshots, 0, sizeof( clientSnapshots ) );
98 }
99
100 /*
101 ================
102 idGameLocal::InitLocalClient
103 ================
104 */
105 void idGameLocal::InitLocalClient( int clientNum ) {
106         isServer = false;
107         isClient = true;
108         localClientNum = clientNum;
109         clientSmoothing = net_clientSmoothing.GetFloat();
110 }
111
112 /*
113 ================
114 idGameLocal::InitClientDeclRemap
115 ================
116 */
117 void idGameLocal::InitClientDeclRemap( int clientNum ) {
118         int type, i, num;
119
120         for ( type = 0; type < declManager->GetNumDeclTypes(); type++ ) {
121
122                 // only implicit materials and sound shaders decls are used
123                 if ( type != DECL_MATERIAL && type != DECL_SOUND ) {
124                         continue;
125                 }
126
127                 num = declManager->GetNumDecls( (declType_t) type );
128                 clientDeclRemap[clientNum][type].Clear();
129                 clientDeclRemap[clientNum][type].AssureSize( num, -1 );
130
131                 // pre-initialize the remap with non-implicit decls, all non-implicit decls are always going
132                 // to be in order and in sync between server and client because of the decl manager checksum
133                 for ( i = 0; i < num; i++ ) {
134                         const idDecl *decl = declManager->DeclByIndex( (declType_t) type, i, false );
135                         if ( decl->IsImplicit() ) {
136                                 // once the first implicit decl is found all remaining decls are considered implicit as well
137                                 break;
138                         }
139                         clientDeclRemap[clientNum][type][i] = i;
140                 }
141         }
142 }
143
144 /*
145 ================
146 idGameLocal::ServerSendDeclRemapToClient
147 ================
148 */
149 void idGameLocal::ServerSendDeclRemapToClient( int clientNum, declType_t type, int index ) {
150         idBitMsg        outMsg;
151         byte            msgBuf[MAX_GAME_MESSAGE_SIZE];
152
153         // if no client connected for this spot
154         if ( entities[clientNum] == NULL ) {
155                 return;
156         }
157         // increase size of list if required
158         if ( index >= clientDeclRemap[clientNum][type].Num() ) {
159                 clientDeclRemap[clientNum][(int)type].AssureSize( index + 1, -1 );
160         }
161         // if already remapped
162         if ( clientDeclRemap[clientNum][(int)type][index] != -1 ) {
163                 return;
164         }
165
166         const idDecl *decl = declManager->DeclByIndex( type, index, false );
167         if ( decl == NULL ) {
168                 gameLocal.Error( "server tried to remap bad %s decl index %d", declManager->GetDeclNameFromType( type ), index );
169                 return;
170         }
171
172         // set the index at the server
173         clientDeclRemap[clientNum][(int)type][index] = index;
174
175         // write update to client
176         outMsg.Init( msgBuf, sizeof( msgBuf ) );
177         outMsg.BeginWriting();
178         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_REMAP_DECL );
179         outMsg.WriteByte( type );
180         outMsg.WriteLong( index );
181         outMsg.WriteString( decl->GetName() );
182         networkSystem->ServerSendReliableMessage( clientNum, outMsg );
183 }
184
185 /*
186 ================
187 idGameLocal::ServerRemapDecl
188 ================
189 */
190 int idGameLocal::ServerRemapDecl( int clientNum, declType_t type, int index ) {
191
192         // only implicit materials and sound shaders decls are used
193         if ( type != DECL_MATERIAL && type != DECL_SOUND ) {
194                 return index;
195         }
196
197         if ( clientNum == -1 ) {
198                 for ( int i = 0; i < MAX_CLIENTS; i++ ) {
199                         ServerSendDeclRemapToClient( i, type, index );
200                 }
201         } else {
202                 ServerSendDeclRemapToClient( clientNum, type, index );
203         }
204         return index;
205 }
206
207 /*
208 ================
209 idGameLocal::ClientRemapDecl
210 ================
211 */
212 int idGameLocal::ClientRemapDecl( declType_t type, int index ) {
213
214         // only implicit materials and sound shaders decls are used
215         if ( type != DECL_MATERIAL && type != DECL_SOUND ) {
216                 return index;
217         }
218
219         // negative indexes are sometimes used for NULL decls
220         if ( index < 0 ) {
221                 return index;
222         }
223
224         // make sure the index is valid
225         if ( clientDeclRemap[localClientNum][(int)type].Num() == 0 ) {
226                 gameLocal.Error( "client received decl index %d before %s decl remap was initialized", index, declManager->GetDeclNameFromType( type ) );
227                 return -1;
228         }
229         if ( index >= clientDeclRemap[localClientNum][(int)type].Num() ) {
230                 gameLocal.Error( "client received unmapped %s decl index %d from server", declManager->GetDeclNameFromType( type ), index );
231                 return -1;
232         }
233         if ( clientDeclRemap[localClientNum][(int)type][index] == -1 ) {
234                 gameLocal.Error( "client received unmapped %s decl index %d from server", declManager->GetDeclNameFromType( type ), index );
235                 return -1;
236         }
237         return clientDeclRemap[localClientNum][type][index];
238 }
239
240 /*
241 ================
242 idGameLocal::ServerAllowClient
243 ================
244 */
245 allowReply_t idGameLocal::ServerAllowClient( int numClients, const char *IP, const char *guid, const char *password, char reason[ MAX_STRING_CHARS ] ) {
246         reason[0] = '\0';
247
248         if ( serverInfo.GetInt( "si_pure" ) && !mpGame.IsPureReady() ) {
249                 idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07139" );
250                 return ALLOW_NOTYET;
251         }
252
253         if ( !serverInfo.GetInt( "si_maxPlayers" ) ) {
254                 idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07140" );
255                 return ALLOW_NOTYET;
256         }
257
258         if ( numClients >= serverInfo.GetInt( "si_maxPlayers" ) ) {
259                 idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07141" );
260                 return ALLOW_NOTYET;
261         }
262
263         if ( !cvarSystem->GetCVarBool( "si_usepass" ) ) {
264                 return ALLOW_YES;
265         }
266
267         const char *pass = cvarSystem->GetCVarString( "g_password" );
268         if ( pass[ 0 ] == '\0' ) {
269                 common->Warning( "si_usepass is set but g_password is empty" );
270                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "say si_usepass is set but g_password is empty" );
271                 // avoids silent misconfigured state
272                 idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07142" );
273                 return ALLOW_NOTYET;
274         }
275
276         if ( !idStr::Cmp( pass, password ) ) {
277                 return ALLOW_YES;
278         }
279
280         idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07143" );
281         Printf( "Rejecting client %s from IP %s: invalid password\n", guid, IP );
282         return ALLOW_BADPASS;
283 }
284
285 /*
286 ================
287 idGameLocal::ServerClientConnect
288 ================
289 */
290 void idGameLocal::ServerClientConnect( int clientNum, const char *guid ) {
291         // make sure no parasite entity is left
292         if ( entities[ clientNum ] ) {
293                 common->DPrintf( "ServerClientConnect: remove old player entity\n" );
294                 delete entities[ clientNum ];
295         }
296         userInfo[ clientNum ].Clear();
297         mpGame.ServerClientConnect( clientNum );
298         Printf( "client %d connected.\n", clientNum );
299 }
300
301 /*
302 ================
303 idGameLocal::ServerClientBegin
304 ================
305 */
306 void idGameLocal::ServerClientBegin( int clientNum ) {
307         idBitMsg        outMsg;
308         byte            msgBuf[MAX_GAME_MESSAGE_SIZE];
309
310         // initialize the decl remap
311         InitClientDeclRemap( clientNum );
312
313         // send message to initialize decl remap at the client (this is always the very first reliable game message)
314         outMsg.Init( msgBuf, sizeof( msgBuf ) );
315         outMsg.BeginWriting();
316         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_INIT_DECL_REMAP );
317         networkSystem->ServerSendReliableMessage( clientNum, outMsg );
318
319         // spawn the player
320         SpawnPlayer( clientNum );
321         if ( clientNum == localClientNum ) {
322                 mpGame.EnterGame( clientNum );
323         }
324
325         // send message to spawn the player at the clients
326         outMsg.Init( msgBuf, sizeof( msgBuf ) );
327         outMsg.BeginWriting();
328         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SPAWN_PLAYER );
329         outMsg.WriteByte( clientNum );
330         outMsg.WriteLong( spawnIds[ clientNum ] );
331         networkSystem->ServerSendReliableMessage( -1, outMsg );
332 }
333
334 /*
335 ================
336 idGameLocal::ServerClientDisconnect
337 ================
338 */
339 void idGameLocal::ServerClientDisconnect( int clientNum ) {
340         int                     i;
341         idBitMsg        outMsg;
342         byte            msgBuf[MAX_GAME_MESSAGE_SIZE];
343
344         outMsg.Init( msgBuf, sizeof( msgBuf ) );
345         outMsg.BeginWriting();
346         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_DELETE_ENT );
347         outMsg.WriteBits( ( spawnIds[ clientNum ] << GENTITYNUM_BITS ) | clientNum, 32 ); // see GetSpawnId
348         networkSystem->ServerSendReliableMessage( -1, outMsg );
349
350         // free snapshots stored for this client
351         FreeSnapshotsOlderThanSequence( clientNum, 0x7FFFFFFF );
352
353         // free entity states stored for this client
354         for ( i = 0; i < MAX_GENTITIES; i++ ) {
355                 if ( clientEntityStates[ clientNum ][ i ] ) {
356                         entityStateAllocator.Free( clientEntityStates[ clientNum ][ i ] );
357                         clientEntityStates[ clientNum ][ i ] = NULL;
358                 }
359         }
360
361         // clear the client PVS
362         memset( clientPVS[ clientNum ], 0, sizeof( clientPVS[ clientNum ] ) );
363
364         // delete the player entity
365         delete entities[ clientNum ];
366
367         mpGame.DisconnectClient( clientNum );
368
369 }
370
371 /*
372 ================
373 idGameLocal::ServerWriteInitialReliableMessages
374
375   Send reliable messages to initialize the client game up to a certain initial state.
376 ================
377 */
378 void idGameLocal::ServerWriteInitialReliableMessages( int clientNum ) {
379         int                     i;
380         idBitMsg        outMsg;
381         byte            msgBuf[MAX_GAME_MESSAGE_SIZE];
382         entityNetEvent_t *event;
383
384         // spawn players
385         for ( i = 0; i < MAX_CLIENTS; i++ ) {
386                 if ( entities[i] == NULL || i == clientNum ) {
387                         continue;
388                 }
389                 outMsg.Init( msgBuf, sizeof( msgBuf ) );
390                 outMsg.BeginWriting( );
391                 outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SPAWN_PLAYER );
392                 outMsg.WriteByte( i );
393                 outMsg.WriteLong( spawnIds[ i ] );
394                 networkSystem->ServerSendReliableMessage( clientNum, outMsg );
395         }
396
397         // send all saved events
398         for ( event = savedEventQueue.Start(); event; event = event->next ) {
399                 outMsg.Init( msgBuf, sizeof( msgBuf ) );
400                 outMsg.BeginWriting();
401                 outMsg.WriteByte( GAME_RELIABLE_MESSAGE_EVENT );
402                 outMsg.WriteBits( event->spawnId, 32 );
403                 outMsg.WriteByte( event->event );
404                 outMsg.WriteLong( event->time );
405                 outMsg.WriteBits( event->paramsSize, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
406                 if ( event->paramsSize ) {
407                         outMsg.WriteData( event->paramsBuf, event->paramsSize );
408                 }
409
410                 networkSystem->ServerSendReliableMessage( clientNum, outMsg );
411         }
412
413         // update portals for opened doors
414         int numPortals = gameRenderWorld->NumPortals();
415         outMsg.Init( msgBuf, sizeof( msgBuf ) );
416         outMsg.BeginWriting();
417         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_PORTALSTATES );
418         outMsg.WriteLong( numPortals );
419         for ( i = 0; i < numPortals; i++ ) {
420                 outMsg.WriteBits( gameRenderWorld->GetPortalState( (qhandle_t) (i+1) ) , NUM_RENDER_PORTAL_BITS );
421         }
422         networkSystem->ServerSendReliableMessage( clientNum, outMsg );
423
424         mpGame.ServerWriteInitialReliableMessages( clientNum );
425 }
426
427 /*
428 ================
429 idGameLocal::SaveEntityNetworkEvent
430 ================
431 */
432 void idGameLocal::SaveEntityNetworkEvent( const idEntity *ent, int eventId, const idBitMsg *msg ) {
433         entityNetEvent_t *event;
434
435         event = savedEventQueue.Alloc();
436         event->spawnId = GetSpawnId( ent );
437         event->event = eventId;
438         event->time = time;
439         if ( msg ) {
440                 event->paramsSize = msg->GetSize();
441                 memcpy( event->paramsBuf, msg->GetData(), msg->GetSize() );
442         } else {
443                 event->paramsSize = 0;
444         }
445
446         savedEventQueue.Enqueue( event, idEventQueue::OUTOFORDER_IGNORE );
447 }
448
449 /*
450 ================
451 idGameLocal::FreeSnapshotsOlderThanSequence
452 ================
453 */
454 void idGameLocal::FreeSnapshotsOlderThanSequence( int clientNum, int sequence ) {
455         snapshot_t *snapshot, *lastSnapshot, *nextSnapshot;
456         entityState_t *state;
457
458         for ( lastSnapshot = NULL, snapshot = clientSnapshots[clientNum]; snapshot; snapshot = nextSnapshot ) {
459                 nextSnapshot = snapshot->next;
460                 if ( snapshot->sequence < sequence ) {
461                         for ( state = snapshot->firstEntityState; state; state = snapshot->firstEntityState ) {
462                                 snapshot->firstEntityState = snapshot->firstEntityState->next;
463                                 entityStateAllocator.Free( state );
464                         }
465                         if ( lastSnapshot ) {
466                                 lastSnapshot->next = snapshot->next;
467                         } else {
468                                 clientSnapshots[clientNum] = snapshot->next;
469                         }
470                         snapshotAllocator.Free( snapshot );
471                 } else {
472                         lastSnapshot = snapshot;
473                 }
474         }
475 }
476
477 /*
478 ================
479 idGameLocal::ApplySnapshot
480 ================
481 */
482 bool idGameLocal::ApplySnapshot( int clientNum, int sequence ) {
483         snapshot_t *snapshot, *lastSnapshot, *nextSnapshot;
484         entityState_t *state;
485
486         FreeSnapshotsOlderThanSequence( clientNum, sequence );
487
488         for ( lastSnapshot = NULL, snapshot = clientSnapshots[clientNum]; snapshot; snapshot = nextSnapshot ) {
489                 nextSnapshot = snapshot->next;
490                 if ( snapshot->sequence == sequence ) {
491                         for ( state = snapshot->firstEntityState; state; state = state->next ) {
492                                 if ( clientEntityStates[clientNum][state->entityNumber] ) {
493                                         entityStateAllocator.Free( clientEntityStates[clientNum][state->entityNumber] );
494                                 }
495                                 clientEntityStates[clientNum][state->entityNumber] = state;
496                         }
497                         memcpy( clientPVS[clientNum], snapshot->pvs, sizeof( snapshot->pvs ) );
498                         if ( lastSnapshot ) {
499                                 lastSnapshot->next = nextSnapshot;
500                         } else {
501                                 clientSnapshots[clientNum] = nextSnapshot;
502                         }
503                         snapshotAllocator.Free( snapshot );
504                         return true;
505                 } else {
506                         lastSnapshot = snapshot;
507                 }
508         }
509
510         return false;
511 }
512
513 /*
514 ================
515 idGameLocal::WriteGameStateToSnapshot
516 ================
517 */
518 void idGameLocal::WriteGameStateToSnapshot( idBitMsgDelta &msg ) const {
519         int i;
520
521         for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
522                 msg.WriteFloat( globalShaderParms[i] );
523         }
524
525         mpGame.WriteToSnapshot( msg );
526 }
527
528 /*
529 ================
530 idGameLocal::ReadGameStateFromSnapshot
531 ================
532 */
533 void idGameLocal::ReadGameStateFromSnapshot( const idBitMsgDelta &msg ) {
534         int i;
535
536         for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
537                 globalShaderParms[i] = msg.ReadFloat();
538         }
539
540         mpGame.ReadFromSnapshot( msg );
541 }
542
543 /*
544 ================
545 idGameLocal::ServerWriteSnapshot
546
547   Write a snapshot of the current game state for the given client.
548 ================
549 */
550 void idGameLocal::ServerWriteSnapshot( int clientNum, int sequence, idBitMsg &msg, byte *clientInPVS, int numPVSClients ) {
551         int i, msgSize, msgWriteBit;
552         idPlayer *player, *spectated = NULL;
553         idEntity *ent;
554         pvsHandle_t pvsHandle;
555         idBitMsgDelta deltaMsg;
556         snapshot_t *snapshot;
557         entityState_t *base, *newBase;
558         int numSourceAreas, sourceAreas[ idEntity::MAX_PVS_AREAS ];
559
560         player = static_cast<idPlayer *>( entities[ clientNum ] );
561         if ( !player ) {
562                 return;
563         }
564         if ( player->spectating && player->spectator != clientNum && entities[ player->spectator ] ) {
565                 spectated = static_cast< idPlayer * >( entities[ player->spectator ] );
566         } else {
567                 spectated = player;
568         }
569         
570         // free too old snapshots
571         FreeSnapshotsOlderThanSequence( clientNum, sequence - 64 );
572
573         // allocate new snapshot
574         snapshot = snapshotAllocator.Alloc();
575         snapshot->sequence = sequence;
576         snapshot->firstEntityState = NULL;
577         snapshot->next = clientSnapshots[clientNum];
578         clientSnapshots[clientNum] = snapshot;
579         memset( snapshot->pvs, 0, sizeof( snapshot->pvs ) );
580
581         // get PVS for this player
582         // don't use PVSAreas for networking - PVSAreas depends on animations (and md5 bounds), which are not synchronized
583         numSourceAreas = gameRenderWorld->BoundsInAreas( spectated->GetPlayerPhysics()->GetAbsBounds(), sourceAreas, idEntity::MAX_PVS_AREAS );
584         pvsHandle = gameLocal.pvs.SetupCurrentPVS( sourceAreas, numSourceAreas, PVS_NORMAL );
585
586 #if ASYNC_WRITE_TAGS
587         idRandom tagRandom;
588         tagRandom.SetSeed( random.RandomInt() );
589         msg.WriteLong( tagRandom.GetSeed() );
590 #endif
591
592         // create the snapshot
593         for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
594
595                 // if the entity is not in the player PVS
596                 if ( !ent->PhysicsTeamInPVS( pvsHandle ) && ent->entityNumber != clientNum ) {
597                         continue;
598                 }
599
600                 // add the entity to the snapshot pvs
601                 snapshot->pvs[ ent->entityNumber >> 5 ] |= 1 << ( ent->entityNumber & 31 );
602
603                 // if that entity is not marked for network synchronization
604                 if ( !ent->fl.networkSync ) {
605                         continue;
606                 }
607
608                 // save the write state to which we can revert when the entity didn't change at all
609                 msg.SaveWriteState( msgSize, msgWriteBit );
610
611                 // write the entity to the snapshot
612                 msg.WriteBits( ent->entityNumber, GENTITYNUM_BITS );
613
614                 base = clientEntityStates[clientNum][ent->entityNumber];
615                 if ( base ) {
616                         base->state.BeginReading();
617                 }
618                 newBase = entityStateAllocator.Alloc();
619                 newBase->entityNumber = ent->entityNumber;
620                 newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) );
621                 newBase->state.BeginWriting();
622
623                 deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg );
624
625                 deltaMsg.WriteBits( spawnIds[ ent->entityNumber ], 32 - GENTITYNUM_BITS );
626                 deltaMsg.WriteBits( ent->GetType()->typeNum, idClass::GetTypeNumBits() );
627                 deltaMsg.WriteBits( ServerRemapDecl( -1, DECL_ENTITYDEF, ent->entityDefNumber ), entityDefBits );
628
629                 // write the class specific data to the snapshot
630                 ent->WriteToSnapshot( deltaMsg );
631
632                 if ( !deltaMsg.HasChanged() ) {
633                         msg.RestoreWriteState( msgSize, msgWriteBit );
634                         entityStateAllocator.Free( newBase );
635                 } else {
636                         newBase->next = snapshot->firstEntityState;
637                         snapshot->firstEntityState = newBase;
638
639 #if ASYNC_WRITE_TAGS
640                         msg.WriteLong( tagRandom.RandomInt() );
641 #endif
642                 }
643         }
644
645         msg.WriteBits( ENTITYNUM_NONE, GENTITYNUM_BITS );
646
647         // write the PVS to the snapshot
648 #if ASYNC_WRITE_PVS
649         for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) {
650                 if ( i < numSourceAreas ) {
651                         msg.WriteLong( sourceAreas[ i ] );
652                 } else {
653                         msg.WriteLong( 0 );
654                 }
655         }
656         gameLocal.pvs.WritePVS( pvsHandle, msg );
657 #endif
658         for ( i = 0; i < ENTITY_PVS_SIZE; i++ ) {
659                 msg.WriteDeltaLong( clientPVS[clientNum][i], snapshot->pvs[i] );
660         }
661
662         // free the PVS
663         pvs.FreeCurrentPVS( pvsHandle );
664
665         // write the game and player state to the snapshot
666         base = clientEntityStates[clientNum][ENTITYNUM_NONE];   // ENTITYNUM_NONE is used for the game and player state
667         if ( base ) {
668                 base->state.BeginReading();
669         }
670         newBase = entityStateAllocator.Alloc();
671         newBase->entityNumber = ENTITYNUM_NONE;
672         newBase->next = snapshot->firstEntityState;
673         snapshot->firstEntityState = newBase;
674         newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) );
675         newBase->state.BeginWriting();
676         deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg );
677         if ( player->spectating && player->spectator != player->entityNumber && gameLocal.entities[ player->spectator ] && gameLocal.entities[ player->spectator ]->IsType( idPlayer::Type ) ) {
678                 static_cast< idPlayer * >( gameLocal.entities[ player->spectator ] )->WritePlayerStateToSnapshot( deltaMsg );
679         } else {
680                 player->WritePlayerStateToSnapshot( deltaMsg );
681         }
682         WriteGameStateToSnapshot( deltaMsg );
683
684         // copy the client PVS string
685         memcpy( clientInPVS, snapshot->pvs, ( numPVSClients + 7 ) >> 3 );
686         LittleRevBytes( clientInPVS, sizeof( int ), sizeof( clientInPVS ) / sizeof ( int ) );
687 }
688
689 /*
690 ================
691 idGameLocal::ServerApplySnapshot
692 ================
693 */
694 bool idGameLocal::ServerApplySnapshot( int clientNum, int sequence ) {
695         return ApplySnapshot( clientNum, sequence );
696 }
697
698 /*
699 ================
700 idGameLocal::NetworkEventWarning
701 ================
702 */
703 void idGameLocal::NetworkEventWarning( const entityNetEvent_t *event, const char *fmt, ... ) {
704         char buf[1024];
705         int length = 0;
706         va_list argptr;
707
708         int entityNum   = event->spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 );
709         int id                  = event->spawnId >> GENTITYNUM_BITS;
710
711         length += idStr::snPrintf( buf+length, sizeof(buf)-1-length, "event %d for entity %d %d: ", event->event, entityNum, id );
712         va_start( argptr, fmt );
713         length = idStr::vsnPrintf( buf+length, sizeof(buf)-1-length, fmt, argptr );
714         va_end( argptr );
715         idStr::Append( buf, sizeof(buf), "\n" );
716
717         common->DWarning( buf );
718 }
719
720 /*
721 ================
722 idGameLocal::ServerProcessEntityNetworkEventQueue
723 ================
724 */
725 void idGameLocal::ServerProcessEntityNetworkEventQueue( void ) {
726         idEntity                        *ent;
727         entityNetEvent_t        *event;
728         idBitMsg                        eventMsg;
729
730         while ( eventQueue.Start() ) {
731                 event = eventQueue.Start();
732
733                 if ( event->time > time ) {
734                         break;
735                 }
736
737                 idEntityPtr< idEntity > entPtr;
738                         
739                 if( !entPtr.SetSpawnId( event->spawnId ) ) {
740                         NetworkEventWarning( event, "Entity does not exist any longer, or has not been spawned yet." );
741                 } else {
742                         ent = entPtr.GetEntity();
743                         assert( ent );
744
745                         eventMsg.Init( event->paramsBuf, sizeof( event->paramsBuf ) );
746                         eventMsg.SetSize( event->paramsSize );
747                         eventMsg.BeginReading();
748                         if ( !ent->ServerReceiveEvent( event->event, event->time, eventMsg ) ) {
749                                 NetworkEventWarning( event, "unknown event" );
750                         }
751                 }
752
753                 entityNetEvent_t* freedEvent = eventQueue.Dequeue();
754                 assert( freedEvent == event );
755                 eventQueue.Free( event );
756         }
757 }
758
759 /*
760 ================
761 idGameLocal::ServerSendChatMessage
762 ================
763 */
764 void idGameLocal::ServerSendChatMessage( int to, const char *name, const char *text ) {
765         idBitMsg outMsg;
766         byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
767
768         outMsg.Init( msgBuf, sizeof( msgBuf ) );
769         outMsg.BeginWriting();
770         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CHAT );
771         outMsg.WriteString( name );
772         outMsg.WriteString( text, -1, false );
773         networkSystem->ServerSendReliableMessage( to, outMsg );
774
775         if ( to == -1 || to == localClientNum ) {
776                 mpGame.AddChatLine( "%s^0: %s\n", name, text );
777         }
778 }
779
780 /*
781 ================
782 idGameLocal::ServerProcessReliableMessage
783 ================
784 */
785 void idGameLocal::ServerProcessReliableMessage( int clientNum, const idBitMsg &msg ) {
786         int id;
787
788         id = msg.ReadByte();
789         switch( id ) {
790                 case GAME_RELIABLE_MESSAGE_CHAT:
791                 case GAME_RELIABLE_MESSAGE_TCHAT: {
792                         char name[128];
793                         char text[128];
794
795                         msg.ReadString( name, sizeof( name ) );
796                         msg.ReadString( text, sizeof( text ) );
797
798                         mpGame.ProcessChatMessage( clientNum, id == GAME_RELIABLE_MESSAGE_TCHAT, name, text, NULL );
799
800                         break;
801                 }
802                 case GAME_RELIABLE_MESSAGE_VCHAT: {
803                         int index = msg.ReadLong();
804                         bool team = msg.ReadBits( 1 ) != 0;
805                         mpGame.ProcessVoiceChat( clientNum, team, index );
806                         break;
807                 }
808                 case GAME_RELIABLE_MESSAGE_KILL: {
809                         mpGame.WantKilled( clientNum );
810                         break;
811                 }
812                 case GAME_RELIABLE_MESSAGE_DROPWEAPON: {
813                         mpGame.DropWeapon( clientNum );
814                         break;
815                 }
816                 case GAME_RELIABLE_MESSAGE_CALLVOTE: {
817                         mpGame.ServerCallVote( clientNum, msg );
818                         break;
819                 }
820                 case GAME_RELIABLE_MESSAGE_CASTVOTE: {
821                         bool vote = ( msg.ReadByte() != 0 );
822                         mpGame.CastVote( clientNum, vote );
823                         break;
824                 }
825 #if 0
826                 // uncomment this if you want to track when players are in a menu
827                 case GAME_RELIABLE_MESSAGE_MENU: {
828                         bool menuUp = ( msg.ReadBits( 1 ) != 0 );
829                         break;
830                 }
831 #endif
832                 case GAME_RELIABLE_MESSAGE_EVENT: {
833                         entityNetEvent_t *event;
834
835                         // allocate new event
836                         event = eventQueue.Alloc();
837                         eventQueue.Enqueue( event, idEventQueue::OUTOFORDER_DROP );
838
839                         event->spawnId = msg.ReadBits( 32 );
840                         event->event = msg.ReadByte();
841                         event->time = msg.ReadLong();
842
843                         event->paramsSize = msg.ReadBits( idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
844                         if ( event->paramsSize ) {
845                                 if ( event->paramsSize > MAX_EVENT_PARAM_SIZE ) {
846                                         NetworkEventWarning( event, "invalid param size" );
847                                         return;
848                                 }
849                                 msg.ReadByteAlign();
850                                 msg.ReadData( event->paramsBuf, event->paramsSize );
851                         }
852                         break;
853                 }
854                 default: {
855                         Warning( "Unknown client->server reliable message: %d", id );
856                         break;
857                 }
858         }
859 }
860
861 /*
862 ================
863 idGameLocal::ClientShowSnapshot
864 ================
865 */
866 void idGameLocal::ClientShowSnapshot( int clientNum ) const {
867         int baseBits;
868         idEntity *ent;
869         idPlayer *player;
870         idMat3 viewAxis;
871         idBounds viewBounds;
872         entityState_t *base;
873
874         if ( !net_clientShowSnapshot.GetInteger() ) {
875                 return;
876         }
877
878         player = static_cast<idPlayer *>( entities[clientNum] );
879         if ( !player ) {
880                 return;
881         }
882
883         viewAxis = player->viewAngles.ToMat3();
884         viewBounds = player->GetPhysics()->GetAbsBounds().Expand( net_clientShowSnapshotRadius.GetFloat() );
885
886         for( ent = snapshotEntities.Next(); ent != NULL; ent = ent->snapshotNode.Next() ) {
887
888                 if ( net_clientShowSnapshot.GetInteger() == 1 && ent->snapshotBits == 0 ) {
889                         continue;
890                 }
891
892                 const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds();
893
894                 if ( !entBounds.IntersectsBounds( viewBounds ) ) {
895                         continue;
896                 }
897
898                 base = clientEntityStates[clientNum][ent->entityNumber];
899                 if ( base ) {
900                         baseBits = base->state.GetNumBitsWritten();
901                 } else {
902                         baseBits = 0;
903                 }
904
905                 if ( net_clientShowSnapshot.GetInteger() == 2 && baseBits == 0 ) {
906                         continue;
907                 }
908
909                 gameRenderWorld->DebugBounds( colorGreen, entBounds );
910                 gameRenderWorld->DrawText( va( "%d: %s (%d,%d bytes of %d,%d)\n", ent->entityNumber,
911                                                 ent->name.c_str(), ent->snapshotBits >> 3, ent->snapshotBits & 7, baseBits >> 3, baseBits & 7 ),
912                                                         entBounds.GetCenter(), 0.1f, colorWhite, viewAxis, 1 );
913         }
914 }
915
916 /*
917 ================
918 idGameLocal::UpdateLagometer
919 ================
920 */
921 void idGameLocal::UpdateLagometer( int aheadOfServer, int dupeUsercmds ) {
922                 int i, j, ahead;
923                 for ( i = 0; i < LAGO_HEIGHT; i++ ) {
924                         memmove( (byte *)lagometer + LAGO_WIDTH * 4 * i, (byte *)lagometer + LAGO_WIDTH * 4 * i + 4, ( LAGO_WIDTH - 1 ) * 4 );
925                 }
926                 j = LAGO_WIDTH - 1;
927                 for ( i = 0; i < LAGO_HEIGHT; i++ ) {
928                         lagometer[i][j][0] = lagometer[i][j][1] = lagometer[i][j][2] = lagometer[i][j][3] = 0;
929                 }
930                 ahead = idMath::Rint( (float)aheadOfServer / 16.0f );
931                 if ( ahead >= 0 ) {
932                         for ( i = 2 * Max( 0, 5 - ahead ); i < 2 * 5; i++ ) {
933                                 lagometer[i][j][1] = 255;
934                                 lagometer[i][j][3] = 255;
935                         }
936                 } else {
937                         for ( i = 2 * 5; i < 2 * ( 5 + Min( 10, -ahead ) ); i++ ) {
938                                 lagometer[i][j][0] = 255;
939                                 lagometer[i][j][1] = 255;
940                                 lagometer[i][j][3] = 255;
941                         }
942                 }
943                 for ( i = LAGO_HEIGHT - 2 * Min( 6, dupeUsercmds ); i < LAGO_HEIGHT; i++ ) {
944                         lagometer[i][j][0] = 255;
945                         if ( dupeUsercmds <= 2 ) {
946                                 lagometer[i][j][1] = 255;
947                         }
948                         lagometer[i][j][3] = 255;
949                 }
950 }
951
952 /*
953 ================
954 idGameLocal::ClientReadSnapshot
955 ================
956 */
957 void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gameFrame, const int gameTime, const int dupeUsercmds, const int aheadOfServer, const idBitMsg &msg ) {
958         int                             i, typeNum, entityDefNumber, numBitsRead;
959         idTypeInfo              *typeInfo;
960         idEntity                *ent;
961         idPlayer                *player, *spectated;
962         pvsHandle_t             pvsHandle;
963         idDict                  args;
964         const char              *classname;
965         idBitMsgDelta   deltaMsg;
966         snapshot_t              *snapshot;
967         entityState_t   *base, *newBase;
968         int                             spawnId;
969         int                             numSourceAreas, sourceAreas[ idEntity::MAX_PVS_AREAS ];
970         idWeapon                *weap;
971
972         if ( net_clientLagOMeter.GetBool() && renderSystem ) {
973                 UpdateLagometer( aheadOfServer, dupeUsercmds );
974                 if ( !renderSystem->UploadImage( LAGO_IMAGE, (byte *)lagometer, LAGO_IMG_WIDTH, LAGO_IMG_HEIGHT ) ) {
975                         common->Printf( "lagometer: UploadImage failed. turning off net_clientLagOMeter\n" );
976                         net_clientLagOMeter.SetBool( false );
977                 }
978         }
979
980         InitLocalClient( clientNum );
981
982         // clear any debug lines from a previous frame
983         gameRenderWorld->DebugClearLines( time );
984
985         // clear any debug polygons from a previous frame
986         gameRenderWorld->DebugClearPolygons( time );
987
988         // update the game time
989         framenum = gameFrame;
990         time = gameTime;
991         previousTime = time - msec;
992
993         // so that StartSound/StopSound doesn't risk skipping
994         isNewFrame = true;
995
996         // clear the snapshot entity list
997         snapshotEntities.Clear();
998
999         // allocate new snapshot
1000         snapshot = snapshotAllocator.Alloc();
1001         snapshot->sequence = sequence;
1002         snapshot->firstEntityState = NULL;
1003         snapshot->next = clientSnapshots[clientNum];
1004         clientSnapshots[clientNum] = snapshot;
1005
1006 #if ASYNC_WRITE_TAGS
1007         idRandom tagRandom;
1008         tagRandom.SetSeed( msg.ReadLong() );
1009 #endif
1010
1011         // read all entities from the snapshot
1012         for ( i = msg.ReadBits( GENTITYNUM_BITS ); i != ENTITYNUM_NONE; i = msg.ReadBits( GENTITYNUM_BITS ) ) {
1013
1014                 base = clientEntityStates[clientNum][i];
1015                 if ( base ) {
1016                         base->state.BeginReading();
1017                 }
1018                 newBase = entityStateAllocator.Alloc();
1019                 newBase->entityNumber = i;
1020                 newBase->next = snapshot->firstEntityState;
1021                 snapshot->firstEntityState = newBase;
1022                 newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) );
1023                 newBase->state.BeginWriting();
1024
1025                 numBitsRead = msg.GetNumBitsRead();
1026
1027                 deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg );
1028
1029                 spawnId = deltaMsg.ReadBits( 32 - GENTITYNUM_BITS );
1030                 typeNum = deltaMsg.ReadBits( idClass::GetTypeNumBits() );
1031                 entityDefNumber = ClientRemapDecl( DECL_ENTITYDEF, deltaMsg.ReadBits( entityDefBits ) );
1032
1033                 typeInfo = idClass::GetType( typeNum );
1034                 if ( !typeInfo ) {
1035                         Error( "Unknown type number %d for entity %d with class number %d", typeNum, i, entityDefNumber );
1036                 }
1037
1038                 ent = entities[i];
1039
1040                 // if there is no entity or an entity of the wrong type
1041                 if ( !ent || ent->GetType()->typeNum != typeNum || ent->entityDefNumber != entityDefNumber || spawnId != spawnIds[ i ] ) {
1042
1043                         if ( i < MAX_CLIENTS && ent ) {
1044                                 // SPAWN_PLAYER should be taking care of spawning the entity with the right spawnId
1045                                 common->Warning( "ClientReadSnapshot: recycling client entity %d\n", i );
1046                         }
1047
1048                         delete ent;
1049
1050                         spawnCount = spawnId;
1051
1052                         args.Clear();
1053                         args.SetInt( "spawn_entnum", i );
1054                         args.Set( "name", va( "entity%d", i ) );
1055
1056                         if ( entityDefNumber >= 0 ) {
1057                                 if ( entityDefNumber >= declManager->GetNumDecls( DECL_ENTITYDEF ) ) {
1058                                         Error( "server has %d entityDefs instead of %d", entityDefNumber, declManager->GetNumDecls( DECL_ENTITYDEF ) );
1059                                 }
1060                                 classname = declManager->DeclByIndex( DECL_ENTITYDEF, entityDefNumber, false )->GetName();
1061                                 args.Set( "classname", classname );
1062                                 if ( !SpawnEntityDef( args, &ent ) || !entities[i] || entities[i]->GetType()->typeNum != typeNum ) {
1063                                         Error( "Failed to spawn entity with classname '%s' of type '%s'", classname, typeInfo->classname );
1064                                 }
1065                         } else {
1066                                 ent = SpawnEntityType( *typeInfo, &args, true );
1067                                 if ( !entities[i] || entities[i]->GetType()->typeNum != typeNum ) {
1068                                         Error( "Failed to spawn entity of type '%s'", typeInfo->classname );
1069                                 }
1070                         }
1071                         if ( i < MAX_CLIENTS && i >= numClients ) {
1072                                 numClients = i + 1;
1073                         }
1074                 }
1075
1076                 // add the entity to the snapshot list
1077                 ent->snapshotNode.AddToEnd( snapshotEntities );
1078                 ent->snapshotSequence = sequence;
1079
1080                 // read the class specific data from the snapshot
1081                 ent->ReadFromSnapshot( deltaMsg );
1082
1083                 ent->snapshotBits = msg.GetNumBitsRead() - numBitsRead;
1084
1085 #if ASYNC_WRITE_TAGS
1086                 if ( msg.ReadLong() != tagRandom.RandomInt() ) {
1087                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, "writeGameState" );
1088                         if ( entityDefNumber >= 0 && entityDefNumber < declManager->GetNumDecls( DECL_ENTITYDEF ) ) {
1089                                 classname = declManager->DeclByIndex( DECL_ENTITYDEF, entityDefNumber, false )->GetName();
1090                                 Error( "write to and read from snapshot out of sync for classname '%s' of type '%s'", classname, typeInfo->classname );
1091                         } else {
1092                                 Error( "write to and read from snapshot out of sync for type '%s'", typeInfo->classname );
1093                         }
1094                 }
1095 #endif
1096         }
1097
1098         player = static_cast<idPlayer *>( entities[clientNum] );
1099         if ( !player ) {
1100                 return;
1101         }
1102
1103         // if prediction is off, enable local client smoothing
1104         player->SetSelfSmooth( dupeUsercmds > 2 );
1105
1106         if ( player->spectating && player->spectator != clientNum && entities[ player->spectator ] ) {
1107                 spectated = static_cast< idPlayer * >( entities[ player->spectator ] );
1108         } else {
1109                 spectated = player;
1110         }
1111
1112         // get PVS for this player
1113         // don't use PVSAreas for networking - PVSAreas depends on animations (and md5 bounds), which are not synchronized
1114         numSourceAreas = gameRenderWorld->BoundsInAreas( spectated->GetPlayerPhysics()->GetAbsBounds(), sourceAreas, idEntity::MAX_PVS_AREAS );
1115         pvsHandle = gameLocal.pvs.SetupCurrentPVS( sourceAreas, numSourceAreas, PVS_NORMAL );
1116
1117         // read the PVS from the snapshot
1118 #if ASYNC_WRITE_PVS
1119         int serverPVS[idEntity::MAX_PVS_AREAS];
1120         i = numSourceAreas;
1121         while ( i < idEntity::MAX_PVS_AREAS ) {
1122                 sourceAreas[ i++ ] = 0;
1123         }
1124         for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) {
1125                 serverPVS[ i ] = msg.ReadLong();
1126         }
1127         if ( memcmp( sourceAreas, serverPVS, idEntity::MAX_PVS_AREAS * sizeof( int ) ) ) {
1128                 common->Warning( "client PVS areas != server PVS areas, sequence 0x%x", sequence );
1129                 for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) {
1130                         common->DPrintf( "%3d ", sourceAreas[ i ] );
1131                 }
1132                 common->DPrintf( "\n" );
1133                 for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) {
1134                         common->DPrintf( "%3d ", serverPVS[ i ] );
1135                 }
1136                 common->DPrintf( "\n" );
1137         }
1138         gameLocal.pvs.ReadPVS( pvsHandle, msg );
1139 #endif
1140         for ( i = 0; i < ENTITY_PVS_SIZE; i++ ) {
1141                 snapshot->pvs[i] = msg.ReadDeltaLong( clientPVS[clientNum][i] );
1142         }
1143
1144         // add entities in the PVS that haven't changed since the last applied snapshot
1145         for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
1146
1147                 // if the entity is already in the snapshot
1148                 if ( ent->snapshotSequence == sequence ) {
1149                         continue;
1150                 }
1151
1152                 // if the entity is not in the snapshot PVS
1153                 if ( !( snapshot->pvs[ent->entityNumber >> 5] & ( 1 << ( ent->entityNumber & 31 ) ) ) ) {
1154                         if ( ent->PhysicsTeamInPVS( pvsHandle ) ) {
1155                                 if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < mapSpawnCount ) {
1156                                         // server says it's not in PVS, client says it's in PVS
1157                                         // if that happens on map entities, most likely something is wrong
1158                                         // I can see that moving pieces along several PVS could be a legit situation though
1159                                         // this is a band aid, which means something is not done right elsewhere
1160                                         common->DWarning( "client thinks map entity 0x%x (%s) is stale, sequence 0x%x", ent->entityNumber, ent->name.c_str(), sequence );
1161                                 } else {
1162                                         ent->FreeModelDef();
1163                                         ent->UpdateVisuals();
1164                                         ent->GetPhysics()->UnlinkClip();
1165                                 }
1166                         }
1167                         continue;
1168                 }
1169
1170                 // add the entity to the snapshot list
1171                 ent->snapshotNode.AddToEnd( snapshotEntities );
1172                 ent->snapshotSequence = sequence;
1173                 ent->snapshotBits = 0;
1174
1175                 base = clientEntityStates[clientNum][ent->entityNumber];
1176                 if ( !base ) {
1177                         // entity has probably fl.networkSync set to false
1178                         continue;
1179                 }
1180
1181                 base->state.BeginReading();
1182
1183                 deltaMsg.Init( &base->state, NULL, (const idBitMsg *)NULL );
1184
1185                 spawnId = deltaMsg.ReadBits( 32 - GENTITYNUM_BITS );
1186                 typeNum = deltaMsg.ReadBits( idClass::GetTypeNumBits() );
1187                 entityDefNumber = deltaMsg.ReadBits( entityDefBits );
1188
1189                 typeInfo = idClass::GetType( typeNum );
1190
1191                 // if the entity is not the right type
1192                 if ( !typeInfo || ent->GetType()->typeNum != typeNum || ent->entityDefNumber != entityDefNumber ) {
1193                         // should never happen - it does though. with != entityDefNumber only?
1194                         common->DWarning( "entity '%s' is not the right type %p 0x%d 0x%x 0x%x 0x%x", ent->GetName(), typeInfo, ent->GetType()->typeNum, typeNum, ent->entityDefNumber, entityDefNumber );
1195                         continue;
1196                 }
1197
1198                 // read the class specific data from the base state
1199                 ent->ReadFromSnapshot( deltaMsg );
1200         }
1201
1202         // free the PVS
1203         pvs.FreeCurrentPVS( pvsHandle );
1204
1205         // read the game and player state from the snapshot
1206         base = clientEntityStates[clientNum][ENTITYNUM_NONE];   // ENTITYNUM_NONE is used for the game and player state
1207         if ( base ) {
1208                 base->state.BeginReading();
1209         }
1210         newBase = entityStateAllocator.Alloc();
1211         newBase->entityNumber = ENTITYNUM_NONE;
1212         newBase->next = snapshot->firstEntityState;
1213         snapshot->firstEntityState = newBase;
1214         newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) );
1215         newBase->state.BeginWriting();
1216         deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg );
1217         if ( player->spectating && player->spectator != player->entityNumber && gameLocal.entities[ player->spectator ] && gameLocal.entities[ player->spectator ]->IsType( idPlayer::Type ) ) {
1218                 static_cast< idPlayer * >( gameLocal.entities[ player->spectator ] )->ReadPlayerStateFromSnapshot( deltaMsg );
1219                 weap = static_cast< idPlayer * >( gameLocal.entities[ player->spectator ] )->weapon.GetEntity();
1220                 if ( weap && ( weap->GetRenderEntity()->bounds[0] == weap->GetRenderEntity()->bounds[1] ) ) {
1221                         // update the weapon's viewmodel bounds so that the model doesn't flicker in the spectator's view
1222                         weap->GetAnimator()->GetBounds( gameLocal.time, weap->GetRenderEntity()->bounds );
1223                         weap->UpdateVisuals();
1224                 }
1225         } else {
1226                 player->ReadPlayerStateFromSnapshot( deltaMsg );
1227         }
1228         ReadGameStateFromSnapshot( deltaMsg );
1229
1230         // visualize the snapshot
1231         ClientShowSnapshot( clientNum );
1232
1233         // process entity events
1234         ClientProcessEntityNetworkEventQueue();
1235 }
1236
1237 /*
1238 ================
1239 idGameLocal::ClientApplySnapshot
1240 ================
1241 */
1242 bool idGameLocal::ClientApplySnapshot( int clientNum, int sequence ) {
1243         return ApplySnapshot( clientNum, sequence );
1244 }
1245
1246 /*
1247 ================
1248 idGameLocal::ClientProcessEntityNetworkEventQueue
1249 ================
1250 */
1251 void idGameLocal::ClientProcessEntityNetworkEventQueue( void ) {
1252         idEntity                        *ent;
1253         entityNetEvent_t        *event;
1254         idBitMsg                        eventMsg;
1255
1256         while( eventQueue.Start() ) {
1257                 event = eventQueue.Start();
1258
1259                 // only process forward, in order
1260                 if ( event->time > time ) {
1261                         break;
1262                 }
1263
1264                 idEntityPtr< idEntity > entPtr;
1265                         
1266                 if( !entPtr.SetSpawnId( event->spawnId ) ) {
1267                         if( !gameLocal.entities[ event->spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 ) ] ) {
1268                                 // if new entity exists in this position, silently ignore
1269                                 NetworkEventWarning( event, "Entity does not exist any longer, or has not been spawned yet." );
1270                         }
1271                 } else {
1272                         ent = entPtr.GetEntity();
1273                         assert( ent );
1274
1275                         eventMsg.Init( event->paramsBuf, sizeof( event->paramsBuf ) );
1276                         eventMsg.SetSize( event->paramsSize );
1277                         eventMsg.BeginReading();
1278                         if ( !ent->ClientReceiveEvent( event->event, event->time, eventMsg ) ) {
1279                                 NetworkEventWarning( event, "unknown event" );
1280                         }
1281                 }
1282
1283                 entityNetEvent_t* freedEvent = eventQueue.Dequeue();
1284                 assert( freedEvent == event );
1285                 eventQueue.Free( event );
1286         }
1287 }
1288
1289 /*
1290 ================
1291 idGameLocal::ClientProcessReliableMessage
1292 ================
1293 */
1294 void idGameLocal::ClientProcessReliableMessage( int clientNum, const idBitMsg &msg ) {
1295         int                     id, line;
1296         idPlayer        *p;
1297         idDict          backupSI;
1298
1299         InitLocalClient( clientNum );
1300
1301         id = msg.ReadByte();
1302         switch( id ) {
1303                 case GAME_RELIABLE_MESSAGE_INIT_DECL_REMAP: {
1304                         InitClientDeclRemap( clientNum );
1305                         break;
1306                 }
1307                 case GAME_RELIABLE_MESSAGE_REMAP_DECL: {
1308                         int type, index;
1309                         char name[MAX_STRING_CHARS];
1310
1311                         type = msg.ReadByte();
1312                         index = msg.ReadLong();
1313                         msg.ReadString( name, sizeof( name ) );
1314
1315                         const idDecl *decl = declManager->FindType( (declType_t)type, name, false );
1316                         if ( decl != NULL ) {
1317                                 if ( index >= clientDeclRemap[clientNum][type].Num() ) {
1318                                         clientDeclRemap[clientNum][type].AssureSize( index + 1, -1 );
1319                                 }
1320                                 clientDeclRemap[clientNum][type][index] = decl->Index();
1321                         }
1322                         break;
1323                 }
1324                 case GAME_RELIABLE_MESSAGE_SPAWN_PLAYER: {
1325                         int client = msg.ReadByte();
1326                         int spawnId = msg.ReadLong();
1327                         if ( !entities[ client ] ) {
1328                                 SpawnPlayer( client );
1329                                 entities[ client ]->FreeModelDef();
1330                         }
1331                         // fix up the spawnId to match what the server says
1332                         // otherwise there is going to be a bogus delete/new of the client entity in the first ClientReadFromSnapshot
1333                         spawnIds[ client ] = spawnId;
1334                         break;
1335                 }
1336                 case GAME_RELIABLE_MESSAGE_DELETE_ENT: {
1337                         int spawnId = msg.ReadBits( 32 );
1338                         idEntityPtr< idEntity > entPtr;
1339                         if( !entPtr.SetSpawnId( spawnId ) ) {
1340                                 break;
1341                         }
1342                         delete entPtr.GetEntity();
1343                         break;
1344                 }
1345                 case GAME_RELIABLE_MESSAGE_CHAT:
1346                 case GAME_RELIABLE_MESSAGE_TCHAT: { // (client should never get a TCHAT though)
1347                         char name[128];
1348                         char text[128];
1349                         msg.ReadString( name, sizeof( name ) );
1350                         msg.ReadString( text, sizeof( text ) );
1351                         mpGame.AddChatLine( "%s^0: %s\n", name, text );
1352                         break;
1353                 }
1354                 case GAME_RELIABLE_MESSAGE_SOUND_EVENT: {
1355                         snd_evt_t snd_evt = (snd_evt_t)msg.ReadByte();
1356                         mpGame.PlayGlobalSound( -1, snd_evt );
1357                         break;
1358                 }
1359                 case GAME_RELIABLE_MESSAGE_SOUND_INDEX: {
1360                         int index = gameLocal.ClientRemapDecl( DECL_SOUND, msg.ReadLong() );
1361                         if ( index >= 0 && index < declManager->GetNumDecls( DECL_SOUND ) ) {
1362                                 const idSoundShader *shader = declManager->SoundByIndex( index );
1363                                 mpGame.PlayGlobalSound( -1, SND_COUNT, shader->GetName() );
1364                         }
1365                         break;
1366                 }
1367                 case GAME_RELIABLE_MESSAGE_DB: {
1368                         idMultiplayerGame::msg_evt_t msg_evt = (idMultiplayerGame::msg_evt_t)msg.ReadByte();
1369                         int parm1, parm2;
1370                         parm1 = msg.ReadByte( );
1371                         parm2 = msg.ReadByte( );
1372                         mpGame.PrintMessageEvent( -1, msg_evt, parm1, parm2 );
1373                         break;
1374                 }
1375                 case GAME_RELIABLE_MESSAGE_EVENT: {
1376                         entityNetEvent_t *event;
1377
1378                         // allocate new event
1379                         event = eventQueue.Alloc();
1380                         eventQueue.Enqueue( event, idEventQueue::OUTOFORDER_IGNORE );
1381
1382                         event->spawnId = msg.ReadBits( 32 );
1383                         event->event = msg.ReadByte();
1384                         event->time = msg.ReadLong();
1385
1386                         event->paramsSize = msg.ReadBits( idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
1387                         if ( event->paramsSize ) {
1388                                 if ( event->paramsSize > MAX_EVENT_PARAM_SIZE ) {
1389                                         NetworkEventWarning( event, "invalid param size" );
1390                                         return;
1391                                 }
1392                                 msg.ReadByteAlign();
1393                                 msg.ReadData( event->paramsBuf, event->paramsSize );
1394                         }
1395                         break;
1396                 }
1397                 case GAME_RELIABLE_MESSAGE_SERVERINFO: {
1398                         idDict info;
1399                         msg.ReadDeltaDict( info, NULL );
1400                         gameLocal.SetServerInfo( info );
1401                         break;
1402                 }
1403                 case GAME_RELIABLE_MESSAGE_RESTART: {
1404                         MapRestart();
1405                         break;
1406                 }
1407                 case GAME_RELIABLE_MESSAGE_TOURNEYLINE: {
1408                         line = msg.ReadByte( );
1409                         p = static_cast< idPlayer * >( entities[ clientNum ] );
1410                         if ( !p ) {
1411                                 break;
1412                         }
1413                         p->tourneyLine = line;
1414                         break;
1415                 }
1416                 case GAME_RELIABLE_MESSAGE_STARTVOTE: {
1417                         char voteString[ MAX_STRING_CHARS ];
1418                         int clientNum = msg.ReadByte( );
1419                         msg.ReadString( voteString, sizeof( voteString ) );
1420                         mpGame.ClientStartVote( clientNum, voteString );
1421                         break;
1422                 }
1423                 case GAME_RELIABLE_MESSAGE_UPDATEVOTE: {
1424                         int result = msg.ReadByte( );
1425                         int yesCount = msg.ReadByte( );
1426                         int noCount = msg.ReadByte( );
1427                         mpGame.ClientUpdateVote( (idMultiplayerGame::vote_result_t)result, yesCount, noCount );
1428                         break;
1429                 }
1430                 case GAME_RELIABLE_MESSAGE_PORTALSTATES: {
1431                         int numPortals = msg.ReadLong();
1432                         assert( numPortals == gameRenderWorld->NumPortals() );
1433                         for ( int i = 0; i < numPortals; i++ ) {
1434                                 gameRenderWorld->SetPortalState( (qhandle_t) (i+1), msg.ReadBits( NUM_RENDER_PORTAL_BITS ) );
1435                         }
1436                         break;
1437                 }
1438                 case GAME_RELIABLE_MESSAGE_PORTAL: {
1439                         qhandle_t portal = msg.ReadLong();
1440                         int blockingBits = msg.ReadBits( NUM_RENDER_PORTAL_BITS );
1441                         assert( portal > 0 && portal <= gameRenderWorld->NumPortals() );
1442                         gameRenderWorld->SetPortalState( portal, blockingBits );
1443                         break;
1444                 }
1445                 case GAME_RELIABLE_MESSAGE_STARTSTATE: {
1446                         mpGame.ClientReadStartState( msg );
1447                         break;
1448                 }
1449                 case GAME_RELIABLE_MESSAGE_WARMUPTIME: {
1450                         mpGame.ClientReadWarmupTime( msg );
1451                         break;
1452                 }
1453                 default: {
1454                         Error( "Unknown server->client reliable message: %d", id );
1455                         break;
1456                 }
1457         }
1458 }
1459
1460 /*
1461 ================
1462 idGameLocal::ClientPrediction
1463 ================
1464 */
1465 gameReturn_t idGameLocal::ClientPrediction( int clientNum, const usercmd_t *clientCmds, bool lastPredictFrame ) {
1466         idEntity *ent;
1467         idPlayer *player;
1468         gameReturn_t ret;
1469
1470         ret.sessionCommand[ 0 ] = '\0';
1471
1472         player = static_cast<idPlayer *>( entities[clientNum] );
1473         if ( !player ) {
1474                 return ret;
1475         }
1476
1477         // check for local client lag
1478         if ( networkSystem->ClientGetTimeSinceLastPacket() >= net_clientMaxPrediction.GetInteger() ) {
1479                 player->isLagged = true;
1480         } else {
1481                 player->isLagged = false;
1482         }
1483
1484         InitLocalClient( clientNum );
1485
1486         // update the game time
1487         framenum++;
1488         previousTime = time;
1489         time += msec;
1490
1491         // update the real client time and the new frame flag
1492         if ( time > realClientTime ) {
1493                 realClientTime = time;
1494                 isNewFrame = true;
1495         } else {
1496                 isNewFrame = false;
1497         }
1498
1499         // set the user commands for this frame
1500         memcpy( usercmds, clientCmds, numClients * sizeof( usercmds[ 0 ] ) );
1501
1502         // run prediction on all entities from the last snapshot
1503         for( ent = snapshotEntities.Next(); ent != NULL; ent = ent->snapshotNode.Next() ) {
1504                 ent->thinkFlags |= TH_PHYSICS;
1505                 ent->ClientPredictionThink();
1506         }
1507
1508         // service any pending events
1509         idEvent::ServiceEvents();
1510
1511         // show any debug info for this frame
1512         if ( isNewFrame ) {
1513                 RunDebugInfo();
1514                 D_DrawDebugLines();
1515         }
1516
1517         if ( sessionCommand.Length() ) {
1518                 strncpy( ret.sessionCommand, sessionCommand, sizeof( ret.sessionCommand ) );
1519         }
1520         return ret;
1521 }
1522
1523 /*
1524 ===============
1525 idGameLocal::Tokenize
1526 ===============
1527 */
1528 void idGameLocal::Tokenize( idStrList &out, const char *in ) {
1529         char buf[ MAX_STRING_CHARS ];
1530         char *token, *next;
1531         
1532         idStr::Copynz( buf, in, MAX_STRING_CHARS );
1533         token = buf;
1534         next = strchr( token, ';' );
1535         while ( token ) {
1536                 if ( next ) {
1537                         *next = '\0';
1538                 }
1539                 idStr::ToLower( token );
1540                 out.Append( token );
1541                 if ( next ) {
1542                         token = next + 1;
1543                         next = strchr( token, ';' );
1544                 } else {
1545                         token = NULL;
1546                 }               
1547         }
1548 }
1549
1550 /*
1551 ===============
1552 idGameLocal::DownloadRequest
1553 ===============
1554 */
1555 bool idGameLocal::DownloadRequest( const char *IP, const char *guid, const char *paks, char urls[ MAX_STRING_CHARS ] ) {
1556         if ( !cvarSystem->GetCVarInteger( "net_serverDownload" ) ) {
1557                 return false;
1558         }
1559         if ( cvarSystem->GetCVarInteger( "net_serverDownload" ) == 1 ) {
1560                 // 1: single URL redirect
1561                 if ( !strlen( cvarSystem->GetCVarString( "si_serverURL" ) ) ) {
1562                         common->Warning( "si_serverURL not set" );
1563                         return false;
1564                 }
1565                 idStr::snPrintf( urls, MAX_STRING_CHARS, "1;%s", cvarSystem->GetCVarString( "si_serverURL" ) );
1566                 return true;
1567         } else {
1568                 // 2: table of pak URLs
1569                 // first token is the game pak if request, empty if not requested by the client
1570                 // there may be empty tokens for paks the server couldn't pinpoint - the order matters
1571                 idStr reply = "2;";
1572                 idStrList dlTable, pakList;
1573                 int i, j;
1574
1575                 Tokenize( dlTable, cvarSystem->GetCVarString( "net_serverDlTable" ) );
1576                 Tokenize( pakList, paks );
1577
1578                 for ( i = 0; i < pakList.Num(); i++ ) {
1579                         if ( i > 0 ) {
1580                                 reply += ";";
1581                         }
1582                         if ( pakList[ i ][ 0 ] == '\0' ) {
1583                                 if ( i == 0 ) {
1584                                         // pak 0 will always miss when client doesn't ask for game bin
1585                                         common->DPrintf( "no game pak request\n" );
1586                                 } else {
1587                                         common->DPrintf( "no pak %d\n", i );
1588                                 }
1589                                 continue;
1590                         }
1591                         for ( j = 0; j < dlTable.Num(); j++ ) {
1592                                 if ( !fileSystem->FilenameCompare( pakList[ i ], dlTable[ j ] ) ) {
1593                                         break;
1594                                 }
1595                         }
1596                         if ( j == dlTable.Num() ) {
1597                                 common->Printf( "download for %s: pak not matched: %s\n", IP, pakList[ i ].c_str() );
1598                         } else {
1599                                 idStr url = cvarSystem->GetCVarString( "net_serverDlBaseURL" );
1600                                 url.AppendPath( dlTable[ j ] );
1601                                 reply += url;
1602                                 common->DPrintf( "download for %s: %s\n", IP, url.c_str() );
1603                         }
1604                 }
1605                 
1606                 idStr::Copynz( urls, reply, MAX_STRING_CHARS );
1607                 return true;
1608         }
1609         return false;
1610 }
1611
1612 /*
1613 ===============
1614 idEventQueue::Alloc
1615 ===============
1616 */
1617 entityNetEvent_t* idEventQueue::Alloc() {
1618         entityNetEvent_t* event = eventAllocator.Alloc();
1619         event->prev = NULL;
1620         event->next = NULL;
1621         return event;
1622 }
1623
1624 /*
1625 ===============
1626 idEventQueue::Free
1627 ===============
1628 */
1629 void idEventQueue::Free( entityNetEvent_t *event ) {
1630         // should only be called on an unlinked event!
1631         assert( !event->next && !event->prev );
1632         eventAllocator.Free( event );
1633 }
1634
1635 /*
1636 ===============
1637 idEventQueue::Shutdown
1638 ===============
1639 */
1640 void idEventQueue::Shutdown() {
1641         eventAllocator.Shutdown();
1642         this->Init();
1643 }
1644
1645 /*
1646 ===============
1647 idEventQueue::Init
1648 ===============
1649 */
1650 void idEventQueue::Init( void ) {
1651         start = NULL;
1652         end = NULL;
1653 }
1654
1655 /*
1656 ===============
1657 idEventQueue::Dequeue
1658 ===============
1659 */
1660 entityNetEvent_t* idEventQueue::Dequeue( void ) {
1661         entityNetEvent_t* event = start;
1662         if ( !event ) {
1663                 return NULL;
1664         }
1665
1666         start = start->next;
1667
1668         if ( !start ) {
1669                 end = NULL;
1670         } else {
1671                 start->prev = NULL;
1672         }
1673
1674         event->next = NULL;
1675         event->prev = NULL;
1676
1677         return event;
1678 }
1679
1680 /*
1681 ===============
1682 idEventQueue::RemoveLast
1683 ===============
1684 */
1685 entityNetEvent_t* idEventQueue::RemoveLast( void ) {
1686         entityNetEvent_t *event = end;
1687         if ( !event ) {
1688                 return NULL;
1689         }
1690
1691         end = event->prev;
1692
1693         if ( !end ) {
1694                 start = NULL;
1695         } else {
1696                 end->next = NULL;               
1697         }
1698
1699         event->next = NULL;
1700         event->prev = NULL;
1701
1702         return event;
1703 }
1704
1705 /*
1706 ===============
1707 idEventQueue::Enqueue
1708 ===============
1709 */
1710 void idEventQueue::Enqueue( entityNetEvent_t *event, outOfOrderBehaviour_t behaviour ) {
1711         if ( behaviour == OUTOFORDER_DROP ) {
1712                 // go backwards through the queue and determine if there are
1713                 // any out-of-order events
1714                 while ( end && end->time > event->time ) {
1715                         entityNetEvent_t *outOfOrder = RemoveLast();
1716                         common->DPrintf( "WARNING: new event with id %d ( time %d ) caused removal of event with id %d ( time %d ), game time = %d.\n", event->event, event->time, outOfOrder->event, outOfOrder->time, gameLocal.time );
1717                         Free( outOfOrder );
1718                 }
1719         } else if ( behaviour == OUTOFORDER_SORT && end ) {
1720                 // NOT TESTED -- sorting out of order packets hasn't been
1721                 //                               tested yet... wasn't strictly necessary for
1722                 //                               the patch fix.
1723                 entityNetEvent_t *cur = end;
1724                 // iterate until we find a time < the new event's
1725                 while ( cur && cur->time > event->time ) {
1726                         cur = cur->prev;
1727                 }
1728                 if ( !cur ) {
1729                         // add to start
1730                         event->next = start;
1731                         event->prev = NULL;
1732                         start = event;
1733                 } else {
1734                         // insert
1735                         event->prev = cur;
1736                         event->next = cur->next;
1737                         cur->next = event;
1738                 }
1739                 return;
1740         } 
1741
1742         // add the new event
1743         event->next = NULL;
1744         event->prev = NULL;
1745
1746         if ( end ) {
1747                 end->next = event;
1748                 event->prev = end;
1749         } else {
1750                 start = event;
1751         }
1752         end = event;
1753 }