~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/cgame/cg_snapshot.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

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