1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2000-2006 Tim Angus
5 
6 This file is part of Tremulous.
7 
8 Tremulous is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12 
13 Tremulous is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Tremulous; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 ===========================================================================
22 */
23 
24 // cg_snapshot.c -- things that happen on snapshot transition,
25 // not necessarily every single rendered frame
26 
27 
28 #include "cg_local.h"
29 
30 /*
31 ==================
32 CG_ResetEntity
33 ==================
34 */
CG_ResetEntity(centity_t * cent)35 static void CG_ResetEntity( centity_t *cent )
36 {
37   // if the previous snapshot this entity was updated in is at least
38   // an event window back in time then we can reset the previous event
39   if( cent->snapShotTime < cg.time - EVENT_VALID_MSEC )
40     cent->previousEvent = 0;
41 
42   cent->trailTime = cg.snap->serverTime;
43 
44   VectorCopy( cent->currentState.origin, cent->lerpOrigin );
45   VectorCopy( cent->currentState.angles, cent->lerpAngles );
46 
47   if( cent->currentState.eType == ET_PLAYER )
48     CG_ResetPlayerEntity( cent );
49 }
50 
51 /*
52 ===============
53 CG_TransitionEntity
54 
55 cent->nextState is moved to cent->currentState and events are fired
56 ===============
57 */
CG_TransitionEntity(centity_t * cent)58 static void CG_TransitionEntity( centity_t *cent )
59 {
60   cent->currentState = cent->nextState;
61   cent->currentValid = qtrue;
62 
63   // reset if the entity wasn't in the last frame or was teleported
64   if( !cent->interpolate )
65     CG_ResetEntity( cent );
66 
67   // clear the next state.  if will be set by the next CG_SetNextSnap
68   cent->interpolate = qfalse;
69 
70   // check for events
71   CG_CheckEvents( cent );
72 }
73 
74 
75 /*
76 ==================
77 CG_SetInitialSnapshot
78 
79 This will only happen on the very first snapshot, or
80 on tourney restarts.  All other times will use
81 CG_TransitionSnapshot instead.
82 
83 FIXME: Also called by map_restart?
84 ==================
85 */
CG_SetInitialSnapshot(snapshot_t * snap)86 void CG_SetInitialSnapshot( snapshot_t *snap )
87 {
88   int           i;
89   centity_t     *cent;
90   entityState_t *state;
91 
92   cg.snap = snap;
93 
94   BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
95 
96   // sort out solid entities
97   CG_BuildSolidList( );
98 
99   CG_ExecuteNewServerCommands( snap->serverCommandSequence );
100 
101   // set our local weapon selection pointer to
102   // what the server has indicated the current weapon is
103   CG_Respawn( );
104 
105   for( i = 0; i < cg.snap->numEntities; i++ )
106   {
107     state = &cg.snap->entities[ i ];
108     cent = &cg_entities[ state->number ];
109 
110     memcpy( &cent->currentState, state, sizeof( entityState_t ) );
111     //cent->currentState = *state;
112     cent->interpolate = qfalse;
113     cent->currentValid = qtrue;
114 
115     CG_ResetEntity( cent );
116 
117     // check for events
118     CG_CheckEvents( cent );
119   }
120 }
121 
122 
123 /*
124 ===================
125 CG_TransitionSnapshot
126 
127 The transition point from snap to nextSnap has passed
128 ===================
129 */
CG_TransitionSnapshot(void)130 static void CG_TransitionSnapshot( void )
131 {
132   centity_t   *cent;
133   snapshot_t  *oldFrame;
134   int         i;
135 
136   if( !cg.snap )
137     CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
138 
139   if( !cg.nextSnap )
140     CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
141 
142   // execute any server string commands before transitioning entities
143   CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
144 
145   // if we had a map_restart, set everthing with initial
146   if( !cg.snap ) { } //TA: ?
147 
148   // clear the currentValid flag for all entities in the existing snapshot
149   for( i = 0; i < cg.snap->numEntities; i++ )
150   {
151     cent = &cg_entities[ cg.snap->entities[ i ].number ];
152     cent->currentValid = qfalse;
153   }
154 
155   // move nextSnap to snap and do the transitions
156   oldFrame = cg.snap;
157   cg.snap = cg.nextSnap;
158 
159   BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
160   cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
161 
162   for( i = 0; i < cg.snap->numEntities; i++ )
163   {
164     cent = &cg_entities[ cg.snap->entities[ i ].number ];
165     CG_TransitionEntity( cent );
166 
167     // remember time of snapshot this entity was last updated in
168     cent->snapShotTime = cg.snap->serverTime;
169   }
170 
171   cg.nextSnap = NULL;
172 
173   // check for playerstate transition events
174   if( oldFrame )
175   {
176     playerState_t *ops, *ps;
177 
178     ops = &oldFrame->ps;
179     ps = &cg.snap->ps;
180     // teleporting checks are irrespective of prediction
181     if( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT )
182       cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
183 
184     // if we are not doing client side movement prediction for any
185     // reason, then the client events and view changes will be issued now
186     if( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW ) ||
187         cg_nopredict.integer || cg_synchronousClients.integer )
188       CG_TransitionPlayerState( ps, ops );
189   }
190 }
191 
192 
193 /*
194 ===================
195 CG_SetNextSnap
196 
197 A new snapshot has just been read in from the client system.
198 ===================
199 */
CG_SetNextSnap(snapshot_t * snap)200 static void CG_SetNextSnap( snapshot_t *snap )
201 {
202   int           num;
203   entityState_t *es;
204   centity_t     *cent;
205 
206   cg.nextSnap = snap;
207 
208   BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
209   cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
210 
211   // check for extrapolation errors
212   for( num = 0 ; num < snap->numEntities ; num++ )
213   {
214     es = &snap->entities[ num ];
215     cent = &cg_entities[ es->number ];
216 
217     memcpy( &cent->nextState, es, sizeof( entityState_t ) );
218     //cent->nextState = *es;
219 
220     // if this frame is a teleport, or the entity wasn't in the
221     // previous frame, don't interpolate
222     if( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) )
223       cent->interpolate = qfalse;
224     else
225       cent->interpolate = qtrue;
226   }
227 
228   // if the next frame is a teleport for the playerstate, we
229   // can't interpolate during demos
230   if( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) )
231     cg.nextFrameTeleport = qtrue;
232   else
233     cg.nextFrameTeleport = qfalse;
234 
235   // if changing follow mode, don't interpolate
236   if( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum )
237     cg.nextFrameTeleport = qtrue;
238 
239   // if changing server restarts, don't interpolate
240   if( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT )
241     cg.nextFrameTeleport = qtrue;
242 
243   // sort out solid entities
244   CG_BuildSolidList( );
245 }
246 
247 
248 /*
249 ========================
250 CG_ReadNextSnapshot
251 
252 This is the only place new snapshots are requested
253 This may increment cgs.processedSnapshotNum multiple
254 times if the client system fails to return a
255 valid snapshot.
256 ========================
257 */
CG_ReadNextSnapshot(void)258 static snapshot_t *CG_ReadNextSnapshot( void )
259 {
260   qboolean    r;
261   snapshot_t  *dest;
262 
263   if( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 )
264   {
265     CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
266       cg.latestSnapshotNum, cgs.processedSnapshotNum );
267   }
268 
269   while( cgs.processedSnapshotNum < cg.latestSnapshotNum )
270   {
271     // decide which of the two slots to load it into
272     if( cg.snap == &cg.activeSnapshots[ 0 ] )
273       dest = &cg.activeSnapshots[ 1 ];
274     else
275       dest = &cg.activeSnapshots[ 0 ];
276 
277     // try to read the snapshot from the client system
278     cgs.processedSnapshotNum++;
279     r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
280 
281     // FIXME: why would trap_GetSnapshot return a snapshot with the same server time
282     if( cg.snap && r && dest->serverTime == cg.snap->serverTime )
283     {
284       //continue;
285     }
286 
287     // if it succeeded, return
288     if( r )
289     {
290       CG_AddLagometerSnapshotInfo( dest );
291       return dest;
292     }
293 
294     // a GetSnapshot will return failure if the snapshot
295     // never arrived, or  is so old that its entities
296     // have been shoved off the end of the circular
297     // buffer in the client system.
298 
299     // record as a dropped packet
300     CG_AddLagometerSnapshotInfo( NULL );
301 
302     // If there are additional snapshots, continue trying to
303     // read them.
304   }
305 
306   // nothing left to read
307   return NULL;
308 }
309 
310 
311 /*
312 ============
313 CG_ProcessSnapshots
314 
315 We are trying to set up a renderable view, so determine
316 what the simulated time is, and try to get snapshots
317 both before and after that time if available.
318 
319 If we don't have a valid cg.snap after exiting this function,
320 then a 3D game view cannot be rendered.  This should only happen
321 right after the initial connection.  After cg.snap has been valid
322 once, it will never turn invalid.
323 
324 Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
325 hasn't arrived yet (it becomes an extrapolating situation instead
326 of an interpolating one)
327 
328 ============
329 */
CG_ProcessSnapshots(void)330 void CG_ProcessSnapshots( void )
331 {
332   snapshot_t  *snap;
333   int         n;
334 
335   // see what the latest snapshot the client system has is
336   trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
337 
338   if( n != cg.latestSnapshotNum )
339   {
340     if( n < cg.latestSnapshotNum )
341     {
342       // this should never happen
343       CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
344     }
345 
346     cg.latestSnapshotNum = n;
347   }
348 
349   // If we have yet to receive a snapshot, check for it.
350   // Once we have gotten the first snapshot, cg.snap will
351   // always have valid data for the rest of the game
352   while( !cg.snap )
353   {
354     snap = CG_ReadNextSnapshot( );
355 
356     if( !snap )
357     {
358       // we can't continue until we get a snapshot
359       return;
360     }
361 
362     // set our weapon selection to what
363     // the playerstate is currently using
364     if( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) )
365       CG_SetInitialSnapshot( snap );
366   }
367 
368   // loop until we either have a valid nextSnap with a serverTime
369   // greater than cg.time to interpolate towards, or we run
370   // out of available snapshots
371   do
372   {
373     // if we don't have a nextframe, try and read a new one in
374     if( !cg.nextSnap )
375     {
376       snap = CG_ReadNextSnapshot( );
377 
378       // if we still don't have a nextframe, we will just have to
379       // extrapolate
380       if( !snap )
381         break;
382 
383       CG_SetNextSnap( snap );
384 
385       // if time went backwards, we have a level restart
386       if( cg.nextSnap->serverTime < cg.snap->serverTime )
387         CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
388     }
389 
390     // if our time is < nextFrame's, we have a nice interpolating state
391     if( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime )
392       break;
393 
394     // we have passed the transition from nextFrame to frame
395     CG_TransitionSnapshot( );
396   } while( 1 );
397 
398   // assert our valid conditions upon exiting
399   if( cg.snap == NULL )
400     CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
401 
402   if( cg.time < cg.snap->serverTime )
403   {
404     // this can happen right after a vid_restart
405     cg.time = cg.snap->serverTime;
406   }
407 
408   if( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time )
409     CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
410 }
411 
412