Replace non-ASCII characters in comments with ASCII equivalents

Em dashes (---) replaced with --, arrows replaced with ->.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
serge_shubin 2026-03-25 00:58:47 +08:00
parent 6e00a47416
commit 643c1d0294
7 changed files with 6643 additions and 6643 deletions

View file

@ -1,459 +1,459 @@
/* /*
=========================================================================== ===========================================================================
Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code. This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License, published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version. or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
// //
// cg_snapshot.c -- things that happen on snapshot transition, // cg_snapshot.c -- things that happen on snapshot transition,
// not necessarily every single rendered frame // not necessarily every single rendered frame
#include "cg_local.h" #include "cg_local.h"
/* /*
================== ==================
CG_ResetEntity CG_ResetEntity
================== ==================
*/ */
static void CG_ResetEntity( centity_t *cent ) { static void CG_ResetEntity( centity_t *cent ) {
// if the previous snapshot this entity was updated in is at least // if the previous snapshot this entity was updated in is at least
// an event window back in time then we can reset the previous event // an event window back in time then we can reset the previous event
if ( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) { if ( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) {
cent->previousEvent = 0; cent->previousEvent = 0;
} }
cent->trailTime = cg.snap->serverTime; cent->trailTime = cg.snap->serverTime;
VectorCopy (cent->currentState.origin, cent->lerpOrigin); VectorCopy (cent->currentState.origin, cent->lerpOrigin);
VectorCopy (cent->currentState.angles, cent->lerpAngles); VectorCopy (cent->currentState.angles, cent->lerpAngles);
if ( cent->currentState.eType == ET_PLAYER ) { if ( cent->currentState.eType == ET_PLAYER ) {
CG_ResetPlayerEntity( cent ); CG_ResetPlayerEntity( cent );
} }
} }
/* /*
=============== ===============
CG_TransitionEntity CG_TransitionEntity
cent->nextState is moved to cent->currentState and events are fired cent->nextState is moved to cent->currentState and events are fired
=============== ===============
*/ */
static void CG_TransitionEntity( centity_t *cent ) { static void CG_TransitionEntity( centity_t *cent ) {
cent->currentState = cent->nextState; cent->currentState = cent->nextState;
cent->currentValid = qtrue; cent->currentValid = qtrue;
// reset if the entity wasn't in the last frame or was teleported // reset if the entity wasn't in the last frame or was teleported
if ( !cent->interpolate ) { if ( !cent->interpolate ) {
CG_ResetEntity( cent ); CG_ResetEntity( cent );
} }
// clear the next state. if will be set by the next CG_SetNextSnap // clear the next state. if will be set by the next CG_SetNextSnap
cent->interpolate = qfalse; cent->interpolate = qfalse;
// check for events // check for events
CG_CheckEvents( cent ); CG_CheckEvents( cent );
} }
/* /*
================== ==================
CG_SetInitialSnapshot CG_SetInitialSnapshot
This will only happen on the very first snapshot, or This will only happen on the very first snapshot, or
on tourney restarts. All other times will use on tourney restarts. All other times will use
CG_TransitionSnapshot instead. CG_TransitionSnapshot instead.
FIXME: Also called by map_restart? FIXME: Also called by map_restart?
================== ==================
*/ */
void CG_SetInitialSnapshot( snapshot_t *snap ) { void CG_SetInitialSnapshot( snapshot_t *snap ) {
int i; int i;
centity_t *cent; centity_t *cent;
entityState_t *state; entityState_t *state;
cg.snap = snap; cg.snap = snap;
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
// sort out solid entities // sort out solid entities
CG_BuildSolidList(); CG_BuildSolidList();
CG_ExecuteNewServerCommands( snap->serverCommandSequence ); CG_ExecuteNewServerCommands( snap->serverCommandSequence );
// set our local weapon selection pointer to // set our local weapon selection pointer to
// what the server has indicated the current weapon is // what the server has indicated the current weapon is
CG_Respawn(); CG_Respawn();
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
state = &cg.snap->entities[ i ]; state = &cg.snap->entities[ i ];
cent = &cg_entities[ state->number ]; cent = &cg_entities[ state->number ];
memcpy(&cent->currentState, state, sizeof(entityState_t)); memcpy(&cent->currentState, state, sizeof(entityState_t));
//cent->currentState = *state; //cent->currentState = *state;
cent->interpolate = qfalse; cent->interpolate = qfalse;
cent->currentValid = qtrue; cent->currentValid = qtrue;
CG_ResetEntity( cent ); CG_ResetEntity( cent );
// check for events // check for events
CG_CheckEvents( cent ); CG_CheckEvents( cent );
} }
} }
/* /*
=================== ===================
CG_TransitionSnapshot CG_TransitionSnapshot
The transition point from snap to nextSnap has passed The transition point from snap to nextSnap has passed
=================== ===================
*/ */
static void CG_TransitionSnapshot( void ) { static void CG_TransitionSnapshot( void ) {
centity_t *cent; centity_t *cent;
snapshot_t *oldFrame; snapshot_t *oldFrame;
int i; int i;
if ( !cg.snap ) { if ( !cg.snap ) {
CG_Error( "CG_TransitionSnapshot: NULL cg.snap" ); CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
} }
if ( !cg.nextSnap ) { if ( !cg.nextSnap ) {
CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" ); CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
} }
// execute any server string commands before transitioning entities // execute any server string commands before transitioning entities
CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence ); CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
// if we had a map_restart, set everthing with initial // if we had a map_restart, set everthing with initial
if ( !cg.snap ) { if ( !cg.snap ) {
} }
// clear the currentValid flag for all entities in the existing snapshot // clear the currentValid flag for all entities in the existing snapshot
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
cent = &cg_entities[ cg.snap->entities[ i ].number ]; cent = &cg_entities[ cg.snap->entities[ i ].number ];
cent->currentValid = qfalse; cent->currentValid = qfalse;
} }
// move nextSnap to snap and do the transitions // move nextSnap to snap and do the transitions
oldFrame = cg.snap; oldFrame = cg.snap;
cg.snap = cg.nextSnap; cg.snap = cg.nextSnap;
BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse ); BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse; cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
cent = &cg_entities[ cg.snap->entities[ i ].number ]; cent = &cg_entities[ cg.snap->entities[ i ].number ];
CG_TransitionEntity( cent ); CG_TransitionEntity( cent );
// remember time of snapshot this entity was last updated in // remember time of snapshot this entity was last updated in
cent->snapShotTime = cg.snap->serverTime; cent->snapShotTime = cg.snap->serverTime;
} }
cg.nextSnap = NULL; cg.nextSnap = NULL;
// check for playerstate transition events // check for playerstate transition events
if ( oldFrame ) { if ( oldFrame ) {
playerState_t *ops, *ps; playerState_t *ops, *ps;
ops = &oldFrame->ps; ops = &oldFrame->ps;
ps = &cg.snap->ps; ps = &cg.snap->ps;
// teleporting checks are irrespective of prediction // teleporting checks are irrespective of prediction
if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) { if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
cg.thisFrameTeleport = qtrue; // will be cleared by prediction code cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
} }
// if we are not doing client side movement prediction for any // if we are not doing client side movement prediction for any
// reason, then the client events and view changes will be issued now // reason, then the client events and view changes will be issued now
if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW)
|| cg_nopredict.integer || cg_synchronousClients.integer ) { || cg_nopredict.integer || cg_synchronousClients.integer ) {
CG_TransitionPlayerState( ps, ops ); CG_TransitionPlayerState( ps, ops );
} }
// server demo: detect followfree camera transition // server demo: detect follow->free camera transition
if ( cg.svDemoPlayback ) { if ( cg.svDemoPlayback ) {
qboolean wasFollowing = ( ops->pm_flags & PMF_FOLLOW ) != 0; qboolean wasFollowing = ( ops->pm_flags & PMF_FOLLOW ) != 0;
qboolean isFollowing = ( ps->pm_flags & PMF_FOLLOW ) != 0; qboolean isFollowing = ( ps->pm_flags & PMF_FOLLOW ) != 0;
if ( wasFollowing && !isFollowing ) { if ( wasFollowing && !isFollowing ) {
// exiting follow mode init camera from last known position // exiting follow mode -- init camera from last known position
cg.svDemoFreeCamera = qtrue; cg.svDemoFreeCamera = qtrue;
cg.svDemoCameraTime = trap_Milliseconds(); cg.svDemoCameraTime = trap_Milliseconds();
VectorCopy( ops->origin, cg.svDemoCameraPs.origin ); VectorCopy( ops->origin, cg.svDemoCameraPs.origin );
VectorCopy( ops->viewangles, cg.svDemoCameraPs.viewangles ); VectorCopy( ops->viewangles, cg.svDemoCameraPs.viewangles );
cg.svDemoCameraPs.pm_type = PM_SPECTATOR; cg.svDemoCameraPs.pm_type = PM_SPECTATOR;
cg.svDemoCameraPs.speed = 480; cg.svDemoCameraPs.speed = 480;
cg.svDemoCameraPs.clientNum = cg.clientNum; cg.svDemoCameraPs.clientNum = cg.clientNum;
} }
} }
} }
} }
/* /*
=================== ===================
CG_SetNextSnap CG_SetNextSnap
A new snapshot has just been read in from the client system. A new snapshot has just been read in from the client system.
=================== ===================
*/ */
static void CG_SetNextSnap( snapshot_t *snap ) { static void CG_SetNextSnap( snapshot_t *snap ) {
int num; int num;
entityState_t *es; entityState_t *es;
centity_t *cent; centity_t *cent;
cg.nextSnap = snap; cg.nextSnap = snap;
// SNAPFLAG_RESET_ENTITIES: invalidate all entities so they are // SNAPFLAG_RESET_ENTITIES: invalidate all entities so they are
// treated as new (no interpolation from old positions). // treated as new (no interpolation from old positions).
// Must happen before the entity loop below. // Must happen before the entity loop below.
if ( snap->snapFlags & SNAPFLAG_RESET_ENTITIES ) { if ( snap->snapFlags & SNAPFLAG_RESET_ENTITIES ) {
for ( num = 0 ; num < MAX_GENTITIES ; num++ ) { for ( num = 0 ; num < MAX_GENTITIES ; num++ ) {
cg_entities[ num ].currentValid = qfalse; cg_entities[ num ].currentValid = qfalse;
} }
} }
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse ); BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue; cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
// check for extrapolation errors // check for extrapolation errors
for ( num = 0 ; num < snap->numEntities ; num++ ) { for ( num = 0 ; num < snap->numEntities ; num++ ) {
es = &snap->entities[num]; es = &snap->entities[num];
cent = &cg_entities[ es->number ]; cent = &cg_entities[ es->number ];
memcpy(&cent->nextState, es, sizeof(entityState_t)); memcpy(&cent->nextState, es, sizeof(entityState_t));
//cent->nextState = *es; //cent->nextState = *es;
// if this frame is a teleport, or the entity wasn't in the // if this frame is a teleport, or the entity wasn't in the
// previous frame, don't interpolate // previous frame, don't interpolate
if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) { if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) {
cent->interpolate = qfalse; cent->interpolate = qfalse;
} else { } else {
cent->interpolate = qtrue; cent->interpolate = qtrue;
} }
} }
// if the next frame is a teleport for the playerstate, we // if the next frame is a teleport for the playerstate, we
// can't interpolate during demos // can't interpolate during demos
if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) { if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
cg.nextFrameTeleport = qtrue; cg.nextFrameTeleport = qtrue;
} else { } else {
cg.nextFrameTeleport = qfalse; cg.nextFrameTeleport = qfalse;
} }
// if changing follow mode, don't interpolate // if changing follow mode, don't interpolate
if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) { if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {
cg.nextFrameTeleport = qtrue; cg.nextFrameTeleport = qtrue;
} }
// if changing server restarts, don't interpolate // if changing server restarts, don't interpolate
if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) { if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
cg.nextFrameTeleport = qtrue; cg.nextFrameTeleport = qtrue;
} }
// entity reset also prevents playerstate interpolation // entity reset also prevents playerstate interpolation
if ( cg.nextSnap->snapFlags & SNAPFLAG_RESET_ENTITIES ) { if ( cg.nextSnap->snapFlags & SNAPFLAG_RESET_ENTITIES ) {
cg.nextFrameTeleport = qtrue; cg.nextFrameTeleport = qtrue;
} }
// sort out solid entities // sort out solid entities
CG_BuildSolidList(); CG_BuildSolidList();
} }
/* /*
======================== ========================
CG_ReadNextSnapshot CG_ReadNextSnapshot
This is the only place new snapshots are requested This is the only place new snapshots are requested
This may increment cgs.processedSnapshotNum multiple This may increment cgs.processedSnapshotNum multiple
times if the client system fails to return a times if the client system fails to return a
valid snapshot. valid snapshot.
======================== ========================
*/ */
static snapshot_t *CG_ReadNextSnapshot( void ) { static snapshot_t *CG_ReadNextSnapshot( void ) {
qboolean r; qboolean r;
snapshot_t *dest; snapshot_t *dest;
if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) { if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {
CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i", CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
cg.latestSnapshotNum, cgs.processedSnapshotNum ); cg.latestSnapshotNum, cgs.processedSnapshotNum );
} }
while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) { while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {
// decide which of the two slots to load it into // decide which of the two slots to load it into
if ( cg.snap == &cg.activeSnapshots[0] ) { if ( cg.snap == &cg.activeSnapshots[0] ) {
dest = &cg.activeSnapshots[1]; dest = &cg.activeSnapshots[1];
} else { } else {
dest = &cg.activeSnapshots[0]; dest = &cg.activeSnapshots[0];
} }
// try to read the snapshot from the client system // try to read the snapshot from the client system
cgs.processedSnapshotNum++; cgs.processedSnapshotNum++;
r = trap_GetSnapshot( cgs.processedSnapshotNum, dest ); r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
// FIXME: why would trap_GetSnapshot return a snapshot with the same server time // FIXME: why would trap_GetSnapshot return a snapshot with the same server time
if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) { if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {
//continue; //continue;
} }
// if it succeeded, return // if it succeeded, return
if ( r ) { if ( r ) {
CG_AddLagometerSnapshotInfo( dest ); CG_AddLagometerSnapshotInfo( dest );
return dest; return dest;
} }
// a GetSnapshot will return failure if the snapshot // a GetSnapshot will return failure if the snapshot
// never arrived, or is so old that its entities // never arrived, or is so old that its entities
// have been shoved off the end of the circular // have been shoved off the end of the circular
// buffer in the client system. // buffer in the client system.
// record as a dropped packet // record as a dropped packet
CG_AddLagometerSnapshotInfo( NULL ); CG_AddLagometerSnapshotInfo( NULL );
// If there are additional snapshots, continue trying to // If there are additional snapshots, continue trying to
// read them. // read them.
} }
// nothing left to read // nothing left to read
return NULL; return NULL;
} }
/* /*
============ ============
CG_ProcessSnapshots CG_ProcessSnapshots
We are trying to set up a renderable view, so determine We are trying to set up a renderable view, so determine
what the simulated time is, and try to get snapshots what the simulated time is, and try to get snapshots
both before and after that time if available. both before and after that time if available.
If we don't have a valid cg.snap after exiting this function, If we don't have a valid cg.snap after exiting this function,
then a 3D game view cannot be rendered. This should only happen then a 3D game view cannot be rendered. This should only happen
right after the initial connection. After cg.snap has been valid right after the initial connection. After cg.snap has been valid
once, it will never turn invalid. once, it will never turn invalid.
Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
hasn't arrived yet (it becomes an extrapolating situation instead hasn't arrived yet (it becomes an extrapolating situation instead
of an interpolating one) of an interpolating one)
============ ============
*/ */
void CG_ProcessSnapshots( void ) { void CG_ProcessSnapshots( void ) {
snapshot_t *snap; snapshot_t *snap;
int n; int n;
// see what the latest snapshot the client system has is // see what the latest snapshot the client system has is
trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime ); trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
if ( n != cg.latestSnapshotNum ) { if ( n != cg.latestSnapshotNum ) {
if ( n < cg.latestSnapshotNum ) { if ( n < cg.latestSnapshotNum ) {
// this should never happen // this should never happen
CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" ); CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
} }
cg.latestSnapshotNum = n; cg.latestSnapshotNum = n;
} }
// If we have yet to receive a snapshot, check for it. // If we have yet to receive a snapshot, check for it.
// Once we have gotten the first snapshot, cg.snap will // Once we have gotten the first snapshot, cg.snap will
// always have valid data for the rest of the game // always have valid data for the rest of the game
while ( !cg.snap ) { while ( !cg.snap ) {
snap = CG_ReadNextSnapshot(); snap = CG_ReadNextSnapshot();
if ( !snap ) { if ( !snap ) {
// we can't continue until we get a snapshot // we can't continue until we get a snapshot
return; return;
} }
// set our weapon selection to what // set our weapon selection to what
// the playerstate is currently using // the playerstate is currently using
if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
CG_SetInitialSnapshot( snap ); CG_SetInitialSnapshot( snap );
} }
} }
// loop until we either have a valid nextSnap with a serverTime // loop until we either have a valid nextSnap with a serverTime
// greater than cg.time to interpolate towards, or we run // greater than cg.time to interpolate towards, or we run
// out of available snapshots // out of available snapshots
do { do {
// if we don't have a nextframe, try and read a new one in // if we don't have a nextframe, try and read a new one in
if ( !cg.nextSnap ) { if ( !cg.nextSnap ) {
snap = CG_ReadNextSnapshot(); snap = CG_ReadNextSnapshot();
// if we still don't have a nextframe, we will just have to // if we still don't have a nextframe, we will just have to
// extrapolate // extrapolate
if ( !snap ) { if ( !snap ) {
break; break;
} }
CG_SetNextSnap( snap ); CG_SetNextSnap( snap );
// if time went backwards, we have a level restart or demo seek // if time went backwards, we have a level restart or demo seek
if ( cg.nextSnap->serverTime < cg.snap->serverTime ) { if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
if ( cg.svDemoPlayback ) { if ( cg.svDemoPlayback ) {
// demo seek discard old snap, use nextSnap as current, // demo seek -- discard old snap, use nextSnap as current,
// and wait for another snapshot before rendering // and wait for another snapshot before rendering
cg.snap = cg.nextSnap; cg.snap = cg.nextSnap;
cg.nextSnap = NULL; cg.nextSnap = NULL;
cg.time = cg.snap->serverTime; cg.time = cg.snap->serverTime;
// reset all entity state and time-dependent fields // reset all entity state and time-dependent fields
{ {
int e; int e;
for ( e = 0; e < MAX_GENTITIES; e++ ) { for ( e = 0; e < MAX_GENTITIES; e++ ) {
cg_entities[e].currentValid = qfalse; cg_entities[e].currentValid = qfalse;
cg_entities[e].interpolate = qfalse; cg_entities[e].interpolate = qfalse;
cg_entities[e].muzzleFlashTime = 0; cg_entities[e].muzzleFlashTime = 0;
cg_entities[e].trailTime = 0; cg_entities[e].trailTime = 0;
cg_entities[e].dustTrailTime = 0; cg_entities[e].dustTrailTime = 0;
cg_entities[e].miscTime = 0; cg_entities[e].miscTime = 0;
cg_entities[e].snapShotTime = 0; cg_entities[e].snapShotTime = 0;
cg_entities[e].previousEvent = 0; cg_entities[e].previousEvent = 0;
cg_entities[e].teleportFlag = 0; cg_entities[e].teleportFlag = 0;
} }
} }
// clear local entities (particles, gibs, etc.) // clear local entities (particles, gibs, etc.)
// they reference old times and would render incorrectly // they reference old times and would render incorrectly
CG_InitLocalEntities(); CG_InitLocalEntities();
break; // exit loop, wait for next snapshot break; // exit loop, wait for next snapshot
} }
CG_Error( "CG_ProcessSnapshots: Server time went backwards" ); CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
} }
} }
// if our time is < nextFrame's, we have a nice interpolating state // if our time is < nextFrame's, we have a nice interpolating state
if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) { if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {
break; break;
} }
// we have passed the transition from nextFrame to frame // we have passed the transition from nextFrame to frame
CG_TransitionSnapshot(); CG_TransitionSnapshot();
} while ( 1 ); } while ( 1 );
// assert our valid conditions upon exiting // assert our valid conditions upon exiting
if ( cg.snap == NULL ) { if ( cg.snap == NULL ) {
CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" ); CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
} }
if ( cg.time < cg.snap->serverTime ) { if ( cg.time < cg.snap->serverTime ) {
// this can happen right after a vid_restart // this can happen right after a vid_restart
cg.time = cg.snap->serverTime; cg.time = cg.snap->serverTime;
} }
if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) { if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" ); CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,199 +1,199 @@
/* /*
=========================================================================== ===========================================================================
Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code. This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License, published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version. or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
// //
#include "g_local.h" #include "g_local.h"
/* /*
======================================================================= =======================================================================
SESSION DATA SESSION DATA
Session data is the only data that stays persistant across level loads Session data is the only data that stays persistant across level loads
and tournament restarts. and tournament restarts.
======================================================================= =======================================================================
*/ */
/* /*
================ ================
G_WriteClientSessionData G_WriteClientSessionData
Called on game shutdown Called on game shutdown
================ ================
*/ */
void G_WriteClientSessionData( gclient_t *client ) { void G_WriteClientSessionData( gclient_t *client ) {
const char *s; const char *s;
const char *var; const char *var;
s = va("%i %i %i %i %i %i %i", s = va("%i %i %i %i %i %i %i",
client->sess.sessionTeam, client->sess.sessionTeam,
client->sess.spectatorTime, client->sess.spectatorTime,
client->sess.spectatorState, client->sess.spectatorState,
client->sess.spectatorClient, client->sess.spectatorClient,
client->sess.wins, client->sess.wins,
client->sess.losses, client->sess.losses,
client->sess.teamLeader client->sess.teamLeader
); );
var = va( "session%i", client - level.clients ); var = va( "session%i", client - level.clients );
trap_Cvar_Set( var, s ); trap_Cvar_Set( var, s );
} }
/* /*
================ ================
G_ReadSessionData G_ReadSessionData
Called on a reconnect Called on a reconnect
================ ================
*/ */
void G_ReadSessionData( gclient_t *client ) { void G_ReadSessionData( gclient_t *client ) {
char s[MAX_STRING_CHARS]; char s[MAX_STRING_CHARS];
const char *var; const char *var;
// bk001205 - format // bk001205 - format
int teamLeader; int teamLeader;
int spectatorState; int spectatorState;
int sessionTeam; int sessionTeam;
var = va( "session%i", client - level.clients ); var = va( "session%i", client - level.clients );
trap_Cvar_VariableStringBuffer( var, s, sizeof(s) ); trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
sscanf( s, "%i %i %i %i %i %i %i", sscanf( s, "%i %i %i %i %i %i %i",
&sessionTeam, // bk010221 - format &sessionTeam, // bk010221 - format
&client->sess.spectatorTime, &client->sess.spectatorTime,
&spectatorState, // bk010221 - format &spectatorState, // bk010221 - format
&client->sess.spectatorClient, &client->sess.spectatorClient,
&client->sess.wins, &client->sess.wins,
&client->sess.losses, &client->sess.losses,
&teamLeader // bk010221 - format &teamLeader // bk010221 - format
); );
// bk001205 - format issues // bk001205 - format issues
client->sess.sessionTeam = (team_t)sessionTeam; client->sess.sessionTeam = (team_t)sessionTeam;
client->sess.spectatorState = (spectatorState_t)spectatorState; client->sess.spectatorState = (spectatorState_t)spectatorState;
client->sess.teamLeader = (qboolean)teamLeader; client->sess.teamLeader = (qboolean)teamLeader;
} }
/* /*
================ ================
G_InitSessionData G_InitSessionData
Called on a first-time connect Called on a first-time connect
================ ================
*/ */
void G_InitSessionData( gclient_t *client, char *userinfo ) { void G_InitSessionData( gclient_t *client, char *userinfo ) {
clientSession_t *sess; clientSession_t *sess;
const char *value; const char *value;
sess = &client->sess; sess = &client->sess;
// initial team determination // initial team determination
if ( g_gametype.integer >= GT_TEAM ) { if ( g_gametype.integer >= GT_TEAM ) {
if ( g_teamAutoJoin.integer ) { if ( g_teamAutoJoin.integer ) {
sess->sessionTeam = PickTeam( -1 ); sess->sessionTeam = PickTeam( -1 );
BroadcastTeamChange( client, -1 ); BroadcastTeamChange( client, -1 );
} else { } else {
// always spawn as spectator in team games // always spawn as spectator in team games
sess->sessionTeam = TEAM_SPECTATOR; sess->sessionTeam = TEAM_SPECTATOR;
} }
} else { } else {
value = Info_ValueForKey( userinfo, "team" ); value = Info_ValueForKey( userinfo, "team" );
if ( value[0] == 's' ) { if ( value[0] == 's' ) {
// a willing spectator, not a waiting-in-line // a willing spectator, not a waiting-in-line
sess->sessionTeam = TEAM_SPECTATOR; sess->sessionTeam = TEAM_SPECTATOR;
} else { } else {
switch ( g_gametype.integer ) { switch ( g_gametype.integer ) {
default: default:
case GT_FFA: case GT_FFA:
case GT_SINGLE_PLAYER: case GT_SINGLE_PLAYER:
if ( g_maxGameClients.integer > 0 && if ( g_maxGameClients.integer > 0 &&
level.numNonSpectatorClients >= g_maxGameClients.integer ) { level.numNonSpectatorClients >= g_maxGameClients.integer ) {
sess->sessionTeam = TEAM_SPECTATOR; sess->sessionTeam = TEAM_SPECTATOR;
} else { } else {
sess->sessionTeam = TEAM_FREE; sess->sessionTeam = TEAM_FREE;
} }
break; break;
case GT_TOURNAMENT: case GT_TOURNAMENT:
// if the game is full, go into a waiting mode // if the game is full, go into a waiting mode
if ( level.numNonSpectatorClients >= 2 ) { if ( level.numNonSpectatorClients >= 2 ) {
sess->sessionTeam = TEAM_SPECTATOR; sess->sessionTeam = TEAM_SPECTATOR;
} else { } else {
sess->sessionTeam = TEAM_FREE; sess->sessionTeam = TEAM_FREE;
} }
break; break;
} }
} }
} }
sess->spectatorState = SPECTATOR_FREE; sess->spectatorState = SPECTATOR_FREE;
sess->spectatorTime = level.time; sess->spectatorTime = level.time;
G_WriteClientSessionData( client ); G_WriteClientSessionData( client );
} }
/* /*
================== ==================
G_InitWorldSession G_InitWorldSession
================== ==================
*/ */
void G_InitWorldSession( void ) { void G_InitWorldSession( void ) {
char s[MAX_STRING_CHARS]; char s[MAX_STRING_CHARS];
int gt; int gt;
trap_Cvar_VariableStringBuffer( "session", s, sizeof(s) ); trap_Cvar_VariableStringBuffer( "session", s, sizeof(s) );
gt = atoi( s ); gt = atoi( s );
// if the gametype changed since the last session, don't use any // if the gametype changed since the last session, don't use any
// client sessions // client sessions
if ( g_gametype.integer != gt ) { if ( g_gametype.integer != gt ) {
level.newSession = qtrue; level.newSession = qtrue;
G_Printf( "Gametype changed, clearing session data.\n" ); G_Printf( "Gametype changed, clearing session data.\n" );
} }
} }
/* /*
================== ==================
G_WriteSessionData G_WriteSessionData
================== ==================
*/ */
void G_WriteSessionData( void ) { void G_WriteSessionData( void ) {
int i; int i;
// don't persist demo spectator sessions the forced TEAM_SPECTATOR // don't persist demo spectator sessions -- the forced TEAM_SPECTATOR
// would carry over to the next normal game // would carry over to the next normal game
if ( g_svDemoPlaying.integer ) { if ( g_svDemoPlaying.integer ) {
return; return;
} }
trap_Cvar_Set( "session", va("%i", g_gametype.integer) ); trap_Cvar_Set( "session", va("%i", g_gametype.integer) );
for ( i = 0 ; i < level.maxclients ; i++ ) { for ( i = 0 ; i < level.maxclients ; i++ ) {
if ( level.clients[i].pers.connected == CON_CONNECTED ) { if ( level.clients[i].pers.connected == CON_CONNECTED ) {
G_WriteClientSessionData( &level.clients[i] ); G_WriteClientSessionData( &level.clients[i] );
} }
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff