/* * ================== * 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, false); // 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 = false; cent->currentValid = true; CG_ResetEntity(cent); // check for events CG_CheckEvents(cent); } }
/* * =================== * 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, false); cg_entities[cg.snap->ps.clientNum].interpolate = true; // 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 = false; } else { cent->interpolate = true; } } // 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 = true; } else { cg.nextFrameTeleport = false; } // if changing follow mode, don't interpolate if (cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum) { cg.nextFrameTeleport = true; } // if changing server restarts, don't interpolate if ((cg.nextSnap->snapFlags ^ cg.snap->snapFlags) & SNAPFLAG_SERVERCOUNT) { cg.nextFrameTeleport = true; } // sort out solid entities CG_BuildSolidList(); }
/* * ==================== * CL_GetSnapshot * ==================== */ bool CL_GetSnapshot(int snapshotNumber, snapshot_t *snapshot) { clSnapshot_t *clSnap; int i, count; if (snapshotNumber > cl.snap.messageNum) { Com_Error(ERR_DROP, "CL_GetSnapshot: snapshotNumber > cl.snapshot.messageNum"); } // if the frame has fallen out of the circular buffer, we can't return it if (cl.snap.messageNum - snapshotNumber >= PACKET_BACKUP) { return(false); } // if the frame is not valid, we can't return it clSnap = &cl.snapshots[snapshotNumber & PACKET_MASK]; if (!clSnap->valid) { return(false); } // if the entities in the frame have fallen out of their // circular buffer, we can't return it if (cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES) { return(false); } // write the snapshot snapshot->snapFlags = clSnap->snapFlags; snapshot->serverCommandSequence = clSnap->serverCommandNum; snapshot->ping = clSnap->ping; snapshot->serverTime = clSnap->serverTime; Com_Memcpy(snapshot->areamask, clSnap->areamask, sizeof(snapshot->areamask)); snapshot->ps = clSnap->ps; count = clSnap->numEntities; if (count > MAX_ENTITIES_IN_SNAPSHOT) { Com_DPrintf("CL_GetSnapshot: truncated %i entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT); count = MAX_ENTITIES_IN_SNAPSHOT; } snapshot->numEntities = count; for (i = 0; i < count; i++) { snapshot->entities[i] = cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)]; } // FIXME: configstring changes and server commands!!! return(true); }