/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot( snapshot_t *snap ) { int i; centity_t *cent; entityState_t *state; cg.snap = snap; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for ( i = 0; i < cg.snap->numEntities; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; memcpy( ¢->currentState, state, sizeof( entityState_t ) ); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); } }
// This will only happen on the very first snapshot, or on tourney restarts. // All other times will use CG_TransitionSnapshot instead. // FIXME: Also called by map_restart? void CG_SetInitialSnapshot( snapshot_t *snap ) { int i; centity_t *cent; entityState_t *state; cg.snap = snap; if ( !cg_entities[snap->ps.clientNum].ghoul2 && trap->G2_HaveWeGhoul2Models( cgs.clientinfo[snap->ps.clientNum].ghoul2Model ) ) { trap->G2API_DuplicateGhoul2Instance( cgs.clientinfo[snap->ps.clientNum].ghoul2Model, &cg_entities[snap->ps.clientNum].ghoul2 ); CG_CopyG2WeaponInstance( &cg_entities[snap->ps.clientNum], FIRST_WEAPON, cg_entities[snap->ps.clientNum].ghoul2 ); // check now to see if we have this bone for setting anims and such if ( trap->G2API_AddBolt( cg_entities[snap->ps.clientNum].ghoul2, 0, "face" ) == -1 ) cg_entities[snap->ps.clientNum].noFace = qtrue; } BG_PlayerStateToEntityState( &snap->ps, &cg_entities[snap->ps.clientNum].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for ( i = 0; i < cg.snap->numEntities; i++ ) { state = &cg.snap->entities[i]; cent = &cg_entities[state->number]; memcpy( ¢->currentState, state, sizeof(entityState_t) ); // cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); } // auto record demo if ( cg_autoRecordDemo.integer & (1 << cgs.gametype) && cg.warmup <= 0 && !cg.demoPlayback ) { time_t rawtime; char buf[256] = { 0 }, timeStr[64] = { 0 }, mapName[MAX_QPATH] = { 0 }; time( &rawtime ); strftime( timeStr, sizeof(timeStr), "%Y-%m-%d_%H-%M-%S", localtime( &rawtime ) ); Q_strncpyz( mapName, cgs.mapname + 5, sizeof(mapName) ); Q_strstrip( mapName, "/", "-" ); COM_StripExtension( mapName, mapName, sizeof(mapName) ); Com_sprintf( buf, sizeof(buf), "%s_%s_%s_%s", timeStr, gametypeStringShort[cgs.gametype], mapName, cgs.clientinfo[cg.clientNum].name ); Q_strstrip( buf, "\n\r;?*<>|\\/\"", NULL ); Q_strstrip( buf, " ", "_" ); Q_CleanString( buf, STRIP_COLOUR | STRIP_EXTASCII ); trap->SendConsoleCommand( va( "stoprecord; record %s\n", buf ) ); } }
/* =================== CG_SetNextSnap A new snapshot has just been read in from the client system. =================== */ static void CG_SetNextSnap( snapshot_t *snap ) { int num; entityState_t *es; centity_t *cent; cg.nextSnap = snap; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse ); cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue; // check for extrapolation errors for ( num = 0; num < snap->numEntities; num++ ) { es = &snap->entities[ num ]; cent = &cg_entities[ es->number ]; memcpy( ¢->nextState, es, sizeof( entityState_t ) ); //cent->nextState = *es; // if this frame is a teleport, or the entity wasn't in the // previous frame, don't interpolate if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) { cent->interpolate = qfalse; } else { cent->interpolate = qtrue; } } // if the next frame is a teleport for the playerstate, we // can't interpolate during demos if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) { cg.nextFrameTeleport = qtrue; } else { cg.nextFrameTeleport = qfalse; } // if changing follow mode, don't interpolate if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) { cg.nextFrameTeleport = qtrue; } // if changing server restarts, don't interpolate if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) { cg.nextFrameTeleport = qtrue; CG_OnMapRestart(); } // sort out solid entities CG_BuildSolidList(); }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot( snapshot_t *snap ) { int i; centity_t *cent; entityState_t *state; lua_State *L = GetClientLuaState(); cg.snap = snap; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; memcpy(¢->currentState, state, sizeof(entityState_t)); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); if(L != NULL && cent->linked == qfalse && cent->currentState.eType <= ET_LUA && cent->currentState.eType != ET_GENERAL) { qlua_gethook(L,"EntityLinked"); lua_pushentity(L,cent); qlua_pcall(L,1,0,qtrue); cent->linked = qtrue; } } if(L != NULL && !playBack) { qlua_gethook(L,"InitialSnapshot"); qlua_pcall(L,0,0,qtrue); } }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot. At all other times, CG_TransitionSnapshot is used instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot( snapshot_t *snap ) { int i; centity_t *cent; entityState_t *state; cg.snap = snap; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for ( i = 0; i < cg.snap->numEntities; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; memcpy( ¢->currentState, state, sizeof( entityState_t ) ); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); } // Need this check because the initial weapon for spec isn't always WP_NONE if ( snap->ps.persistant[ PERS_TEAM ] == TEAM_NONE ) { trap_Rocket_ShowHud( WP_NONE ); } else { trap_Rocket_ShowHud( BG_GetPlayerWeapon( &snap->ps ) ); } }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot( snapshot_t *snap ) { int i; centity_t *cent; entityState_t *state; cg.snap = snap; if ((cg_entities[snap->ps.clientNum].ghoul2 == NULL) && trap_G2_HaveWeGhoul2Models(cgs.clientinfo[snap->ps.clientNum].ghoul2Model)) { trap_G2API_DuplicateGhoul2Instance(cgs.clientinfo[snap->ps.clientNum].ghoul2Model, &cg_entities[snap->ps.clientNum].ghoul2); CG_CopyG2WeaponInstance(FIRST_WEAPON, cg_entities[snap->ps.clientNum].ghoul2); } BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; memcpy(¢->currentState, state, sizeof(entityState_t)); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; if ( jk2startversion == VERSION_1_02 ) { // MVSDK: Version Magic! cent->currentState.torsoAnim = MV_MapAnimation104( cent->currentState.torsoAnim ); cent->currentState.legsAnim = MV_MapAnimation104( cent->currentState.legsAnim ); } CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); } }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot( snapshot_t *snap ) { int i; centity_t *cent; entityState_t *state; cg.snap = snap; if ((cg_entities[snap->ps.clientNum].ghoul2 == NULL) && trap->G2_HaveWeGhoul2Models(cgs.clientinfo[snap->ps.clientNum].ghoul2Model)) { trap->G2API_DuplicateGhoul2Instance(cgs.clientinfo[snap->ps.clientNum].ghoul2Model, &cg_entities[snap->ps.clientNum].ghoul2); CG_CopyG2WeaponInstance(&cg_entities[snap->ps.clientNum], FIRST_WEAPON, 0, cg_entities[snap->ps.clientNum].ghoul2); if (trap->G2API_AddBolt(cg_entities[snap->ps.clientNum].ghoul2, 0, "face") == -1) { //check now to see if we have this bone for setting anims and such cg_entities[snap->ps.clientNum].noFace = qtrue; } } BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; memcpy(¢->currentState, state, sizeof(entityState_t)); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); } }
void firstReplayFrame() { int i; snapshot_t *snap; centity_t *cent; entityState_t *state; lua_State *L = GetClientLuaState(); snap = &replaySnaps[0]; cg.snap = snap; cg.snap->serverTime += cg.time; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); CG_Respawn(); for ( i = 0 ; i < sizeof(cg_entities) / sizeof(cg_entities[0]); i++ ) { CG_ResetEntity(&cg_entities[i]); } for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; if(state->time != 0) state->time += cg.time; if(state->time2 != 0) state->time2 += cg.time; state->pos.trTime += cg.time; state->apos.trTime += cg.time; memcpy(¢->currentState, state, sizeof(entityState_t)); cent->interpolate = qtrue; cent->currentValid = qtrue; CG_ResetEntity( cent ); CG_CheckEvents( cent ); cent->previousEvent = 0; } //cg.time = snap->serverTime; }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot( snapshot_t *snap ) { int i; centity_t *cent; entityState_t *state; char buff[16]; cg.snap = snap; // trap_S_ClearSounds( qtrue ); BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn( qfalse ); for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; memcpy(¢->currentState, state, sizeof(entityState_t)); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); } cg_fxflags = 0; trap_Cvar_VariableStringBuffer( "r_oldMode", buff, sizeof(buff) ); if( atoi(buff) ) { // Arnout: confirmation screen trap_UI_Popup( UIMENU_INGAME ); } else if(cg.demoPlayback) { ccInitial = qtrue; } else { static char prevmap[64] = { 0 }; char curmap[64]; trap_Cvar_VariableStringBuffer( "mapname", curmap, 64 ); if ( Q_stricmp( curmap, prevmap ) ) { strcpy( prevmap, curmap ); if(cgs.campaignInfoLoaded) { if( !cg.showGameView ) { CG_LimboMenu_f(); } /* } else { ccInitial = qtrue; // Start the Initial Camera if specified CG_StartInitialCamera(); */ } } } // OSP - remove motd window if(cg.motdWindow != NULL) { CG_windowFree(cg.motdWindow); cg.motdWindow = NULL; } // Activate alternate input handler during demo playback if(cg.demoPlayback) { CG_keyOn_f(); if(demo_infoWindow.integer > 0) { CG_ShowHelp_On(&cg.demohelpWindow); } } // OSP #if __MACOS__ #ifdef GAMERANGER // LBO 12/13/04. Add support for GameRanger team voice IDs GRSetMyTeamID(cg.snap->ps.persistant[PERS_TEAM]); #endif #endif }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot(snapshot_t *snap) { int i; centity_t *cent; entityState_t *state; char buff[16]; cg.snap = snap; // trap_S_ClearSounds( qtrue ); BG_PlayerStateToEntityState(&snap->ps, &cg_entities[snap->ps.clientNum].currentState, cg.time, qfalse); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands(snap->serverCommandSequence); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(qfalse); for (i = 0 ; i < cg.snap->numEntities ; i++) { state = &cg.snap->entities[i]; cent = &cg_entities[state->number]; memcpy(¢->currentState, state, sizeof(entityState_t)); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity(cent); // check for events CG_CheckEvents(cent); } trap_Cvar_VariableStringBuffer("r_oldMode", buff, sizeof(buff)); if (atoi(buff)) { // confirmation screen trap_UI_Popup(UIMENU_INGAME); } else if (cg.demoPlayback) { ccInitial = qtrue; } else { static char prevmap[64] = { 0 }; char curmap[64]; trap_Cvar_VariableStringBuffer("mapname", curmap, 64); if (Q_stricmp(curmap, prevmap)) { strcpy(prevmap, curmap); if (cgs.campaignInfoLoaded) { if (!cg.showGameView) { CG_LimboMenu_f(); } /* } else { ccInitial = qtrue; // Start the Initial Camera if specified CG_StartInitialCamera(); */ } } } // remove motd window if (cg.motdWindow != NULL) { CG_windowFree(cg.motdWindow); cg.motdWindow = NULL; } // Activate alternate input handler during demo playback if (cg.demoPlayback) { CG_keyOn_f(); if (demo_infoWindow.integer > 0) { CG_ShowHelp_On(&cg.demohelpWindow); } } // update client XP for spectator frames if (cg.snap->ps.clientNum == cg.clientNum) // sanity check { int cXP = (32768 * cg.snap->ps.stats[STAT_XP_OVERFLOW]) + cg.snap->ps.stats[STAT_XP]; if (cg.xp < cXP) { cg.xpChangeTime = cg.time; } cg.xp = cXP; } }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. ================== */ void CG_SetInitialSnapshot(snapshot_t *snap) { int i; centity_t *cent; char buff[16]; cg.snap = snap; BG_PlayerStateToEntityState(&snap->ps, &cg_entities[snap->ps.clientNum].currentState, qfalse); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands(snap->serverCommandSequence); // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for (i = 0 ; i < cg.snap->numEntities ; ++i) { entityState_t *state = &cg.snap->entities[i]; cent = &cg_entities[state->number]; memcpy(¢->currentState, state, sizeof (entityState_t)); cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity(cent); // check for events CG_CheckEvents(cent); } cg_fxflags = 0; trap_Cvar_VariableStringBuffer("r_oldMode", buff, sizeof (buff)); if (atoi(buff)) { // Arnout: confirmation screen trap_UI_Popup(UIMENU_INGAME); } else if (!cg.demoPlayback) { static char prevmap[64] = { 0 }; char curmap[64]; trap_Cvar_VariableStringBuffer("mapname", curmap, 64); if (Q_stricmp(curmap, prevmap)) { strcpy(prevmap, curmap); if (cgs.campaignInfoLoaded) { if (!cg.showGameView) { CG_LimboMenu_f(); } } } } // OSP - remove motd window if (cg.motdWindow != NULL) { CG_windowFree(cg.motdWindow); cg.motdWindow = NULL; } // Activate alternate input handler during demo playback if (cg.demoPlayback) { CG_keyOn_f(); if (demo_infoWindow.integer > 0) { CG_ShowHelp_On(&cg.demohelpWindow); } } }
/* ================== CG_SetInitialSnapshot This will only happen on the very first snapshot, or on tourney restarts. All other times will use CG_TransitionSnapshot instead. FIXME: Also called by map_restart? ================== */ void CG_SetInitialSnapshot( snapshot_t *snap ) { char buf[64]; int i; centity_t *cent; entityState_t *state; cg.snap = snap; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); // sort out solid entities CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); trap_SendClientCommand( "fogswitch 0" ); // clear it out so the set below will take trap_Cvar_VariableStringBuffer( "r_savegameFogColor", buf, sizeof( buf ) ); trap_Cvar_Set( "r_savegameFogColor", "0" ); if ( strlen( buf ) > 1 ) { if ( !Q_stricmp( buf, "none" ) ) { trap_SendClientCommand( "fogswitch 0" ); // 'off' } else { trap_SendClientCommand( va( "fogswitch %s", buf ) ); } } else { trap_Cvar_VariableStringBuffer( "r_mapFogColor", buf, sizeof( buf ) ); trap_SendClientCommand( va( "fogswitch %s", buf ) ); } // set our local weapon selection pointer to // what the server has indicated the current weapon is CG_Respawn(); for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; memcpy( ¢->currentState, state, sizeof( entityState_t ) ); //cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; CG_ResetEntity( cent ); // check for events CG_CheckEvents( cent ); } // DHM - Nerve :: Set cg.clientNum so that it may be used elsewhere cg.clientNum = snap->ps.clientNum; // NERVE - SMF { static char prevmap[64] = { 0 }; char curmap[64]; trap_Cvar_VariableStringBuffer( "mapname", curmap, 64 ); if ( cgs.gametype == GT_WOLF && Q_stricmp( curmap, prevmap ) ) { strcpy( prevmap, curmap ); trap_SendConsoleCommand( "openLimboMenu\n" ); } } // -NERVE - SMF }
void demoProcessSnapShots( qboolean hadSkip ) { int i; snapshot_t *snap; // see what the latest snapshot the client system has is trap_GetCurrentSnapshotNumber( &cg.latestSnapshotNum, &cg.latestSnapshotTime ); if (hadSkip || !cg.snap) { cgs.processedSnapshotNum = max(cg.latestSnapshotNum - 3, -1); if (cg.nextSnap) cgs.serverCommandSequence = cg.nextSnap->serverCommandSequence; else if (cg.snap) cgs.serverCommandSequence = cg.snap->serverCommandSequence; cg.snap = 0; cg.nextSnap = 0; cg.nextNextSnap = 0; for (i=-1;i<MAX_GENTITIES;i++) { centity_t *cent = i < 0 ? &cg.predictedPlayerEntity : &cg_entities[i]; cent->trailTime = cg.time; cent->snapShotTime = cg.time; cent->currentValid = qfalse; cent->interpolate = qfalse; cent->muzzleFlashTime = cg.time - MUZZLE_FLASH_TIME - 1; cent->previousEvent = 0; if (cent->currentState.eType == ET_PLAYER) { memset( ¢->pe, 0, sizeof( cent->pe ) ); cent->pe.legs.yawAngle = cent->lerpAngles[YAW]; cent->pe.torso.yawAngle = cent->lerpAngles[YAW]; cent->pe.torso.pitchAngle = cent->lerpAngles[PITCH]; } } } /* Check if we have some transition between snapsnots */ if (!cg.snap) { entityState_t pes; snap = CG_ReadNextSnapshot(); if (!snap) return; cg.snap = snap; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); CG_BuildSolidList(); CG_ExecuteNewServerCommands( snap->serverCommandSequence ); CG_UpdateTps( snap, qtrue ); BG_PlayerStateToEntityStateExtraPolate( &snap->ps, &pes, snap->ps.commandTime, qfalse ); CG_AddToHistory( snap->serverTime, &pes, &cg_entities[snap->ps.clientNum] ); for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { entityState_t *state = &cg.snap->entities[ i ]; centity_t *cent = &cg_entities[ state->number ]; memcpy(¢->currentState, state, sizeof(entityState_t)); cent->interpolate = qfalse; cent->currentValid = qtrue; CG_AddToHistory( snap->serverTime, state, cent ); if (cent->currentState.eType > ET_EVENTS) cent->previousEvent = 1; else cent->previousEvent = cent->currentState.event; } } do { if (!cg.nextSnap) { snap = CG_ReadNextSnapshot(); if (!snap) break; CG_SetNextSnap( snap ); } if ( !cg.nextNextSnap ) { snap = CG_ReadNextSnapshot(); if ( !snap ) break; CG_SetNextNextSnap( snap ); } if ( cg.timeFraction >= cg.snap->serverTime - cg.time && cg.timeFraction < cg.nextSnap->serverTime - cg.time ) break; //Todo our own transition checking if we wanna hear certain sounds CG_TransitionSnapshot(); } while (1); }
/* =================== CG_SetNextSnap A new snapshot has just been read in from the client system. =================== */ static void CG_SetNextSnap( snapshot_t *snap ) { lua_State *L = GetClientLuaState(); int num,i,n; int numEnts = sizeof(cg_entities) / sizeof(cg_entities[0]); entityState_t *es; centity_t *cent,*tent; qboolean f = qfalse; qboolean isplayer = qfalse; cg.nextSnap = snap; BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse ); cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue; // check for extrapolation errors for ( num = 0 ; num < snap->numEntities ; num++ ) { es = &snap->entities[num]; cent = &cg_entities[ es->number ]; isplayer = (&cgs.clientinfo[ cent->currentState.clientNum ] != NULL); memcpy(¢->nextState, es, sizeof(entityState_t)); //cent->nextState = *es; // if this frame is a teleport, or the entity wasn't in the // previous frame, don't interpolate if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) { cent->interpolate = qfalse; } else { cent->interpolate = qtrue; } } if(L != NULL) { for (i = 0, tent = cg_entities, n = 1; i < numEnts; i++, tent++) { if(tent != NULL && tent->linked) { isplayer = (&cgs.clientinfo[ tent->currentState.clientNum ] != NULL); f = qfalse; for ( num = 0 ; num < snap->numEntities ; num++ ) { es = &snap->entities[num]; if(es->number == tent->currentState.number) { f = qtrue; } } // && !isplayer if(f == qfalse) { tent->linked = qfalse; qlua_gethook(L,"EntityUnlinked"); lua_pushentity(L,tent); qlua_pcall(L,1,0,qtrue); } } n++; } } // if the next frame is a teleport for the playerstate, we // can't interpolate during demos if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) { cg.nextFrameTeleport = qtrue; } else { cg.nextFrameTeleport = qfalse; } // if changing follow mode, don't interpolate if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) { cg.nextFrameTeleport = qtrue; } // if changing server restarts, don't interpolate if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) { cg.nextFrameTeleport = qtrue; } // sort out solid entities CG_BuildSolidList(); }
void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView ) { qboolean inwater = qfalse; cg.time = serverTime; CG_BuildSolidList(); // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list cgi_S_ClearLoopingSounds(); // clear all the render lists cgi_R_ClearScene(); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap ) { CG_DrawInformation(); return; } // let the client system know what our weapon and zoom settings are cgi_SetUserCmdValue( cg.weaponSelect, cg.refdef.fov_y / 75.0 ); // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predicted_player_state CG_PredictPlayerState(); // decide on third person view cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); if ( in_camera ) { // The camera takes over the view CGCam_RenderScene(); } else { //Finish any fading that was happening CGCam_UpdateFade(); // build cg.refdef inwater = CG_CalcViewValues(); } //This is done from the vieworg to get origin for non-attenuated sounds cgi_S_UpdateAmbientSet( CG_ConfigString( CS_AMBIENT_SET ), cg.refdef.vieworg ); // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { CG_DamageBlendBlob(); } // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); CG_AddLocalEntities(); } // Don't draw the in-view weapon when in camera mode if ( !in_camera && !cg_pano.integer ) CG_AddViewWeapon( &cg.predicted_player_state ); // finish up the rest of the refdef if ( cg.testModelEntity.hModel ) { CG_AddTestModel(); } cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); // update audio positions cgi_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); // warning sounds when powerup is wearing off CG_PowerupTimerSounds(); // make sure the lagometerSample and frame timing isn't done twice when in stereo if ( stereoView != STEREO_RIGHT ) { cg.frametime = cg.time - cg.oldTime; cg.oldTime = cg.time; } //Add all effects if (cg.frametime >= 0) { FX_Add(); } if ( cg_pano.integer ) { // let's grab a panorama! cg.levelShot = qtrue; //hide the 2d VectorClear(cg.refdefViewAngles); cg.refdefViewAngles[YAW] = -360 * cg_pano.integer/cg_panoNumShots.integer; //choose angle AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); CG_DrawActive( stereoView ); cg.levelShot = qfalse; } else { // actually issue the rendering calls CG_DrawActive( stereoView ); } }