/* =============== V_SetupRefDef update refdef values each frame =============== */ void V_SetupRefDef( void ) { cl_entity_t *clent; clent = CL_GetLocalPlayer (); clgame.entities->curstate.scale = clgame.movevars.waveHeight; VectorCopy( cl.frame.local.client.punchangle, cl.refdef.punchangle ); clgame.viewent.curstate.modelindex = cl.frame.local.client.viewmodel; clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex ); clgame.viewent.curstate.entityType = ET_NORMAL; clgame.viewent.index = cl.playernum + 1; cl.refdef.movevars = &clgame.movevars; cl.refdef.onground = ( cl.frame.local.client.flags & FL_ONGROUND ) ? 1 : 0; cl.refdef.health = cl.frame.local.client.health; cl.refdef.playernum = cl.playernum; cl.refdef.max_entities = clgame.maxEntities; cl.refdef.maxclients = cl.maxclients; cl.refdef.time = cl.time; cl.refdef.frametime = cl.time - cl.oldtime; cl.refdef.demoplayback = cls.demoplayback; cl.refdef.smoothing = cl_smooth->integer; cl.refdef.waterlevel = cl.frame.local.client.waterlevel; cl.refdef.onlyClientDraw = 0; // reset clientdraw cl.refdef.viewsize = scr_viewsize->integer; cl.refdef.hardware = true; // always true cl.refdef.spectator = cl.spectator; cl.refdef.nextView = 0; // setup default viewport cl.refdef.viewport[0] = cl.refdef.viewport[1] = 0; cl.refdef.viewport[2] = scr_width->integer; cl.refdef.viewport[3] = scr_height->integer; // calc FOV cl.refdef.fov_x = cl.data.fov; // this is a final fov value cl.refdef.fov_y = V_CalcFov( &cl.refdef.fov_x, cl.refdef.viewport[2], cl.refdef.viewport[3] ); if( CL_IsPredicted( ) && !cl.refdef.demoplayback ) { VectorCopy( cl.predicted_origin, cl.refdef.simorg ); VectorCopy( cl.predicted_velocity, cl.refdef.simvel ); VectorCopy( cl.predicted_viewofs, cl.refdef.viewheight ); } else { VectorCopy( cl.frame.local.client.origin, cl.refdef.simorg ); VectorCopy( cl.frame.local.client.view_ofs, cl.refdef.viewheight ); VectorCopy( cl.frame.local.client.velocity, cl.refdef.simvel ); } }
/* =============== V_SetupRefDef update refdef values each frame =============== */ void V_SetupRefDef( void ) { cl_entity_t *clent; int size; int sb_lines; clent = CL_GetLocalPlayer (); clgame.entities->curstate.scale = clgame.movevars.waveHeight; VectorCopy( cl.frame.local.client.punchangle, cl.refdef.punchangle ); clgame.viewent.curstate.modelindex = cl.frame.local.client.viewmodel; clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex ); clgame.viewent.curstate.number = cl.playernum + 1; clgame.viewent.curstate.entityType = ET_NORMAL; clgame.viewent.index = cl.playernum + 1; cl.refdef.movevars = &clgame.movevars; cl.refdef.onground = ( cl.frame.local.client.flags & FL_ONGROUND ) ? 1 : 0; cl.refdef.health = cl.frame.local.client.health; cl.refdef.playernum = cl.playernum; cl.refdef.max_entities = clgame.maxEntities; cl.refdef.maxclients = cl.maxclients; cl.refdef.time = cl.time; cl.refdef.frametime = cl.time - cl.oldtime; cl.refdef.demoplayback = cls.demoplayback; cl.refdef.smoothing = cl_smooth->integer; cl.refdef.viewsize = scr_viewsize->integer; cl.refdef.waterlevel = cl.frame.local.client.waterlevel; cl.refdef.onlyClientDraw = 0; // reset clientdraw cl.refdef.hardware = true; // always true cl.refdef.spectator = (clent->curstate.spectator != 0); cl.refdef.nextView = 0; SCR_AddDirtyPoint( 0, 0 ); SCR_AddDirtyPoint( scr_width->integer - 1, scr_height->integer - 1 ); if( cl.refdef.viewsize >= 120 ) sb_lines = 0; // no status bar at all else if( cl.refdef.viewsize >= 110 ) sb_lines = 24; // no inventory else sb_lines = 48; size = min( scr_viewsize->integer, 100 ); cl.refdef.viewport[2] = scr_width->integer * size / 100; cl.refdef.viewport[3] = scr_height->integer * size / 100; if( cl.refdef.viewport[3] > scr_height->integer - sb_lines ) cl.refdef.viewport[3] = scr_height->integer - sb_lines; if( cl.refdef.viewport[3] > scr_height->integer ) cl.refdef.viewport[3] = scr_height->integer; cl.refdef.viewport[0] = (scr_width->integer - cl.refdef.viewport[2]) / 2; cl.refdef.viewport[1] = (scr_height->integer - sb_lines - cl.refdef.viewport[3]) / 2; // calc FOV cl.refdef.fov_x = cl.data.fov; // this is a final fov value cl.refdef.fov_y = V_CalcFov( &cl.refdef.fov_x, cl.refdef.viewport[2], cl.refdef.viewport[3] ); // adjust FOV for widescreen if( glState.wideScreen && r_adjust_fov->integer ) V_AdjustFov( &cl.refdef.fov_x, &cl.refdef.fov_y, cl.refdef.viewport[2], cl.refdef.viewport[3], false ); if( CL_IsPredicted( ) && !cl.refdef.demoplayback ) { VectorCopy( cl.predicted_origin, cl.refdef.simorg ); VectorCopy( cl.predicted_velocity, cl.refdef.simvel ); VectorCopy( cl.predicted_viewofs, cl.refdef.viewheight ); } else { VectorCopy( cl.frame.local.client.origin, cl.refdef.simorg ); VectorCopy( cl.frame.local.client.view_ofs, cl.refdef.viewheight ); VectorCopy( cl.frame.local.client.velocity, cl.refdef.simvel ); } }
/* ============= CL_ParseEvent ============= */ void CL_ParseEvent( sizebuf_t *msg ) { int event_index; int i, num_events; int packet_ent; event_args_t nullargs, args; qboolean has_update; entity_state_t *state; cl_entity_t *pEnt; float delay; Q_memset( &nullargs, 0, sizeof( nullargs )); num_events = BF_ReadUBitLong( msg, 5 ); // parse events queue for( i = 0 ; i < num_events; i++ ) { event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS ); Q_memset( &args, 0, sizeof( args )); has_update = false; if( BF_ReadOneBit( msg )) { packet_ent = BF_ReadUBitLong( msg, MAX_ENTITY_BITS ); if( BF_ReadOneBit( msg )) { MSG_ReadDeltaEvent( msg, &nullargs, &args ); has_update = true; } } else packet_ent = -1; if( packet_ent != -1 ) state = &cls.packet_entities[(cl.frame.first_entity+packet_ent)%cls.num_client_entities]; else state = NULL; // it's a client. Override some params if( args.entindex >= 1 && args.entindex <= cl.maxclients ) { if(( args.entindex - 1 ) == cl.playernum ) { if( state && !CL_IsPredicted( )) { // restore viewangles from angles args.angles[PITCH] = -state->angles[PITCH] * 3; args.angles[YAW] = state->angles[YAW]; args.angles[ROLL] = 0; // no roll } else { // get the predicted angles VectorCopy( cl.refdef.cl_viewangles, args.angles ); } VectorCopy( cl.frame.local.client.origin, args.origin ); VectorCopy( cl.frame.local.client.velocity, args.velocity ); } else if( state ) { // restore viewangles from angles args.angles[PITCH] = -state->angles[PITCH] * 3; args.angles[YAW] = state->angles[YAW]; args.angles[ROLL] = 0; // no roll // if we restore origin and velocity everytime, why don't do it here also? if( VectorIsNull( args.origin )) VectorCopy( state->origin, args.origin ); if( VectorIsNull( args.velocity )) VectorCopy( state->velocity, args.velocity ); } } else if( state ) { if( VectorIsNull( args.origin )) VectorCopy( state->origin, args.origin ); if( VectorIsNull( args.angles )) VectorCopy( state->angles, args.angles ); if( VectorIsNull( args.velocity )) VectorCopy( state->velocity, args.velocity ); } else if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL ) { if( VectorIsNull( args.origin )) VectorCopy( pEnt->curstate.origin, args.origin ); if( VectorIsNull( args.angles )) VectorCopy( pEnt->curstate.angles, args.angles ); if( VectorIsNull( args.velocity )) VectorCopy( pEnt->curstate.velocity, args.velocity ); } if( BF_ReadOneBit( msg )) delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f); else delay = 0.0f; // g-cont. should we need find the event with same index? CL_QueueEvent( 0, event_index, delay, &args ); } }
/* ================= CL_PredictMovement Sets cl.predicted_origin and cl.predicted_angles ================= */ void CL_PredictMovement( void ) { int frame = 1; int ack, outgoing_command; int current_command; int current_command_mod; cl_entity_t *player, *viewent; clientdata_t *cd; if( cls.state != ca_active ) return; if( cls.demoplayback && cl.refdef.cmd != NULL ) { // restore viewangles from cmd.angles VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles ); } if( cl.refdef.paused || cls.key_dest == key_menu ) return; player = CL_GetLocalPlayer (); viewent = CL_GetEntityByIndex( cl.refdef.viewentity ); cd = &cl.frame.local.client; // unpredicted pure angled values converted into axis AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up ); if( !CL_IsPredicted( )) { // run commands even if client predicting is disabled - client expected it clgame.pmove->runfuncs = true; CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand ); return; } ack = cls.netchan.incoming_acknowledged; outgoing_command = cls.netchan.outgoing_sequence; ASSERT( cl.refdef.cmd != NULL ); // setup initial pmove state CL_SetupPMove( clgame.pmove, cd, &player->curstate, cl.refdef.cmd ); clgame.pmove->runfuncs = false; while( 1 ) { // we've run too far forward if( frame >= CL_UPDATE_BACKUP - 1 ) break; // Incoming_acknowledged is the last usercmd the server acknowledged having acted upon current_command = ack + frame; current_command_mod = current_command & CL_UPDATE_MASK; // we've caught up to the current command. if( current_command >= outgoing_command ) break; clgame.pmove->cmd = cl.cmds[current_command_mod]; // motor! clgame.dllFuncs.pfnPlayerMove( clgame.pmove, false ); // run frames clgame.pmove->runfuncs = ( current_command > outgoing_command - 1 ) ? true : false; frame++; } CL_PostRunCmd( cl.refdef.cmd, frame ); // copy results out for rendering VectorCopy( clgame.pmove->view_ofs, cl.predicted_viewofs ); VectorCopy( clgame.pmove->origin, cl.predicted_origin ); VectorCopy( clgame.pmove->velocity, cl.predicted_velocity ); }
/* ================= CL_PredictMovement Sets cl.predicted_origin and cl.predicted_angles ================= */ void CL_PredictMovement( void ) { double time; int frame = 1; int ack, outgoing_command; int current_command; int current_command_mod; local_state_t *from = 0, *to = 0; if( cls.state != ca_active ) return; if( cls.demoplayback && cl.refdef.cmd != NULL ) { // restore viewangles from cmd.angles VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles ); } if( cl.refdef.paused || cls.key_dest == key_menu ) return; pfnSetUpPlayerPrediction( false, false ); // unpredicted pure angled values converted into axis AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up ); ASSERT( cl.refdef.cmd != NULL ); if( !cl_predict->integer || Host_IsLocalClient() ) { // fake prediction code // we need to perform cl_lw prediction while cl_predict is disabled // because cl_lw is enabled by default in Half-Life if( !cl_lw->integer ) return; ack = cls.netchan.incoming_acknowledged; outgoing_command = cls.netchan.outgoing_sequence; from = &cl.predict[cl.parsecountmod]; from->playerstate = cl.frame.playerstate[cl.playernum]; from->client = cl.frame.local.client; Q_memcpy( from->weapondata, cl.frame.local.weapondata, sizeof( from->weapondata )); time = cl.frame.time; while( 1 ) { // we've run too far forward if( frame >= CL_UPDATE_BACKUP - 1 ) break; // Incoming_acknowledged is the last usercmd the server acknowledged having acted upon current_command = ack + frame; current_command_mod = current_command & CL_UPDATE_MASK; // we've caught up to the current command. if( current_command >= outgoing_command ) break; to = &cl.predict[( cl.parsecountmod + frame ) & CL_UPDATE_MASK]; CL_FakeUsercmd( from, to, &cl.cmds[current_command_mod], cl.runfuncs[current_command_mod], &time, cls.netchan.incoming_acknowledged + frame ); cl.runfuncs[current_command_mod] = false; from = to; frame++; } if( to ) { cl.predicted_viewmodel = to->client.viewmodel; cl.scr_fov = to->client.fov; if( cl.scr_fov < 1.0f || cl.scr_fov> 170.0f ) cl.scr_fov = 90.0f; } return; } if( !CL_IsPredicted( )) { local_state_t t1, t2; Q_memset( &t1, 0, sizeof( local_state_t )); Q_memset( &t2, 0, sizeof( local_state_t )); clgame.dllFuncs.pfnPostRunCmd( &t1, &t2, cl.refdef.cmd, false, cl.time, cls.lastoutgoingcommand ); cl.scr_fov = t2.client.fov; if( cl.scr_fov < 1.0f || cl.scr_fov> 170.0f ) cl.scr_fov = 90.0f; return; } ack = cls.netchan.incoming_acknowledged; outgoing_command = cls.netchan.outgoing_sequence; from = &cl.predict[cl.parsecountmod]; from->playerstate = cl.frame.playerstate[cl.playernum]; from->client = cl.frame.local.client; Q_memcpy( from->weapondata, cl.frame.local.weapondata, sizeof( from->weapondata )); time = cl.frame.time; CL_SetSolidEntities (); CL_SetSolidPlayers ( cl.playernum ); while( 1 ) { // we've run too far forward if( frame >= CL_UPDATE_BACKUP - 1 ) break; // Incoming_acknowledged is the last usercmd the server acknowledged having acted upon current_command = ack + frame; current_command_mod = current_command & CL_UPDATE_MASK; // we've caught up to the current command. if( current_command >= outgoing_command ) break; to = &cl.predict[( cl.parsecountmod + frame ) & CL_UPDATE_MASK]; CL_RunUsercmd( from, to, &cl.cmds[current_command_mod], cl.runfuncs[current_command_mod], &time, cls.netchan.incoming_acknowledged + frame ); cl.runfuncs[current_command_mod] = false; from = to; frame++; } if( to ) { cl.predicted_viewmodel = to->client.viewmodel; cl.scr_fov = to->client.fov; if( cl.scr_fov < 1.0f || cl.scr_fov> 170.0f ) cl.scr_fov = 90.0f; VectorCopy( to->playerstate.origin, cl.predicted_origin ); VectorCopy( to->client.velocity, cl.predicted_velocity ); VectorCopy( to->client.view_ofs, cl.predicted_viewofs ); VectorCopy( to->client.punchangle, cl.predicted_punchangle ); } }
/* ================= CL_PredictMovement Sets cl.predicted_origin and cl.predicted_angles ================= */ void CL_PredictMovement() { int frame; int ack, outgoing_command; int current_command; int current_command_mod; cl_entity_t *player, *viewent; clientdata_t *cd; if( cls.state != ca_active ) return; if( cls.demoplayback && cl.refdef.cmd != NULL ) VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles ); // restore viewangles from cmd.angles if(cl.refdef.paused /*|| cls.key_dest == key_menu*/) //return; player = CL_GetLocalPlayer (); viewent = CL_GetEntityByIndex( cl.refdef.viewentity ); cd = &cl.frame.local.client; // unpredicted pure angled values converted into axis AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up ); if( !CL_IsPredicted( )) { // run commands even if client predicting is disabled - client expect it clgame.pmove->runfuncs = true; CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand ); return; }; ack = cls.netchan.incoming_acknowledged; outgoing_command = cls.netchan.outgoing_sequence; // if we are too far out of date, just freeze if(outgoing_command - ack >= CL_UPDATE_BACKUP) { //if(cl_showmiss->value) //Com_Printf ("exceeded CL_UPDATE_BACKUP\n"); return; }; ASSERT( cl.refdef.cmd != NULL ); // setup initial pmove state CL_SetupPMove( clgame.pmove, cd, &player->curstate, cl.refdef.cmd ); clgame.pmove->runfuncs = false; frame = 0; while(++ack < outgoing_command) { // we've run too far forward //if( frame >= CL_UPDATE_BACKUP - 1 ) // break; frame = ack & (CL_UPDATE_BACKUP - 1); // Incoming_acknowledged is the last usercmd the server acknowledged having acted upon current_command = ack + frame; current_command_mod = current_command & CL_UPDATE_MASK; // we've caught up to the current command // this was the most up to date command if(current_command >= outgoing_command) break; clgame.pmove->cmd = cl.cmds[current_command_mod]; // Call the client dll player movement function (and it will call the PM_Move()) clgame.dllFuncs.pfnPlayerMove(clgame.pmove, false); // run frames clgame.pmove->runfuncs = ( current_command > outgoing_command - 1 ) ? true : false; // Prevent to play sounds/etc more that once frame++; }; CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand ); // copy results out for rendering VectorCopy( clgame.pmove->view_ofs, cl.predicted_viewofs ); VectorCopy( clgame.pmove->origin, cl.predicted_origin ); VectorCopy( clgame.pmove->velocity, cl.predicted_velocity ); };