1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 // cg_snapshot.c -- things that happen on snapshot transition,
30 // not necessarily every single rendered frame
31 
32 
33 
34 #include "cg_local.h"
35 
36 
37 
38 /*
39 ==================
40 CG_ResetEntity
41 ==================
42 */
CG_ResetEntity(centity_t * cent)43 static void CG_ResetEntity( centity_t *cent ) {
44 	// if an event is set, assume it is new enough to use
45 	// if the event had timed out, it would have been cleared
46 	// RF, not needed for wolf
47 	// DHM - Nerve :: Wolf is now using this.
48 	cent->previousEvent = 0;
49 	cent->previousEventSequence = cent->currentState.eventSequence;
50 
51 	cent->trailTime = cg.snap->serverTime;
52 
53 	// Ridah
54 	cent->headJuncIndex = 0;
55 	cent->headJuncIndex2 = 0;
56 	// done.
57 
58 	VectorCopy( cent->currentState.origin, cent->lerpOrigin );
59 	VectorCopy( cent->currentState.angles, cent->lerpAngles );
60 	if ( cent->currentState.eType == ET_PLAYER ) {
61 		CG_ResetPlayerEntity( cent );
62 	}
63 }
64 
65 
66 
67 /*
68 ===============
69 CG_TransitionEntity
70 
71 cent->nextState is moved to cent->currentState and events are fired
72 ===============
73 */
CG_TransitionEntity(centity_t * cent)74 static void CG_TransitionEntity( centity_t *cent ) {
75 
76 	// Ridah, update the fireDir if it's on fire
77 	if ( CG_EntOnFire( cent ) ) {
78 		vec3_t newDir, newPos, oldPos;
79 		float adjust;
80 		//
81 		BG_EvaluateTrajectory( &cent->nextState.pos, cg.snap->serverTime, newPos );
82 		BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, oldPos );
83 		// update the fireRiseDir
84 		VectorSubtract( oldPos, newPos, newDir );
85 		// fire should go upwards if travelling slow
86 		newDir[2] += 2;
87 		if ( VectorNormalize( newDir ) < 1 ) {
88 			VectorClear( newDir );
89 			newDir[2] = 1;
90 		}
91 		// now move towards the newDir
92 		adjust = 0.3;
93 		VectorMA( cent->fireRiseDir, adjust, newDir, cent->fireRiseDir );
94 		if ( VectorNormalize( cent->fireRiseDir ) <= 0.1 ) {
95 			VectorCopy( newDir, cent->fireRiseDir );
96 		}
97 	}
98 
99 	//----(SA)	the ent lost or gained some part(s), do any necessary effects
100 	//TODO: check for ai first
101 	if ( cent->currentState.dmgFlags != cent->nextState.dmgFlags ) {
102 		CG_AttachedPartChange( cent );
103 	}
104 
105 
106 	cent->currentState = cent->nextState;
107 	cent->currentValid = qtrue;
108 
109 	// reset if the entity wasn't in the last frame or was teleported
110 	if ( !cent->interpolate ) {
111 		CG_ResetEntity( cent );
112 	}
113 
114 	// clear the next state.  if will be set by the next CG_SetNextSnap
115 	cent->interpolate = qfalse;
116 
117 	// check for events
118 	CG_CheckEvents( cent );
119 }
120 
121 
122 /*
123 ==================
124 CG_SetInitialSnapshot
125 
126 This will only happen on the very first snapshot.
127 All other times will use CG_TransitionSnapshot instead.
128 ==================
129 */
CG_SetInitialSnapshot(snapshot_t * snap)130 void CG_SetInitialSnapshot( snapshot_t *snap ) {
131 	int i;
132 	centity_t       *cent;
133 	entityState_t   *state;
134 
135 	cg.snap = snap;
136 
137 	BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
138 
139 	// sort out solid entities
140 	CG_BuildSolidList();
141 
142 	CG_ExecuteNewServerCommands( snap->serverCommandSequence );
143 
144 	// set our local weapon selection pointer to
145 	// what the server has indicated the current weapon is
146 	CG_Respawn();
147 
148 	for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
149 		state = &cg.snap->entities[ i ];
150 		cent = &cg_entities[ state->number ];
151 
152 		memcpy( &cent->currentState, state, sizeof( entityState_t ) );
153 		//cent->currentState = *state;
154 		cent->interpolate = qfalse;
155 		cent->currentValid = qtrue;
156 
157 		CG_ResetEntity( cent );
158 
159 		// check for events
160 		CG_CheckEvents( cent );
161 	}
162 
163 // JPW NERVE -- make sure we didn't break anything
164 	cg_fxflags = 0;
165 // jpw
166 
167 	// DHM - Nerve :: Set cg.clientNum so that it may be used elsewhere
168 	// NERVE - SMF - commented out, TA merge, this has been moved to CG_Init
169 //	cg.clientNum = snap->ps.clientNum;
170 
171 	// NERVE - SMF
172 	{
173 		static char prevmap[64] = { 0 };
174 		char curmap[64];
175 
176 		trap_Cvar_VariableStringBuffer( "mapname", curmap, 64 );
177 
178 		if ( cgs.gametype >= GT_WOLF && Q_stricmp( curmap, prevmap ) ) {
179 			strcpy( prevmap, curmap );
180 			trap_SendConsoleCommand( "openLimboMenu\n" );
181 		}
182 	}
183 	// -NERVE - SMF
184 }
185 
186 
187 /*
188 ===================
189 CG_TransitionSnapshot
190 
191 The transition point from snap to nextSnap has passed
192 ===================
193 */
CG_TransitionSnapshot(void)194 static void CG_TransitionSnapshot( void ) {
195 	centity_t           *cent;
196 	snapshot_t          *oldFrame;
197 	int i;
198 
199 	if ( !cg.snap ) {
200 		CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
201 	}
202 	if ( !cg.nextSnap ) {
203 		CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
204 	}
205 
206 	// execute any server string commands before transitioning entities
207 	CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
208 
209 	// if we had a map_restart, set everything with initial
210 	if ( cg.mapRestart ) {
211 	}
212 
213 	// clear the currentValid flag for all entities in the existing snapshot
214 	for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
215 		cent = &cg_entities[ cg.snap->entities[ i ].number ];
216 		cent->currentValid = qfalse;
217 	}
218 
219 	// move nextSnap to snap and do the transitions
220 	oldFrame = cg.snap;
221 	cg.snap = cg.nextSnap;
222 
223 	BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
224 	cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
225 
226 	for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
227 		cent = &cg_entities[ cg.snap->entities[ i ].number ];
228 		CG_TransitionEntity( cent );
229 	}
230 
231 	cg.nextSnap = NULL;
232 
233 	// check for playerstate transition events
234 	if ( oldFrame ) {
235 		playerState_t   *ops, *ps;
236 
237 		ops = &oldFrame->ps;
238 		ps = &cg.snap->ps;
239 		// teleporting checks are irrespective of prediction
240 		if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
241 			cg.thisFrameTeleport = qtrue;   // will be cleared by prediction code
242 		}
243 
244 		// if we are not doing client side movement prediction for any
245 		// reason, then the client events and view changes will be issued now
246 		if ( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW )
247 			 || cg_nopredict.integer || cg_synchronousClients.integer ) {
248 			CG_TransitionPlayerState( ps, ops );
249 		}
250 	}
251 
252 }
253 
254 
255 /*
256 ===================
257 CG_SetNextSnap
258 
259 A new snapshot has just been read in from the client system.
260 ===================
261 */
CG_SetNextSnap(snapshot_t * snap)262 static void CG_SetNextSnap( snapshot_t *snap ) {
263 	int num;
264 	entityState_t       *es;
265 	centity_t           *cent;
266 
267 	cg.nextSnap = snap;
268 
269 	BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
270 	cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
271 
272 	// check for extrapolation errors
273 	for ( num = 0 ; num < snap->numEntities ; num++ ) {
274 		es = &snap->entities[num];
275 		cent = &cg_entities[ es->number ];
276 
277 		memcpy( &cent->nextState, es, sizeof( entityState_t ) );
278 		//cent->nextState = *es;
279 
280 		// if this frame is a teleport, or the entity wasn't in the
281 		// previous frame, don't interpolate
282 		if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT )  ) {
283 			cent->interpolate = qfalse;
284 		} else {
285 			cent->interpolate = qtrue;
286 		}
287 	}
288 
289 	// if the next frame is a teleport for the playerstate, we
290 	// can't interpolate during demos
291 	if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
292 		cg.nextFrameTeleport = qtrue;
293 	} else {
294 		cg.nextFrameTeleport = qfalse;
295 	}
296 
297 	// if changing follow mode, don't interpolate
298 	if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {
299 		cg.nextFrameTeleport = qtrue;
300 	}
301 
302 	// if changing server restarts, don't interpolate
303 	if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
304 		cg.nextFrameTeleport = qtrue;
305 	}
306 
307 	// sort out solid entities
308 	CG_BuildSolidList();
309 }
310 
311 
312 /*
313 ========================
314 CG_ReadNextSnapshot
315 
316 This is the only place new snapshots are requested
317 This may increment cgs.processedSnapshotNum multiple
318 times if the client system fails to return a
319 valid snapshot.
320 ========================
321 */
CG_ReadNextSnapshot(void)322 static snapshot_t *CG_ReadNextSnapshot( void ) {
323 	qboolean r;
324 	snapshot_t  *dest;
325 
326 	if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {
327 		CG_Printf( "[skipnotify]WARNING: CG_ReadNextSnapshot: way out of range, %i > %i\n",
328 				   cg.latestSnapshotNum, cgs.processedSnapshotNum );
329 	}
330 
331 	while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {
332 		// decide which of the two slots to load it into
333 		if ( cg.snap == &cg.activeSnapshots[0] ) {
334 			dest = &cg.activeSnapshots[1];
335 		} else {
336 			dest = &cg.activeSnapshots[0];
337 		}
338 
339 		// try to read the snapshot from the client system
340 		cgs.processedSnapshotNum++;
341 		r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
342 
343 		// FIXME: why would trap_GetSnapshot return a snapshot with the same server time
344 		if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {
345 			//continue;
346 		}
347 
348 		// if it succeeded, return
349 		if ( r ) {
350 			CG_AddLagometerSnapshotInfo( dest );
351 // JPW NERVE pulled for MP, maybe this was the code that was causing crashes.  Shouldn't need it for savegame stuff
352 			// Ridah, savegame: we should use this as our new base snapshot
353 			// server has been restarted
354 			if ( cg.snap && ( dest->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
355 //				int i;
356 //				centity_t backupCent;
357 //				CG_SetInitialSnapshot( dest );
358 //				cg.nextFrameTeleport = qtrue;
359 				cg.damageTime = 0;
360 				cg.duckTime = -1;
361 				cg.landTime = -1;
362 				cg.stepTime = -1;
363 				// go through an reset the cent's
364 /* // JPW NERVE -- return NULL mighta been bad, q3ta doesn't include this stuff
365 				for ( i = 0; i < MAX_GENTITIES; i++ ) {
366 					backupCent = cg_entities[i];
367 					memset( &cg_entities[i], 0, sizeof( centity_t ) );
368 					cg_entities[i].currentState = backupCent.currentState;
369 					cg_entities[i].nextState = backupCent.nextState;
370 					cg_entities[i].currentValid = backupCent.currentValid;
371 					cg_entities[i].interpolate = backupCent.interpolate;
372 				}
373 				// reset the predicted cent
374 				backupCent = cg.predictedPlayerEntity;				// NERVE - SMF
375 				memset( &cg.predictedPlayerEntity, 0, sizeof( centity_t ) );
376 				cg.predictedPlayerEntity.currentState = backupCent.currentState;
377 				cg.predictedPlayerEntity.nextState = backupCent.nextState;
378 				cg.predictedPlayerEntity.currentValid = backupCent.currentValid;
379 				cg.predictedPlayerEntity.interpolate = backupCent.interpolate;
380 				return NULL;
381 // jpw */
382 			}
383 
384 			return dest;
385 		}
386 
387 		// a GetSnapshot will return failure if the snapshot
388 		// never arrived, or  is so old that its entities
389 		// have been shoved off the end of the circular
390 		// buffer in the client system.
391 
392 		// record as a dropped packet
393 		CG_AddLagometerSnapshotInfo( NULL );
394 
395 		// If there are additional snapshots, continue trying to
396 		// read them.
397 	}
398 
399 	// nothing left to read
400 	return NULL;
401 }
402 
403 
404 /*
405 ============
406 CG_ProcessSnapshots
407 
408 We are trying to set up a renderable view, so determine
409 what the simulated time is, and try to get snapshots
410 both before and after that time if available.
411 
412 If we don't have a valid cg.snap after exiting this function,
413 then a 3D game view cannot be rendered.  This should only happen
414 right after the initial connection.  After cg.snap has been valid
415 once, it will never turn invalid.
416 
417 Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
418 hasn't arrived yet (it becomes an extrapolating situation instead
419 of an interpolating one)
420 
421 ============
422 */
CG_ProcessSnapshots(void)423 void CG_ProcessSnapshots( void ) {
424 	snapshot_t      *snap;
425 	int n;
426 
427 	// see what the latest snapshot the client system has is
428 	trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
429 	if ( n != cg.latestSnapshotNum ) {
430 		if ( n < cg.latestSnapshotNum ) {
431 			// this should never happen
432 			CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
433 		}
434 		cg.latestSnapshotNum = n;
435 	}
436 
437 	// If we have yet to receive a snapshot, check for it.
438 	// Once we have gotten the first snapshot, cg.snap will
439 	// always have valid data for the rest of the game
440 	while ( !cg.snap ) {
441 		snap = CG_ReadNextSnapshot();
442 		if ( !snap ) {
443 			// we can't continue until we get a snapshot
444 			return;
445 		}
446 
447 		// set our weapon selection to what
448 		// the playerstate is currently using
449 		if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
450 			CG_SetInitialSnapshot( snap );
451 		}
452 	}
453 
454 	// loop until we either have a valid nextSnap with a serverTime
455 	// greater than cg.time to interpolate towards, or we run
456 	// out of available snapshots
457 	do {
458 		// if we don't have a nextframe, try and read a new one in
459 		if ( !cg.nextSnap ) {
460 			snap = CG_ReadNextSnapshot();
461 
462 			// if we still don't have a nextframe, we will just have to
463 			// extrapolate
464 			if ( !snap ) {
465 				break;
466 			}
467 
468 			CG_SetNextSnap( snap );
469 
470 			// if time went backwards, we have a level restart
471 			if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
472 				CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
473 			}
474 		}
475 
476 		// if our time is < nextFrame's, we have a nice interpolating state
477 		if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {
478 			break;
479 		}
480 
481 		// we have passed the transition from nextFrame to frame
482 		CG_TransitionSnapshot();
483 	} while ( 1 );
484 
485 	// assert our valid conditions upon exiting
486 	if ( cg.snap == NULL ) {
487 		CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
488 	}
489 	if ( cg.time < cg.snap->serverTime ) {
490 		// this can happen right after a vid_restart
491 		cg.time = cg.snap->serverTime;
492 	}
493 	if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
494 		CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
495 	}
496 
497 }
498