2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition 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 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
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 .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# pragma hdrstop
# include "Game_local.h"
2012-12-02 21:37:32 +00:00
# include "../framework/Common_local.h"
2012-11-26 18:58:24 +00:00
static const int SNAP_GAMESTATE = 0 ;
static const int SNAP_SHADERPARMS = 1 ;
static const int SNAP_PORTALS = 2 ;
static const int SNAP_PLAYERSTATE = SNAP_PORTALS + 1 ;
static const int SNAP_PLAYERSTATE_END = SNAP_PLAYERSTATE + MAX_PLAYERS ;
static const int SNAP_ENTITIES = SNAP_PLAYERSTATE_END ;
static const int SNAP_ENTITIES_END = SNAP_ENTITIES + MAX_GENTITIES ;
static const int SNAP_LAST_CLIENT_FRAME = SNAP_ENTITIES_END ;
static const int SNAP_LAST_CLIENT_FRAME_END = SNAP_LAST_CLIENT_FRAME + MAX_PLAYERS ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Client running game code :
- entity events don ' t work and should not be issued
- entities should never be spawned outside idGameLocal : : ClientReadSnapshot
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
idCVar net_clientSmoothing ( " net_clientSmoothing " , " 0.8 " , CVAR_GAME | CVAR_FLOAT , " smooth other clients angles and position. " , 0.0f , 0.95f ) ;
idCVar net_clientSelfSmoothing ( " net_clientSelfSmoothing " , " 0.6 " , CVAR_GAME | CVAR_FLOAT , " smooth self position if network causes prediction error. " , 0.0f , 0.95f ) ;
extern idCVar net_clientMaxPrediction ;
idCVar cg_predictedSpawn_debug ( " cg_predictedSpawn_debug " , " 0 " , CVAR_BOOL , " Debug predictive spawning of presentables " ) ;
idCVar g_clientFire_checkLineOfSightDebug ( " g_clientFire_checkLineOfSightDebug " , " 0 " , CVAR_BOOL , " " ) ;
/*
= = = = = = = = = = = = = = = =
idGameLocal : : InitAsyncNetwork
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : InitAsyncNetwork ( )
{
2012-11-26 18:58:24 +00:00
eventQueue . Init ( ) ;
savedEventQueue . Init ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
entityDefBits = - ( idMath : : BitsForInteger ( declManager - > GetNumDecls ( DECL_ENTITYDEF ) ) + 1 ) ;
realClientTime = 0 ;
fast . Set ( 0 , 0 , 0 ) ;
slow . Set ( 0 , 0 , 0 ) ;
isNewFrame = true ;
clientSmoothing = net_clientSmoothing . GetFloat ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lastCmdRunTimeOnClient . Zero ( ) ;
lastCmdRunTimeOnServer . Zero ( ) ;
usercmdLastClientMilliseconds . Zero ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ShutdownAsyncNetwork
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ShutdownAsyncNetwork ( )
{
2012-11-26 18:58:24 +00:00
eventQueue . Shutdown ( ) ;
savedEventQueue . Shutdown ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ServerRemapDecl
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idGameLocal : : ServerRemapDecl ( int clientNum , declType_t type , int index )
{
2012-11-26 18:58:24 +00:00
return index ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ClientRemapDecl
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idGameLocal : : ClientRemapDecl ( declType_t type , int index )
{
2012-11-26 18:58:24 +00:00
return index ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SyncPlayersWithLobbyUsers
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : SyncPlayersWithLobbyUsers ( bool initial )
{
idLobbyBase & lobby = session - > GetActingGameStateLobbyBase ( ) ;
if ( ! lobby . IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idStaticList < lobbyUserID_t , MAX_CLIENTS > newLobbyUsers ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// First, loop over lobby users, and see if we find a lobby user that we haven't registered
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < lobby . GetNumLobbyUsers ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
lobbyUserID_t lobbyUserID1 = lobby . GetLobbyUserIdByOrdinal ( i ) ;
2012-11-28 15:47:07 +00:00
if ( ! lobbyUserID1 . IsValid ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! initial & & ! lobby . IsLobbyUserLoaded ( lobbyUserID1 ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Now, see if we find this lobby user in our list
bool found = false ;
2012-11-28 15:47:07 +00:00
for ( int j = 0 ; j < MAX_PLAYERS ; j + + )
{
idPlayer * player = static_cast < idPlayer * > ( entities [ j ] ) ;
if ( player = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
lobbyUserID_t lobbyUserID2 = lobbyUserIDs [ j ] ;
2012-11-28 15:47:07 +00:00
if ( lobbyUserID1 = = lobbyUserID2 )
{
2012-11-26 18:58:24 +00:00
found = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! found )
{
2012-11-26 18:58:24 +00:00
// If we didn't find it, we need to create a player and assign it to this new lobby user
newLobbyUsers . Append ( lobbyUserID1 ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Validate connected players
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
{
idPlayer * player = static_cast < idPlayer * > ( entities [ i ] ) ;
if ( player = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
lobbyUserID_t lobbyUserID = lobbyUserIDs [ i ] ;
2012-11-28 15:47:07 +00:00
if ( ! lobby . IsLobbyUserValid ( lobbyUserID ) )
{
2012-11-26 18:58:24 +00:00
delete entities [ i ] ;
mpGame . DisconnectClient ( i ) ;
lobbyUserIDs [ i ] = lobbyUserID_t ( ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobby . EnableSnapshotsForLobbyUser ( lobbyUserID ) ;
}
2012-11-28 15:47:07 +00:00
while ( newLobbyUsers . Num ( ) > 0 )
{
2012-11-26 18:58:24 +00:00
// Find a free player data slot to use for this new player
int freePlayerDataIndex = - 1 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_PLAYERS ; + + i )
{
idPlayer * player = static_cast < idPlayer * > ( entities [ i ] ) ;
if ( player = = NULL )
{
2012-11-26 18:58:24 +00:00
freePlayerDataIndex = i ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( freePlayerDataIndex = = - 1 )
{
2012-11-26 18:58:24 +00:00
break ; // No player data slots (this shouldn't happen)
}
lobbyUserID_t lobbyUserID = newLobbyUsers [ 0 ] ;
newLobbyUsers . RemoveIndex ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
mpGame . ServerClientConnect ( freePlayerDataIndex ) ;
Printf ( " client %d connected. \n " , freePlayerDataIndex ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyUserIDs [ freePlayerDataIndex ] = lobbyUserID ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Clear this player's old usercmds.
common - > ResetPlayerInput ( freePlayerDataIndex ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
common - > UpdateLevelLoadPacifier ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// spawn the player
SpawnPlayer ( freePlayerDataIndex ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
common - > UpdateLevelLoadPacifier ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ServerWriteInitialReliableMessages ( freePlayerDataIndex , lobbyUserID ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ServerSendNetworkSyncCvars
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ServerSendNetworkSyncCvars ( )
{
if ( ( cvarSystem - > GetModifiedFlags ( ) & CVAR_NETWORKSYNC ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
cvarSystem - > ClearModifiedFlags ( CVAR_NETWORKSYNC ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idBitMsg outMsg ;
byte msgBuf [ MAX_GAME_MESSAGE_SIZE ] ;
2012-11-28 15:47:07 +00:00
idLobbyBase & lobby = session - > GetActingGameStateLobbyBase ( ) ;
2012-11-26 18:58:24 +00:00
outMsg . InitWrite ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . BeginWriting ( ) ;
idDict syncedCvars ;
cvarSystem - > MoveCVarsToDict ( CVAR_NETWORKSYNC , syncedCvars , true ) ;
outMsg . WriteDeltaDict ( syncedCvars , NULL ) ;
lobby . SendReliable ( GAME_RELIABLE_MESSAGE_SYNCEDCVARS , outMsg , false ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Sending networkSync cvars: \n " ) ;
syncedCvars . Print ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ServerWriteInitialReliableMessages
Send reliable messages to initialize the client game up to a certain initial state .
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ServerWriteInitialReliableMessages ( int clientNum , lobbyUserID_t lobbyUserID )
{
if ( clientNum = = GetLocalClientNum ( ) )
{
2012-11-26 18:58:24 +00:00
// We don't need to send messages to ourself
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idBitMsg outMsg ;
byte msgBuf [ MAX_GAME_MESSAGE_SIZE ] ;
2012-11-28 15:47:07 +00:00
idLobbyBase & lobby = session - > GetActingGameStateLobbyBase ( ) ;
2012-11-26 18:58:24 +00:00
outMsg . InitWrite ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . BeginWriting ( ) ;
idDict syncedCvars ;
cvarSystem - > MoveCVarsToDict ( CVAR_NETWORKSYNC , syncedCvars , true ) ;
outMsg . WriteDeltaDict ( syncedCvars , NULL ) ;
lobby . SendReliableToLobbyUser ( lobbyUserID , GAME_RELIABLE_MESSAGE_SYNCEDCVARS , outMsg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Sending initial networkSync cvars: \n " ) ;
syncedCvars . Print ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// send all saved events
2012-11-28 15:47:07 +00:00
for ( entityNetEvent_t * event = savedEventQueue . Start ( ) ; event ; event = event - > next )
{
2012-11-26 18:58:24 +00:00
outMsg . InitWrite ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . BeginWriting ( ) ;
outMsg . WriteBits ( event - > spawnId , 32 ) ;
outMsg . WriteByte ( event - > event ) ;
outMsg . WriteLong ( event - > time ) ;
outMsg . WriteBits ( event - > paramsSize , idMath : : BitsForInteger ( MAX_EVENT_PARAM_SIZE ) ) ;
2012-11-28 15:47:07 +00:00
if ( event - > paramsSize )
{
2012-11-26 18:58:24 +00:00
outMsg . WriteData ( event - > paramsBuf , event - > paramsSize ) ;
}
lobby . SendReliableToLobbyUser ( lobbyUserID , GAME_RELIABLE_MESSAGE_EVENT , outMsg ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
mpGame . ServerWriteInitialReliableMessages ( clientNum , lobbyUserID ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : SaveEntityNetworkEvent
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : SaveEntityNetworkEvent ( const idEntity * ent , int eventId , const idBitMsg * msg )
{
entityNetEvent_t * event = savedEventQueue . Alloc ( ) ;
2012-11-26 18:58:24 +00:00
event - > spawnId = GetSpawnId ( ent ) ;
event - > event = eventId ;
event - > time = time ;
2012-11-28 15:47:07 +00:00
if ( msg )
{
2012-11-26 18:58:24 +00:00
event - > paramsSize = msg - > GetSize ( ) ;
memcpy ( event - > paramsBuf , msg - > GetReadData ( ) , msg - > GetSize ( ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
event - > paramsSize = 0 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
savedEventQueue . Enqueue ( event , idEventQueue : : OUTOFORDER_IGNORE ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ServerWriteSnapshot
Write a snapshot of the current game state
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ServerWriteSnapshot ( idSnapShot & ss )
{
2012-11-26 18:58:24 +00:00
ss . SetTime ( fast . time ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
byte buffer [ MAX_ENTITY_STATE_SIZE ] ;
idBitMsg msg ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// First write the generic game state to the snapshot
msg . InitWrite ( buffer , sizeof ( buffer ) ) ;
mpGame . WriteToSnapshot ( msg ) ;
ss . S_AddObject ( SNAP_GAMESTATE , ~ 0U , msg , " Game State " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Update global shader parameters
msg . InitWrite ( buffer , sizeof ( buffer ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_GLOBAL_SHADER_PARMS ; i + + )
{
2012-11-26 18:58:24 +00:00
msg . WriteFloat ( globalShaderParms [ i ] ) ;
}
ss . S_AddObject ( SNAP_SHADERPARMS , ~ 0U , msg , " Shader Parms " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// update portals for opened doors
msg . InitWrite ( buffer , sizeof ( buffer ) ) ;
int numPortals = gameRenderWorld - > NumPortals ( ) ;
msg . WriteLong ( numPortals ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numPortals ; i + + )
{
msg . WriteBits ( gameRenderWorld - > GetPortalState ( ( qhandle_t ) ( i + 1 ) ) , NUM_RENDER_PORTAL_BITS ) ;
2012-11-26 18:58:24 +00:00
}
ss . S_AddObject ( SNAP_PORTALS , ~ 0U , msg , " Portal State " ) ;
2012-11-28 15:47:07 +00:00
idEntity * skyEnt = portalSkyEnt . GetEntity ( ) ;
2012-11-26 18:58:24 +00:00
pvsHandle_t portalSkyPVS ;
portalSkyPVS . i = - 1 ;
2012-11-28 15:47:07 +00:00
if ( skyEnt ! = NULL )
{
2012-11-26 18:58:24 +00:00
portalSkyPVS = pvs . SetupCurrentPVS ( skyEnt - > GetPVSAreas ( ) , skyEnt - > GetNumPVSAreas ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Build PVS data for each player and write their player state to the snapshot as well
pvsHandle_t pvsHandles [ MAX_PLAYERS ] ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
{
idPlayer * player = static_cast < idPlayer * > ( entities [ i ] ) ;
if ( player = = NULL )
{
2012-11-26 18:58:24 +00:00
pvsHandles [ i ] . i = - 1 ;
continue ;
}
2012-11-28 15:47:07 +00:00
idPlayer * spectated = player ;
if ( player - > spectating & & player - > spectator ! = i & & entities [ player - > spectator ] )
{
spectated = static_cast < idPlayer * > ( entities [ player - > spectator ] ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . InitWrite ( buffer , sizeof ( buffer ) ) ;
spectated - > WritePlayerStateToSnapshot ( msg ) ;
ss . S_AddObject ( SNAP_PLAYERSTATE + i , ~ 0U , msg , " Player State " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int sourceAreas [ idEntity : : MAX_PVS_AREAS ] ;
int numSourceAreas = gameRenderWorld - > BoundsInAreas ( spectated - > GetPlayerPhysics ( ) - > GetAbsBounds ( ) , sourceAreas , idEntity : : MAX_PVS_AREAS ) ;
pvsHandles [ i ] = pvs . SetupCurrentPVS ( sourceAreas , numSourceAreas , PVS_NORMAL ) ;
2012-11-28 15:47:07 +00:00
if ( portalSkyPVS . i > = 0 )
{
2012-11-26 18:58:24 +00:00
pvsHandle_t tempPVS = pvs . MergeCurrentPVS ( pvsHandles [ i ] , portalSkyPVS ) ;
pvs . FreeCurrentPVS ( pvsHandles [ i ] ) ;
pvsHandles [ i ] = tempPVS ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Write the last usercmd processed by the server so that clients know
// when to stop predicting.
msg . BeginWriting ( ) ;
msg . WriteLong ( usercmdLastClientMilliseconds [ i ] ) ;
ss . S_AddObject ( SNAP_LAST_CLIENT_FRAME + i , ~ 0U , msg , " Last client frame " ) ;
}
2012-11-28 15:47:07 +00:00
if ( portalSkyPVS . i > = 0 )
{
2012-11-26 18:58:24 +00:00
pvs . FreeCurrentPVS ( portalSkyPVS ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Add all entities to the snapshot
2012-11-28 15:47:07 +00:00
for ( idEntity * ent = spawnedEntities . Next ( ) ; ent ! = NULL ; ent = ent - > spawnNode . Next ( ) )
{
if ( ent - > GetSkipReplication ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . InitWrite ( buffer , sizeof ( buffer ) ) ;
msg . WriteBits ( spawnIds [ ent - > entityNumber ] , 32 - GENTITYNUM_BITS ) ;
msg . WriteBits ( ent - > GetType ( ) - > typeNum , idClass : : GetTypeNumBits ( ) ) ;
msg . WriteBits ( ServerRemapDecl ( - 1 , DECL_ENTITYDEF , ent - > entityDefNumber ) , entityDefBits ) ;
msg . WriteBits ( ent - > GetPredictedKey ( ) , 32 ) ;
2012-11-28 15:47:07 +00:00
if ( ent - > fl . networkSync )
{
2012-11-26 18:58:24 +00:00
// write the class specific data to the snapshot
ent - > WriteToSnapshot ( msg ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ss . S_AddObject ( SNAP_ENTITIES + ent - > entityNumber , ~ 0U , msg , ent - > GetName ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Free PVS handles for all the players
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
{
if ( pvsHandles [ i ] . i < 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
pvs . FreeCurrentPVS ( pvsHandles [ i ] ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : NetworkEventWarning
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : NetworkEventWarning ( const entityNetEvent_t * event , const char * fmt , . . . )
{
2012-11-26 18:58:24 +00:00
char buf [ 1024 ] ;
int length = 0 ;
va_list argptr ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int entityNum = event - > spawnId & ( ( 1 < < GENTITYNUM_BITS ) - 1 ) ;
int id = event - > spawnId > > GENTITYNUM_BITS ;
2012-11-28 15:47:07 +00:00
length + = idStr : : snPrintf ( buf + length , sizeof ( buf ) - 1 - length , " event %d for entity %d %d: " , event - > event , entityNum , id ) ;
2012-11-26 18:58:24 +00:00
va_start ( argptr , fmt ) ;
2012-11-28 15:47:07 +00:00
length = idStr : : vsnPrintf ( buf + length , sizeof ( buf ) - 1 - length , fmt , argptr ) ;
2012-11-26 18:58:24 +00:00
va_end ( argptr ) ;
2012-11-28 15:47:07 +00:00
idStr : : Append ( buf , sizeof ( buf ) , " \n " ) ;
2012-11-26 18:58:24 +00:00
common - > DWarning ( buf ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ServerProcessEntityNetworkEventQueue
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ServerProcessEntityNetworkEventQueue ( )
{
while ( eventQueue . Start ( ) )
{
entityNetEvent_t * event = eventQueue . Start ( ) ;
if ( event - > time > time )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idEntityPtr < idEntity > entPtr ;
2012-11-28 15:47:07 +00:00
if ( ! entPtr . SetSpawnId ( event - > spawnId ) )
{
2012-11-26 18:58:24 +00:00
NetworkEventWarning ( event , " Entity does not exist any longer, or has not been spawned yet. " ) ;
2012-11-28 15:47:07 +00:00
}
else
{
idEntity * ent = entPtr . GetEntity ( ) ;
2012-11-26 18:58:24 +00:00
assert ( ent ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idBitMsg eventMsg ;
eventMsg . InitRead ( event - > paramsBuf , sizeof ( event - > paramsBuf ) ) ;
eventMsg . SetSize ( event - > paramsSize ) ;
eventMsg . BeginReading ( ) ;
2012-11-28 15:47:07 +00:00
if ( ! ent - > ServerReceiveEvent ( event - > event , event - > time , eventMsg ) )
{
2012-11-26 18:58:24 +00:00
NetworkEventWarning ( event , " unknown event " ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
entityNetEvent_t * freedEvent = eventQueue . Dequeue ( ) ;
verify ( freedEvent = = event ) ;
eventQueue . Free ( event ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ProcessReliableMessage
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ProcessReliableMessage ( int clientNum , int type , const idBitMsg & msg )
{
if ( session - > GetActingGameStateLobbyBase ( ) . IsPeer ( ) )
{
2012-11-26 18:58:24 +00:00
ClientProcessReliableMessage ( type , msg ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
ServerProcessReliableMessage ( clientNum , type , msg ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ServerProcessReliableMessage
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ServerProcessReliableMessage ( int clientNum , int type , const idBitMsg & msg )
{
if ( clientNum < 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
switch ( type )
{
2012-11-26 18:58:24 +00:00
case GAME_RELIABLE_MESSAGE_CHAT :
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_TCHAT :
{
2012-11-26 18:58:24 +00:00
char name [ 128 ] ;
char text [ 128 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . ReadString ( name , sizeof ( name ) ) ;
msg . ReadString ( text , sizeof ( text ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
mpGame . ProcessChatMessage ( clientNum , type = = GAME_RELIABLE_MESSAGE_TCHAT , name , text , NULL ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_VCHAT :
{
2012-11-26 18:58:24 +00:00
int index = msg . ReadLong ( ) ;
bool team = msg . ReadBits ( 1 ) ! = 0 ;
mpGame . ProcessVoiceChat ( clientNum , team , index ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_DROPWEAPON :
{
2012-11-26 18:58:24 +00:00
mpGame . DropWeapon ( clientNum ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_EVENT :
{
2012-11-26 18:58:24 +00:00
// allocate new event
2012-11-28 15:47:07 +00:00
entityNetEvent_t * event = eventQueue . Alloc ( ) ;
2012-11-26 18:58:24 +00:00
eventQueue . Enqueue ( event , idEventQueue : : OUTOFORDER_DROP ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
event - > spawnId = msg . ReadBits ( 32 ) ;
event - > event = msg . ReadByte ( ) ;
event - > time = msg . ReadLong ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
event - > paramsSize = msg . ReadBits ( idMath : : BitsForInteger ( MAX_EVENT_PARAM_SIZE ) ) ;
2012-11-28 15:47:07 +00:00
if ( event - > paramsSize )
{
if ( event - > paramsSize > MAX_EVENT_PARAM_SIZE )
{
2012-11-26 18:58:24 +00:00
NetworkEventWarning ( event , " invalid param size " ) ;
return ;
}
msg . ReadByteAlign ( ) ;
msg . ReadData ( event - > paramsBuf , event - > paramsSize ) ;
}
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_SPECTATE :
{
2012-11-26 18:58:24 +00:00
bool spec = msg . ReadBool ( ) ;
2012-11-28 15:47:07 +00:00
idPlayer * player = GetClientByNum ( clientNum ) ;
if ( serverInfo . GetBool ( " si_spectators " ) )
{
2012-11-26 18:58:24 +00:00
// never let spectators go back to game while sudden death is on
2012-11-28 15:47:07 +00:00
if ( mpGame . GetGameState ( ) = = idMultiplayerGame : : SUDDENDEATH & & ! spec & & player - > wantSpectate )
{
2012-11-26 18:58:24 +00:00
// Don't allow the change
2012-11-28 15:47:07 +00:00
}
else
{
if ( player - > wantSpectate & & ! spec )
{
2012-11-26 18:58:24 +00:00
player - > forceRespawn = true ;
}
player - > wantSpectate = spec ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// If the server turned off si_spectators while a player is spectating, then any spectate message forces the player out of spectate mode
2012-11-28 15:47:07 +00:00
if ( player - > wantSpectate )
{
2012-11-26 18:58:24 +00:00
player - > forceRespawn = true ;
}
player - > wantSpectate = false ;
}
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_CLIENT_HITSCAN_HIT :
{
2012-11-26 18:58:24 +00:00
const int attackerNum = msg . ReadShort ( ) ;
const int victimNum = msg . ReadShort ( ) ;
idVec3 dir ;
msg . ReadVectorFloat ( dir ) ;
const int damageDefIndex = msg . ReadLong ( ) ;
const float damageScale = msg . ReadFloat ( ) ;
const int location = msg . ReadLong ( ) ;
2012-11-28 15:47:07 +00:00
if ( gameLocal . entities [ victimNum ] = = NULL )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( gameLocal . entities [ attackerNum ] = = NULL )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
idPlayer & victim = static_cast < idPlayer & > ( * gameLocal . entities [ victimNum ] ) ;
idPlayer & attacker = static_cast < idPlayer & > ( * gameLocal . entities [ attackerNum ] ) ;
if ( victim . GetPhysics ( ) = = NULL )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( attacker . weapon . GetEntity ( ) = = NULL )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
if ( location = = INVALID_JOINT )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Line of sight check. As a basic precaution against cheating,
// the server performs a ray intersection from the client's position
// to the joint he hit on the target.
idVec3 muzzleOrigin ;
idMat3 muzzleAxis ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
attacker . weapon . GetEntity ( ) - > GetProjectileLaunchOriginAndAxis ( muzzleOrigin , muzzleAxis ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 targetLocation = victim . GetRenderEntity ( ) - > origin + victim . GetRenderEntity ( ) - > joints [ location ] . ToVec3 ( ) * victim . GetRenderEntity ( ) - > axis ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
trace_t tr ;
gameLocal . clip . Translation ( tr , muzzleOrigin , targetLocation , NULL , mat3_identity , MASK_SHOT_RENDERMODEL , & attacker ) ;
2012-11-28 15:47:07 +00:00
idEntity * hitEnt = gameLocal . entities [ tr . c . entityNum ] ;
if ( hitEnt ! = & victim )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
const idDeclEntityDef * damageDef = static_cast < const idDeclEntityDef * > ( declManager - > DeclByIndex ( DECL_ENTITYDEF , damageDefIndex , false ) ) ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( damageDef ! = NULL )
{
2012-11-26 18:58:24 +00:00
victim . Damage ( NULL , gameLocal . entities [ attackerNum ] , dir , damageDef - > GetName ( ) , damageScale , location ) ;
}
break ;
}
2012-11-28 15:47:07 +00:00
default :
{
2012-11-26 18:58:24 +00:00
Warning ( " Unknown reliable message (%d) from client %d " , type , clientNum ) ;
break ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ClientReadSnapshot
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ClientReadSnapshot ( const idSnapShot & ss )
{
if ( GetLocalClientNum ( ) < 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if prediction is off, enable local client smoothing
//localPlayer->SetSelfSmooth( dupeUsercmds > 2 );
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear any debug lines from a previous frame
gameRenderWorld - > DebugClearLines ( time ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear any debug polygons from a previous frame
gameRenderWorld - > DebugClearPolygons ( time ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SelectTimeGroup ( false ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// so that StartSound/StopSound doesn't risk skipping
isNewFrame = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear the snapshot entity list
snapshotEntities . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// read all entities from the snapshot
2012-11-28 15:47:07 +00:00
for ( int o = 0 ; o < ss . NumObjects ( ) ; o + + )
{
2012-11-26 18:58:24 +00:00
idBitMsg msg ;
int snapObjectNum = ss . GetObjectMsgByIndex ( o , msg ) ;
2012-11-28 15:47:07 +00:00
if ( snapObjectNum < 0 )
{
2012-11-26 18:58:24 +00:00
assert ( false ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( snapObjectNum = = SNAP_GAMESTATE )
{
2012-11-26 18:58:24 +00:00
mpGame . ReadFromSnapshot ( msg ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( snapObjectNum = = SNAP_SHADERPARMS )
{
for ( int i = 0 ; i < MAX_GLOBAL_SHADER_PARMS ; i + + )
{
2012-11-26 18:58:24 +00:00
globalShaderParms [ i ] = msg . ReadFloat ( ) ;
}
continue ;
}
2012-11-28 15:47:07 +00:00
if ( snapObjectNum = = SNAP_PORTALS )
{
2012-11-26 18:58:24 +00:00
// update portals for opened doors
int numPortals = msg . ReadLong ( ) ;
assert ( numPortals = = gameRenderWorld - > NumPortals ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numPortals ; i + + )
{
gameRenderWorld - > SetPortalState ( ( qhandle_t ) ( i + 1 ) , msg . ReadBits ( NUM_RENDER_PORTAL_BITS ) ) ;
2012-11-26 18:58:24 +00:00
}
continue ;
}
2012-11-28 15:47:07 +00:00
if ( snapObjectNum > = SNAP_PLAYERSTATE & & snapObjectNum < SNAP_PLAYERSTATE_END )
{
2012-11-26 18:58:24 +00:00
int playerNumber = snapObjectNum - SNAP_PLAYERSTATE ;
2012-11-28 15:47:07 +00:00
idPlayer * otherPlayer = static_cast < idPlayer * > ( entities [ playerNumber ] ) ;
2012-11-26 18:58:24 +00:00
// Don't process Player Snapshots that are disconnected.
const int lobbyIndex = session - > GetActingGameStateLobbyBase ( ) . GetLobbyUserIndexFromLobbyUserID ( lobbyUserIDs [ playerNumber ] ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyIndex < 0 | | session - > GetActingGameStateLobbyBase ( ) . IsLobbyUserConnected ( lobbyIndex ) = = false )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( otherPlayer ! = NULL )
{
2012-11-26 18:58:24 +00:00
otherPlayer - > ReadPlayerStateFromSnapshot ( msg ) ;
2012-11-28 15:47:07 +00:00
if ( otherPlayer ! = entities [ GetLocalClientNum ( ) ] ) // This happens when we spectate another player
{
idWeapon * weap = otherPlayer - > weapon . GetEntity ( ) ;
if ( weap & & ( weap - > GetRenderEntity ( ) - > bounds [ 0 ] = = weap - > GetRenderEntity ( ) - > bounds [ 1 ] ) )
{
2012-11-26 18:58:24 +00:00
// update the weapon's viewmodel bounds so that the model doesn't flicker in the spectator's view
weap - > GetAnimator ( ) - > GetBounds ( gameLocal . time , weap - > GetRenderEntity ( ) - > bounds ) ;
weap - > UpdateVisuals ( ) ;
}
}
}
continue ;
}
2012-11-28 15:47:07 +00:00
if ( snapObjectNum > = SNAP_LAST_CLIENT_FRAME & & snapObjectNum < SNAP_LAST_CLIENT_FRAME_END )
{
2012-11-26 18:58:24 +00:00
int playerNumber = snapObjectNum - SNAP_LAST_CLIENT_FRAME ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Don't process Player Snapshots that are disconnected.
const int lobbyIndex = session - > GetActingGameStateLobbyBase ( ) . GetLobbyUserIndexFromLobbyUserID ( lobbyUserIDs [ playerNumber ] ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyIndex < 0 | | session - > GetActingGameStateLobbyBase ( ) . IsLobbyUserConnected ( lobbyIndex ) = = false )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
usercmdLastClientMilliseconds [ playerNumber ] = msg . ReadLong ( ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( snapObjectNum < SNAP_ENTITIES | | snapObjectNum > = SNAP_ENTITIES_END )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int entityNumber = snapObjectNum - SNAP_ENTITIES ;
2012-11-28 15:47:07 +00:00
if ( msg . GetSize ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
delete entities [ entityNumber ] ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool debug = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int spawnId = msg . ReadBits ( 32 - GENTITYNUM_BITS ) ;
int typeNum = msg . ReadBits ( idClass : : GetTypeNumBits ( ) ) ;
int entityDefNumber = ClientRemapDecl ( DECL_ENTITYDEF , msg . ReadBits ( entityDefBits ) ) ;
const int predictedKey = msg . ReadBits ( 32 ) ;
2012-11-28 15:47:07 +00:00
idTypeInfo * typeInfo = idClass : : GetType ( typeNum ) ;
if ( ! typeInfo )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " Unknown type number %d for entity %d with class number %d " , typeNum , entityNumber , entityDefNumber ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If there is no entity on this client, but the server's entity matches a predictionKey, move the client's
// predicted entity to the normal, replicated area in the entity list.
2012-11-28 15:47:07 +00:00
if ( entities [ entityNumber ] = = NULL )
{
if ( predictedKey ! = idEntity : : INVALID_PREDICTION_KEY )
{
2012-11-26 18:58:24 +00:00
idLib : : PrintfIf ( debug , " Looking for predicted key %d. \n " , predictedKey ) ;
2012-11-28 15:47:07 +00:00
idEntity * predictedEntity = FindPredictedEntity ( predictedKey , typeInfo ) ;
if ( predictedEntity ! = NULL )
{
2012-11-26 18:58:24 +00:00
// This presentable better be in the proper place in the list or bad things will happen if we move this presentable around
assert ( predictedEntity - > GetEntityNumber ( ) > = ENTITYNUM_FIRST_NON_REPLICATED ) ;
continue ;
#if 0
2012-11-28 15:47:07 +00:00
idProjectile * predictedProjectile = idProjectile : : CastTo ( predictedEntity ) ;
if ( predictedProjectile ! = NULL )
{
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
{
if ( entities [ i ] = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
idPlayer * player = idPlayer : : CastTo ( entities [ i ] ) ;
if ( player ! = NULL )
{
if ( player - > GetUniqueProjectile ( ) = = predictedProjectile )
{
2012-11-26 18:58:24 +00:00
// Set new spawn id
player - > TrackUniqueProjectile ( predictedProjectile ) ;
}
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : PrintfIf ( debug , " Found predicted EntNum old:%i new:%i spawnID:%i \n " , predictedEntity - > GetEntityNumber ( ) , entityNumber , spawnId > > GENTITYNUM_BITS ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// move the entity
RemoveEntityFromHash ( predictedEntity - > name . c_str ( ) , predictedEntity ) ;
UnregisterEntity ( predictedEntity ) ;
assert ( entities [ predictedEntity - > GetEntityNumber ( ) ] = = NULL ) ;
predictedEntity - > spawnArgs . SetInt ( " spawn_entnum " , entityNumber ) ;
RegisterEntity ( predictedEntity , spawnId , predictedEntity - > spawnArgs ) ;
predictedEntity - > SetName ( " " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// now mark us as no longer predicted
predictedEntity - > BecomeReplicated ( ) ;
# endif
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
//TODO make this work with non-client preditced entities
/* else {
idLib : : Warning ( " Could not find predicted entity - key: %d. EntityIndex: %d " , predictedKey , entityNum ) ;
} */
}
}
2012-11-28 15:47:07 +00:00
idEntity * ent = entities [ entityNumber ] ;
2012-11-26 18:58:24 +00:00
// if there is no entity or an entity of the wrong type
2012-11-28 15:47:07 +00:00
if ( ! ent | | ent - > GetType ( ) - > typeNum ! = typeNum | | ent - > entityDefNumber ! = entityDefNumber | | spawnId ! = spawnIds [ entityNumber ] )
{
2012-11-26 18:58:24 +00:00
delete ent ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
spawnCount = spawnId ;
2012-11-28 15:47:07 +00:00
if ( entityNumber < MAX_CLIENTS )
{
2012-11-26 18:58:24 +00:00
commonLocal . GetUCmdMgr ( ) . ResetPlayer ( entityNumber ) ;
SpawnPlayer ( entityNumber ) ;
ent = entities [ entityNumber ] ;
ent - > FreeModelDef ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
idDict args ;
args . SetInt ( " spawn_entnum " , entityNumber ) ;
args . Set ( " name " , va ( " entity%d " , entityNumber ) ) ;
2012-11-28 15:47:07 +00:00
if ( entityDefNumber > = 0 )
{
if ( entityDefNumber > = declManager - > GetNumDecls ( DECL_ENTITYDEF ) )
{
2012-11-26 18:58:24 +00:00
Error ( " server has %d entityDefs instead of %d " , entityDefNumber , declManager - > GetNumDecls ( DECL_ENTITYDEF ) ) ;
}
2012-11-28 15:47:07 +00:00
const char * classname = declManager - > DeclByIndex ( DECL_ENTITYDEF , entityDefNumber , false ) - > GetName ( ) ;
2012-11-26 18:58:24 +00:00
args . Set ( " classname " , classname ) ;
2012-11-28 15:47:07 +00:00
if ( ! SpawnEntityDef ( args , & ent ) | | ! entities [ entityNumber ] | | entities [ entityNumber ] - > GetType ( ) - > typeNum ! = typeNum )
{
2012-11-26 18:58:24 +00:00
Error ( " Failed to spawn entity with classname '%s' of type '%s' " , classname , typeInfo - > classname ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
ent = SpawnEntityType ( * typeInfo , & args , true ) ;
2012-11-28 15:47:07 +00:00
if ( ! entities [ entityNumber ] | | entities [ entityNumber ] - > GetType ( ) - > typeNum ! = typeNum )
{
2012-11-26 18:58:24 +00:00
Error ( " Failed to spawn entity of type '%s' " , typeInfo - > classname ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( ent ! = NULL )
{
2012-11-26 18:58:24 +00:00
// Fixme: for now, force all think flags on. We'll need to figure out how we want dormancy to work on clients
// (but for now since clientThink is so light weight, this is ok)
ent - > BecomeActive ( TH_ANIMATE ) ;
ent - > BecomeActive ( TH_THINK ) ;
ent - > BecomeActive ( TH_PHYSICS ) ;
}
2012-11-28 15:47:07 +00:00
if ( entityNumber < MAX_CLIENTS & & entityNumber > = numClients )
{
2012-11-26 18:58:24 +00:00
numClients = entityNumber + 1 ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( ss . ObjectIsStaleByIndex ( o ) )
{
if ( ent - > entityNumber > = MAX_CLIENTS & & ent - > entityNumber < mapSpawnCount & & ! ent - > spawnArgs . GetBool ( " net_dynamic " , " 0 " ) ) //_D3XP
{
2012-11-26 18:58:24 +00:00
// server says it's not in PVS
// if that happens on map entities, most likely something is wrong
// I can see that moving pieces along several PVS could be a legit situation though
// this is a band aid, which means something is not done right elsewhere
common - > DWarning ( " map entity 0x%x (%s) is stale " , ent - > entityNumber , ent - > name . c_str ( ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
ent - > snapshotStale = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ent - > FreeModelDef ( ) ;
// possible fix for left over lights on CTF flag
ent - > FreeLightDef ( ) ;
ent - > UpdateVisuals ( ) ;
ent - > GetPhysics ( ) - > UnlinkClip ( ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// add the entity to the snapshot list
ent - > snapshotNode . AddToEnd ( snapshotEntities ) ;
int snapshotChanged = ss . ObjectChangedCountByIndex ( o ) ;
msg . SetHasChanged ( ent - > snapshotChanged ! = snapshotChanged ) ;
ent - > snapshotChanged = snapshotChanged ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ent - > FlagNewSnapshot ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// read the class specific data from the snapshot
2012-11-28 15:47:07 +00:00
if ( msg . GetRemainingReadBits ( ) > 0 )
{
2012-11-26 18:58:24 +00:00
ent - > ReadFromSnapshot_Ex ( msg ) ;
ent - > snapshotBits = msg . GetSize ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Set after ReadFromSnapshot so we can detect coming unstale
ent - > snapshotStale = false ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// process entity events
ClientProcessEntityNetworkEventQueue ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ClientProcessEntityNetworkEventQueue
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ClientProcessEntityNetworkEventQueue ( )
{
while ( eventQueue . Start ( ) )
{
entityNetEvent_t * event = eventQueue . Start ( ) ;
2012-11-26 18:58:24 +00:00
// only process forward, in order
2012-11-28 15:47:07 +00:00
if ( event - > time > this - > serverTime )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idEntityPtr < idEntity > entPtr ;
2012-11-28 15:47:07 +00:00
if ( ! entPtr . SetSpawnId ( event - > spawnId ) )
{
if ( ! gameLocal . entities [ event - > spawnId & ( ( 1 < < GENTITYNUM_BITS ) - 1 ) ] )
{
2012-11-26 18:58:24 +00:00
// if new entity exists in this position, silently ignore
NetworkEventWarning ( event , " Entity does not exist any longer, or has not been spawned yet. " ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
idEntity * ent = entPtr . GetEntity ( ) ;
2012-11-26 18:58:24 +00:00
assert ( ent ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idBitMsg eventMsg ;
eventMsg . InitRead ( event - > paramsBuf , sizeof ( event - > paramsBuf ) ) ;
eventMsg . SetSize ( event - > paramsSize ) ;
eventMsg . BeginReading ( ) ;
2012-11-28 15:47:07 +00:00
if ( ! ent - > ClientReceiveEvent ( event - > event , event - > time , eventMsg ) )
{
2012-11-26 18:58:24 +00:00
NetworkEventWarning ( event , " unknown event " ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
verify ( eventQueue . Dequeue ( ) = = event ) ;
eventQueue . Free ( event ) ;
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ClientProcessReliableMessage
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ClientProcessReliableMessage ( int type , const idBitMsg & msg )
{
switch ( type )
{
case GAME_RELIABLE_MESSAGE_SYNCEDCVARS :
{
2012-11-26 18:58:24 +00:00
idDict syncedCvars ;
msg . ReadDeltaDict ( syncedCvars , NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Got networkSync cvars: \n " ) ;
syncedCvars . Print ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cvarSystem - > ResetFlaggedVariables ( CVAR_NETWORKSYNC ) ;
cvarSystem - > SetCVarsFromDict ( syncedCvars ) ;
break ;
}
case GAME_RELIABLE_MESSAGE_CHAT :
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_TCHAT : // (client should never get a TCHAT though)
{
2012-11-26 18:58:24 +00:00
char name [ 128 ] ;
char text [ 128 ] ;
msg . ReadString ( name , sizeof ( name ) ) ;
msg . ReadString ( text , sizeof ( text ) ) ;
mpGame . AddChatLine ( " %s^0: %s \n " , name , text ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_SOUND_EVENT :
{
snd_evt_t snd_evt = ( snd_evt_t ) msg . ReadByte ( ) ;
2012-11-26 18:58:24 +00:00
mpGame . PlayGlobalSound ( - 1 , snd_evt ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_SOUND_INDEX :
{
2012-11-26 18:58:24 +00:00
int index = gameLocal . ClientRemapDecl ( DECL_SOUND , msg . ReadLong ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( index > = 0 & & index < declManager - > GetNumDecls ( DECL_SOUND ) )
{
const idSoundShader * shader = declManager - > SoundByIndex ( index ) ;
2012-11-26 18:58:24 +00:00
mpGame . PlayGlobalSound ( - 1 , SND_COUNT , shader - > GetName ( ) ) ;
}
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_DB :
{
idMultiplayerGame : : msg_evt_t msg_evt = ( idMultiplayerGame : : msg_evt_t ) msg . ReadByte ( ) ;
2012-11-26 18:58:24 +00:00
int parm1 , parm2 ;
parm1 = msg . ReadByte ( ) ;
parm2 = msg . ReadByte ( ) ;
mpGame . PrintMessageEvent ( msg_evt , parm1 , parm2 ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_EVENT :
{
2012-11-26 18:58:24 +00:00
// allocate new event
2012-11-28 15:47:07 +00:00
entityNetEvent_t * event = eventQueue . Alloc ( ) ;
2012-11-26 18:58:24 +00:00
eventQueue . Enqueue ( event , idEventQueue : : OUTOFORDER_IGNORE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
event - > spawnId = msg . ReadBits ( 32 ) ;
event - > event = msg . ReadByte ( ) ;
event - > time = msg . ReadLong ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
event - > paramsSize = msg . ReadBits ( idMath : : BitsForInteger ( MAX_EVENT_PARAM_SIZE ) ) ;
2012-11-28 15:47:07 +00:00
if ( event - > paramsSize )
{
if ( event - > paramsSize > MAX_EVENT_PARAM_SIZE )
{
2012-11-26 18:58:24 +00:00
NetworkEventWarning ( event , " invalid param size " ) ;
return ;
}
msg . ReadByteAlign ( ) ;
msg . ReadData ( event - > paramsBuf , event - > paramsSize ) ;
}
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_RESTART :
{
2012-11-26 18:58:24 +00:00
MapRestart ( ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_TOURNEYLINE :
{
2012-11-26 18:58:24 +00:00
int line = msg . ReadByte ( ) ;
2012-11-28 15:47:07 +00:00
idPlayer * p = static_cast < idPlayer * > ( entities [ GetLocalClientNum ( ) ] ) ;
if ( ! p )
{
2012-11-26 18:58:24 +00:00
break ;
}
p - > tourneyLine = line ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_STARTSTATE :
{
2012-11-26 18:58:24 +00:00
mpGame . ClientReadStartState ( msg ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_WARMUPTIME :
{
2012-11-26 18:58:24 +00:00
mpGame . ClientReadWarmupTime ( msg ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_LOBBY_COUNTDOWN :
{
2012-11-26 18:58:24 +00:00
int timeRemaining = msg . ReadLong ( ) ;
Shell_UpdateClientCountdown ( timeRemaining ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_RESPAWN_AVAILABLE :
{
idPlayer * p = static_cast < idPlayer * > ( entities [ GetLocalClientNum ( ) ] ) ;
if ( p )
{
2012-11-26 18:58:24 +00:00
p - > ShowRespawnHudMessage ( ) ;
}
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_MATCH_STARTED_TIME :
{
2012-11-26 18:58:24 +00:00
mpGame . ClientReadMatchStartedTime ( msg ) ;
break ;
}
2012-11-28 15:47:07 +00:00
case GAME_RELIABLE_MESSAGE_ACHIEVEMENT_UNLOCK :
{
2012-11-26 18:58:24 +00:00
mpGame . ClientReadAchievementUnlock ( msg ) ;
break ;
}
2012-11-28 15:47:07 +00:00
default :
{
2012-11-26 18:58:24 +00:00
Error ( " Unknown reliable message (%d) from host " , type ) ;
break ;
}
}
}
/*
= = = = = = = = = = = = = = = =
idGameLocal : : ClientRunFrame
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : ClientRunFrame ( idUserCmdMgr & cmdMgr , bool lastPredictFrame , gameReturn_t & ret )
{
idEntity * ent ;
2012-11-26 18:58:24 +00:00
// update the game time
previousTime = FRAME_TO_MSEC ( framenum ) ;
framenum + + ;
time = FRAME_TO_MSEC ( framenum ) ;
2012-11-28 15:47:07 +00:00
idPlayer * player = static_cast < idPlayer * > ( entities [ GetLocalClientNum ( ) ] ) ;
if ( ! player )
{
2012-11-26 18:58:24 +00:00
// service any pending events
idEvent : : ServiceEvents ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for local client lag
2012-11-28 15:47:07 +00:00
idLobbyBase & lobby = session - > GetActingGameStateLobbyBase ( ) ;
if ( lobby . GetPeerTimeSinceLastPacket ( lobby . PeerIndexForHost ( ) ) > = net_clientMaxPrediction . GetInteger ( ) )
{
2012-11-26 18:58:24 +00:00
player - > isLagged = true ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
player - > isLagged = false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// update the real client time and the new frame flag
2012-11-28 15:47:07 +00:00
if ( time > realClientTime )
{
2012-11-26 18:58:24 +00:00
realClientTime = time ;
isNewFrame = true ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
isNewFrame = false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
slow . Set ( time , previousTime , realClientTime ) ;
fast . Set ( time , previousTime , realClientTime ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// run prediction on all active entities
2012-11-28 15:47:07 +00:00
for ( ent = activeEntities . Next ( ) ; ent ! = NULL ; ent = ent - > activeNode . Next ( ) )
{
2012-11-26 18:58:24 +00:00
ent - > thinkFlags | = TH_PHYSICS ;
2012-11-28 15:47:07 +00:00
if ( ent - > entityNumber ! = GetLocalClientNum ( ) )
{
2012-11-26 18:58:24 +00:00
ent - > ClientThink ( netInterpolationInfo . serverGameMs , netInterpolationInfo . pct , true ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
RunAllUserCmdsForPlayer ( cmdMgr , ent - > entityNumber ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// service any pending events
idEvent : : ServiceEvents ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// show any debug info for this frame
2012-11-28 15:47:07 +00:00
if ( isNewFrame )
{
2012-11-26 18:58:24 +00:00
RunDebugInfo ( ) ;
D_DrawDebugLines ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
BuildReturnValue ( ret ) ;
}
/*
= = = = = = = = = = = = = = =
idGameLocal : : Tokenize
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idGameLocal : : Tokenize ( idStrList & out , const char * in )
{
2012-11-26 18:58:24 +00:00
char buf [ MAX_STRING_CHARS ] ;
2012-11-28 15:47:07 +00:00
char * token , * next ;
2012-11-26 18:58:24 +00:00
idStr : : Copynz ( buf , in , MAX_STRING_CHARS ) ;
token = buf ;
next = strchr ( token , ' ; ' ) ;
2012-11-28 15:47:07 +00:00
while ( token )
{
if ( next )
{
2012-11-26 18:58:24 +00:00
* next = ' \0 ' ;
}
idStr : : ToLower ( token ) ;
out . Append ( token ) ;
2012-11-28 15:47:07 +00:00
if ( next )
{
2012-11-26 18:58:24 +00:00
token = next + 1 ;
next = strchr ( token , ' ; ' ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
token = NULL ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idGameLocal : : FindPredictedEntity
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idEntity * idGameLocal : : FindPredictedEntity ( uint32 predictedKey , idTypeInfo * type )
{
for ( idEntity * predictedEntity = activeEntities . Next ( ) ; predictedEntity ! = NULL ; predictedEntity = predictedEntity - > activeNode . Next ( ) )
{
if ( ! verify ( predictedEntity ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! predictedEntity - > IsReplicated ( ) & & predictedEntity - > GetPredictedKey ( ) = = predictedKey )
{
if ( predictedEntity - > GetType ( ) ! = type )
{
idLib : : Warning ( " Mismatched presentable type. Predicted: %s Actual: %s " , predictedEntity - > GetType ( ) - > classname , type - > classname ) ;
2012-11-26 18:58:24 +00:00
}
return predictedEntity ;
}
}
return NULL ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idGameLocal : : GeneratePredictionKey
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
uint32 idGameLocal : : GeneratePredictionKey ( idWeapon * weapon , idPlayer * playerAttacker , int overrideKey )
{
if ( overrideKey ! = - 1 )
{
2012-11-26 18:58:24 +00:00
uint32 predictedKey = overrideKey ;
int peerIndex = - 1 ;
2012-11-28 15:47:07 +00:00
if ( common - > IsServer ( ) )
{
2012-11-26 18:58:24 +00:00
peerIndex = session - > GetActingGameStateLobbyBase ( ) . PeerIndexFromLobbyUser ( lobbyUserIDs [ playerAttacker - > entityNumber ] ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
peerIndex = session - > GetActingGameStateLobbyBase ( ) . PeerIndexOnHost ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
predictedKey | = ( peerIndex < < 28 ) ;
return predictedKey ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint32 predictedKey = idEntity : : INVALID_PREDICTION_KEY ;
int peerIndex = - 1 ;
// Get key - fireCount or throwCount
//if ( weapon != NULL ) {
2012-11-28 15:47:07 +00:00
if ( common - > IsClient ( ) )
{
2012-11-26 18:58:24 +00:00
predictedKey = playerAttacker - > GetClientFireCount ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
predictedKey = playerAttacker - > usercmd . fireCount ;
}
//} else {
// predictedKey = ( playerAttacker->GetThrowCount() );
//}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Get peer index
2012-11-28 15:47:07 +00:00
if ( common - > IsServer ( ) )
{
2012-11-26 18:58:24 +00:00
peerIndex = session - > GetActingGameStateLobbyBase ( ) . PeerIndexFromLobbyUser ( lobbyUserIDs [ playerAttacker - > entityNumber ] ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
peerIndex = session - > GetActingGameStateLobbyBase ( ) . PeerIndexOnHost ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( cg_predictedSpawn_debug . GetBool ( ) )
{
idLib : : Printf ( " GeneratePredictionKey. predictedKey: %d peedIndex: %d \n " , predictedKey , peerIndex ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
predictedKey | = ( peerIndex < < 28 ) ;
return predictedKey ;
}
/*
= = = = = = = = = = = = = = =
idEventQueue : : Alloc
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
entityNetEvent_t * idEventQueue : : Alloc ( )
{
2012-11-26 18:58:24 +00:00
entityNetEvent_t * event = eventAllocator . Alloc ( ) ;
event - > prev = NULL ;
event - > next = NULL ;
return event ;
}
/*
= = = = = = = = = = = = = = =
idEventQueue : : Free
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idEventQueue : : Free ( entityNetEvent_t * event )
{
2012-11-26 18:58:24 +00:00
// should only be called on an unlinked event!
assert ( ! event - > next & & ! event - > prev ) ;
eventAllocator . Free ( event ) ;
}
/*
= = = = = = = = = = = = = = =
idEventQueue : : Shutdown
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idEventQueue : : Shutdown ( )
{
2012-11-26 18:58:24 +00:00
eventAllocator . Shutdown ( ) ;
this - > Init ( ) ;
}
/*
= = = = = = = = = = = = = = =
idEventQueue : : Init
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idEventQueue : : Init ( )
{
2012-11-26 18:58:24 +00:00
start = NULL ;
end = NULL ;
}
/*
= = = = = = = = = = = = = = =
idEventQueue : : Dequeue
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
entityNetEvent_t * idEventQueue : : Dequeue ( )
{
2012-11-26 18:58:24 +00:00
entityNetEvent_t * event = start ;
2012-11-28 15:47:07 +00:00
if ( ! event )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
start = start - > next ;
2012-11-28 15:47:07 +00:00
if ( ! start )
{
2012-11-26 18:58:24 +00:00
end = NULL ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
start - > prev = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
event - > next = NULL ;
event - > prev = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return event ;
}
/*
= = = = = = = = = = = = = = =
idEventQueue : : RemoveLast
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
entityNetEvent_t * idEventQueue : : RemoveLast ( )
{
entityNetEvent_t * event = end ;
if ( ! event )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
end = event - > prev ;
2012-11-28 15:47:07 +00:00
if ( ! end )
{
2012-11-26 18:58:24 +00:00
start = NULL ;
}
2012-11-28 15:47:07 +00:00
else
{
end - > next = NULL ;
}
2012-11-26 18:58:24 +00:00
event - > next = NULL ;
event - > prev = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return event ;
}
/*
= = = = = = = = = = = = = = =
idEventQueue : : Enqueue
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idEventQueue : : Enqueue ( entityNetEvent_t * event , outOfOrderBehaviour_t behaviour )
{
if ( behaviour = = OUTOFORDER_DROP )
{
2012-11-26 18:58:24 +00:00
// go backwards through the queue and determine if there are
// any out-of-order events
2012-11-28 15:47:07 +00:00
while ( end & & end - > time > event - > time )
{
entityNetEvent_t * outOfOrder = RemoveLast ( ) ;
2012-11-26 18:58:24 +00:00
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 ) ;
Free ( outOfOrder ) ;
}
2012-11-28 15:47:07 +00:00
}
else if ( behaviour = = OUTOFORDER_SORT & & end )
{
2012-11-26 18:58:24 +00:00
// NOT TESTED -- sorting out of order packets hasn't been
// tested yet... wasn't strictly necessary for
// the patch fix.
2012-11-28 15:47:07 +00:00
entityNetEvent_t * cur = end ;
2012-11-26 18:58:24 +00:00
// iterate until we find a time < the new event's
2012-11-28 15:47:07 +00:00
while ( cur & & cur - > time > event - > time )
{
2012-11-26 18:58:24 +00:00
cur = cur - > prev ;
}
2012-11-28 15:47:07 +00:00
if ( ! cur )
{
2012-11-26 18:58:24 +00:00
// add to start
event - > next = start ;
event - > prev = NULL ;
start = event ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// insert
event - > prev = cur ;
event - > next = cur - > next ;
cur - > next = event ;
}
return ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
// add the new event
event - > next = NULL ;
event - > prev = NULL ;
2012-11-28 15:47:07 +00:00
if ( end )
{
2012-11-26 18:58:24 +00:00
end - > next = event ;
event - > prev = end ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
start = event ;
}
end = event ;
}