21 Jun 2010

This commit is contained in:
g-cont 2010-06-21 00:00:00 +04:00 committed by Alibek Omarov
parent 5caebac360
commit c593e56413
33 changed files with 678 additions and 804 deletions

View File

@ -7,6 +7,10 @@
#include "client.h"
#include "byteorder.h"
#define dem_cmd 0
#define dem_read 1
#define dem_set 2
/*
====================
CL_WriteDemoMessage
@ -153,8 +157,9 @@ void CL_DrawDemoRecording( void )
char string[1024];
fs_offset_t pos;
if(!(host.developer && cls.demorecording))
if(!( host.developer && cls.demorecording ))
return;
pos = FS_Tell( cls.demofile );
com.sprintf( string, "RECORDING %s: %ik", cls.demoname, pos / 1024 );
SCR_DrawBigStringColor( 320 - com.strlen( string ) * 8, 80, string, g_color_table[7] );
@ -240,7 +245,7 @@ void CL_ReadDemoMessage( void )
return;
// don't need another message yet
if( cl.time <= cl.frame.servertime )
if( cl.time <= cl.mtime[0] )
return;
// init the message
@ -275,7 +280,7 @@ void CL_ReadDemoMessage( void )
return;
}
cls.connect_time = cls.realtime;
cls.connect_time = host.realtime;
buf.readcount = 0;
CL_ParseServerMessage( &buf );
}

View File

@ -52,13 +52,10 @@ void CL_RunLightStyles( void )
if( cls.state != ca_active ) return;
if( cl_lightstyle_lerping->integer )
ofs = (cl.time * 10);
if( !cl_lightstyle_lerping->integer )
{
ofs = cl.frame.servertime / 100;
}
else
{
ofs = cl.time / 100;
if( ofs == lastofs ) return;
lastofs = ofs;
}
@ -142,7 +139,7 @@ typedef struct
// cdlight_t private starts here
int key; // so entities can reuse same entry
int start; // stop lighting after this time
float start; // stop lighting after this time
int end; // drop this each second
float radius; // radius (not an intensity)
bool fade;
@ -242,7 +239,7 @@ void CL_AddDLight( const float *org, const float *rgb, float radius, float time,
VectorCopy( rgb, dl->color );
dl->radius = radius;
dl->start = cl.time;
dl->end = dl->start + (time * 1000);
dl->end = dl->start + time;
dl->fade = (flags & DLIGHT_FADE) ? true : false;
}
@ -280,7 +277,7 @@ void CL_AddDLights( void )
if( dl->fade )
{
dl->intensity = (float)(cl.time - dl->start) / (dl->end - dl->start);
dl->intensity = dl->radius * (1.0 - dl->intensity);
dl->intensity = dl->radius * (1.0f - dl->intensity);
}
else dl->intensity = dl->radius; // const
@ -458,7 +455,7 @@ void CL_AddParticles( void )
VectorScale( cl.refdef.right, scale, right );
VectorScale( cl.refdef.up, scale, up );
frametime = cls.frametime;
frametime = cl.time - cl.oldtime;
time3 = frametime * 15;
time2 = frametime * 10; // 15;
time1 = frametime * 5;

View File

@ -67,10 +67,9 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
if( ent->free ) CL_InitEdict( ent );
// some data changes will force no lerping
if( state->ed_flags & ESF_NODELTA ) ent->pvClientData->serverframe = -99;
if( newent ) state->ed_flags |= ESF_LINKEDICT; // need to relink
if( ent->pvClientData->serverframe != cl.frame.serverframe - 1 )
if( state->ed_flags & ESF_NODELTA )
{
// duplicate the current state so lerping doesn't hurt anything
ent->pvClientData->prev = *state;
@ -79,8 +78,6 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
{ // shuffle the last state to previous
ent->pvClientData->prev = ent->pvClientData->current;
}
ent->pvClientData->serverframe = cl.frame.serverframe;
ent->pvClientData->current = *state;
}
@ -92,11 +89,65 @@ An svc_packetentities has just been parsed, deal with the
rest of the data stream.
==================
*/
void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newframe )
void CL_ParsePacketEntities( sizebuf_t *msg, bool delta )
{
int newnum;
int newnum, framenum;
entity_state_t *oldstate;
int oldindex, oldnum;
frame_t *oldframe, *newframe;
int old_sequence;
Mem_Set( &cl.frame, 0, sizeof( cl.frame ));
framenum = cls.netchan.incoming_sequence & CL_UPDATE_MASK;
cl.frame = cl.frames[framenum];
newframe = &cl.frame;
if( delta )
{
int new_sequence;
new_sequence = MSG_ReadByte( msg );
old_sequence = cl.frames[framenum].delta_sequence;
if(( new_sequence & CL_UPDATE_MASK ) != ( old_sequence & CL_UPDATE_MASK ))
MsgDev( D_WARN, "CL_ParsePacketEntities: mismatch delta sequence\n" );
}
else old_sequence = -1;
if( old_sequence != -1 )
{
cl.validsequence = cls.netchan.incoming_sequence;
cl.oldframe = oldframe = &cl.frames[old_sequence & CL_UPDATE_MASK];
if( !cl.oldframe->valid )
{
// should never happen
MsgDev( D_WARN, "delta from invalid frame (not supposed to happen!)\n" );
}
if( cls.netchan.outgoing_sequence - old_sequence >= CL_UPDATE_BACKUP - 1 )
{
// The frame that the server did the delta from
// is too old, so we can't reconstruct it properly.
MsgDev( D_WARN, "delta frame too old\n" );
cl.validsequence = 0; // can't render a frame
}
else if( cl.parse_entities - cl.oldframe->parse_entities > MAX_PARSE_ENTITIES - 128 )
{
MsgDev( D_INFO, "delta parse_entities too old\n" );
cl.validsequence = 0; // can't render a frame
}
else cl.frame.valid = true; // valid delta parse
}
else
{
// this is a full update that we can start delta compressing from now
cl.validsequence = cls.netchan.incoming_sequence;
cls.demowaiting = false; // we can start recording now
cl.frame.valid = true; // uncompressed frame
cl.oldframe = oldframe = NULL;
}
newframe->parse_entities = cl.parse_entities;
newframe->num_entities = 0;
@ -104,7 +155,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram
// delta from the entities present in oldframe
oldindex = 0;
oldstate = NULL;
if( !oldframe ) oldnum = MAX_ENTNUMBER;
if( !oldframe )
{
oldnum = MAX_ENTNUMBER;
}
else
{
if( oldindex >= oldframe->num_entities )
@ -191,70 +245,9 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram
oldnum = oldstate->number;
}
}
}
/*
================
CL_ParseFrame
================
*/
void CL_ParseFrame( sizebuf_t *msg )
{
int cmd, client_idx;
edict_t *clent;
Mem_Set( &cl.frame, 0, sizeof( cl.frame ));
cl.frame.serverframe = MSG_ReadLong( msg );
cl.frame.servertime = MSG_ReadLong( msg );
cl.serverframetime = MSG_ReadLong( msg );
cl.frame.deltaframe = MSG_ReadLong( msg );
cl.surpressCount = MSG_ReadByte( msg );
client_idx = MSG_ReadByte( msg );
// read clientindex
clent = EDICT_NUM( client_idx ); // get client
if(( client_idx - 1 ) != cl.playernum )
Host_Error( "CL_ParseFrame: invalid playernum (%d should be %d)\n", client_idx - 1, cl.playernum );
// If the frame is delta compressed from data that we
// no longer have available, we must suck up the rest of
// the frame, but not use it, then ask for a non-compressed
// message
if( cl.frame.deltaframe <= 0 )
{
cl.frame.valid = true; // uncompressed frame
cls.demowaiting = false; // we can start recording now
cl.oldframe = NULL;
}
else
{
cl.oldframe = &cl.frames[cl.frame.deltaframe & CL_UPDATE_MASK];
if( !cl.oldframe->valid )
{
// should never happen
MsgDev( D_INFO, "delta from invalid frame (not supposed to happen!)\n" );
}
if( cl.oldframe->serverframe != cl.frame.deltaframe )
{
// The frame that the server did the delta from
// is too old, so we can't reconstruct it properly.
MsgDev( D_INFO, "delta frame too old\n" );
}
else if( cl.parse_entities - cl.oldframe->parse_entities > MAX_PARSE_ENTITIES - 128 )
{
MsgDev( D_INFO, "delta parse_entities too old\n" );
}
else cl.frame.valid = true; // valid delta parse
}
// read packet entities
cmd = MSG_ReadByte( msg );
if( cmd != svc_packetentities ) Host_Error("CL_ParseFrame: not packetentities[%d]\n", cmd );
CL_ParsePacketEntities( msg, cl.oldframe, &cl.frame );
// save the frame off in the backup array for later delta comparisons
cl.frames[cl.frame.serverframe & CL_UPDATE_MASK] = cl.frame;
cl.frames[framenum & CL_UPDATE_MASK] = cl.frame;
if( !cl.frame.valid ) return;

View File

@ -88,7 +88,7 @@ don't clamped time that come from server
*/
int CL_GetServerTime( void )
{
return cl.frame.servertime;
return cl.mtime[0];
}
/*
@ -195,7 +195,7 @@ void CL_FadeAlpha( int starttime, int endtime, rgba_t color )
return;
}
time = cls.realtime - starttime;
time = (host.realtime * 1000) - starttime; // FIXME; convert it to float properly
if( time >= endtime )
{
@ -280,7 +280,7 @@ void CL_CenterPrint( const char *text, int y, int charWidth )
char *s;
com.strncpy( clgame.ds.centerPrint, text, sizeof( clgame.ds.centerPrint ));
clgame.ds.centerPrintTime = cls.realtime;
clgame.ds.centerPrintTime = host.realtime * 1000;
clgame.ds.centerPrintCharWidth = charWidth;
clgame.ds.centerPrintY = y;
@ -528,7 +528,7 @@ void CL_DrawHUD( int state )
if( state == CL_ACTIVE && cl.refdef.paused )
state = CL_PAUSED;
clgame.dllFuncs.pfnRedraw( cl.time * 0.001f, state );
clgame.dllFuncs.pfnRedraw( cl.time, state );
if( state == CL_ACTIVE || state == CL_PAUSED )
{
@ -745,7 +745,7 @@ void CL_FreeEdict( edict_t *pEdict )
Mem_Set( pEdict, 0, sizeof( *pEdict ));
// mark edict as freed
pEdict->freetime = cl.time * 0.001f;
pEdict->freetime = cl.time;
pEdict->v.nextthink = -1;
pEdict->free = true;
}
@ -760,7 +760,7 @@ edict_t *CL_AllocEdict( void )
pEdict = EDICT_NUM( i );
// the first couple seconds of client time can involve a lot of
// freeing and allocating, so relax the replacement policy
if( pEdict->free && ( pEdict->freetime < 2.0f || ((cl.time * 0.001f) - pEdict->freetime) > 0.5f ))
if( pEdict->free && ( pEdict->freetime < 2.0 || ( cl.time - pEdict->freetime ) > 0.5 ))
{
CL_InitEdict( pEdict );
return pEdict;
@ -1616,7 +1616,7 @@ pfnGetClientTime
*/
static float pfnGetClientTime( void )
{
return cl.time * 0.001f;
return cl.time;
}
/*

View File

@ -10,10 +10,10 @@
cvar_t *rcon_client_password;
cvar_t *rcon_address;
cvar_t *cl_smooth;
cvar_t *cl_timeout;
cvar_t *cl_predict;
cvar_t *cl_showfps;
cvar_t *cl_maxfps;
cvar_t *cl_nodelta;
cvar_t *cl_crosshair;
cvar_t *cl_shownet;
@ -51,6 +51,11 @@ bool CL_IsInGame( void )
return ( cls.key_dest == key_game ); // active if not menu or console
}
bool CL_IsPlaybackDemo( void )
{
return cls.demoplayback;
}
void CL_ForceVid( void )
{
cl.video_prepped = false;
@ -62,6 +67,57 @@ void CL_ForceSnd( void )
cl.audio_prepped = false;
}
/*
===============
CL_LerpPoint
Determines the fraction between the last two messages that the objects
should be put at.
===============
*/
static float CL_LerpPoint( void )
{
float f, frac;
f = cl.mtime[0] - cl.mtime[1];
if( !f || SV_Active( ))
{
cl.time = cl.mtime[0];
return 1.0f;
}
if( f > 0.1f )
{
// dropped packet, or start of demo
cl.mtime[1] = cl.mtime[0] - 0.1f;
f = 0.1f;
}
frac = ( cl.time - cl.mtime[1] ) / f;
if( frac < 0 )
{
if( frac < -0.01f )
{
cl.time = cl.mtime[1];
Msg( "low frac\n" );
}
frac = 0.0f;
}
else if( frac > 1.0f )
{
if( frac > 1.01f )
{
cl.time = cl.mtime[0];
Msg( "high frac\n" );
}
frac = 1.0f;
}
return frac;
}
/*
=======================================================================
@ -224,7 +280,7 @@ void CL_CheckForResend( void )
if( cls.demoplayback || cls.state != ca_connecting )
return;
if(( cls.realtime - cls.connect_time ) < 3000 )
if(( host.realtime - cls.connect_time ) < 3.0 )
return;
if( !NET_StringToAdr( cls.servername, &adr ))
@ -235,7 +291,7 @@ void CL_CheckForResend( void )
}
if( adr.port == 0 ) adr.port = BigShort( PORT_SERVER );
cls.connect_time = cls.realtime; // for retransmit requests
cls.connect_time = host.realtime; // for retransmit requests
MsgDev( D_NOTE, "Connecting to %s...\n", cls.servername );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
@ -536,7 +592,7 @@ void CL_Reconnect_f( void )
if( cls.state >= ca_connected )
{
CL_Disconnect();
cls.connect_time = cls.realtime - 1500;
cls.connect_time = host.realtime - 1.5;
}
else cls.connect_time = MAX_HEARTBEAT; // fire immediately
@ -793,10 +849,7 @@ void CL_ReadPackets( void )
CL_ReadDemoMessage();
else CL_ReadNetMessage();
cl.time = bound( cl.frame.servertime - cl.serverframetime, cl.time, cl.frame.servertime );
if( cl.refdef.paused ) cl.lerpFrac = 1.0f;
else cl.lerpFrac = 1.0 - (cl.frame.servertime - cl.time) / (float)cl.serverframetime;
cl.lerpFrac = CL_LerpPoint();
// singleplayer never has connection timeout
if( NET_IsLocalAddress( cls.netchan.remote_address ))
@ -805,7 +858,7 @@ void CL_ReadPackets( void )
// check timeout
if( cls.state >= ca_connected && !cls.demoplayback )
{
if( cls.realtime - cls.netchan.last_received > (cl_timeout->value * 1000))
if( host.realtime - cls.netchan.last_received > cl_timeout->value )
{
if( ++cl.timeoutcount > 5 ) // timeoutcount saves debugger
{
@ -1010,7 +1063,6 @@ void CL_InitLocal( void )
// register our variables
cl_predict = Cvar_Get( "cl_predict", "1", CVAR_ARCHIVE, "disables client movement prediction" );
cl_maxfps = Cvar_Get( "cl_maxfps", "1000", 0, "maximum client fps" );
cl_crosshair = Cvar_Get( "crosshair", "1", CVAR_ARCHIVE|CVAR_USERINFO, "show weapon chrosshair" );
cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for usercommnds" );
@ -1033,6 +1085,7 @@ void CL_InitLocal( void )
cl_showfps = Cvar_Get( "cl_showfps", "1", CVAR_ARCHIVE, "show client fps" );
cl_lw = Cvar_Get( "cl_lw", "1", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" );
cl_lightstyle_lerping = Cvar_Get( "cl_lightstyle_lerping", "0", CVAR_ARCHIVE, "enables animated light lerping (perfomance option)" );
cl_smooth = Cvar_Get ("cl_smooth", "1", 0, "smooth up stair climbing and interpolate position in multiplayer" );
// register our commands
Cmd_AddCommand ("cmd", CL_ForwardToServer_f, "send a console commandline to the server" );
@ -1076,48 +1129,6 @@ void CL_InitLocal( void )
}
//============================================================================
/*
==================
CL_ApplyAddAngle
==================
*/
void CL_ApplyAddAngle( void )
{
float frametime = (cl.serverframetime * 0.001f);
float amove = 0.0f;
int i;
for( i = 0; i < CMD_MASK; i++ )
{
add_angle_t *add = &cl.addangle[i];
float f, remainder = fabs( add->yawdelta - add->accum );
float amount_to_add;
if( remainder <= 0.0001f )
continue; // this angle expired
// apply some of the delta
f = frametime;
f = bound( 0.0f, f, 1.0f );
amount_to_add = f * add->yawdelta;
if( add->yawdelta > 0.0f )
{
amount_to_add = min( amount_to_add, remainder );
}
else
{
amount_to_add = max( amount_to_add, -remainder );
}
add->accum += amount_to_add;
amove += amount_to_add;
}
cl.refdef.cl_viewangles[1] += amove;
}
/*
==================
@ -1136,23 +1147,18 @@ void CL_SendCommand( void )
/*
==================
CL_Frame
Host_ClientFrame
==================
*/
void CL_Frame( int time )
void Host_ClientFrame( void )
{
if( host.type == HOST_DEDICATED )
return;
// if client is not active, do nothing
if( !cls.initialized ) return;
// decide the simulation time
cl.time += time; // can be merged by cl.frame.servertime
cls.realtime += time;
cls.frametime = time * 0.001f;
if( cls.frametime > 0.2f ) cls.frametime = 0.2f;
// if in the debugger last frame, don't timeout
if( time > 5000 ) cls.netchan.last_received = Sys_Milliseconds();
cl.oldtime = cl.time;
cl.time += host.frametime;
// fetch results from server
CL_ReadPackets();
@ -1163,9 +1169,6 @@ void CL_Frame( int time )
// predict all unacknowledged movements
CL_PredictMovement();
// apply accumulated angles
CL_ApplyAddAngle();
Host_CheckChanges();
// allow sound and video DLL change
@ -1229,7 +1232,6 @@ void CL_Shutdown( void )
{
// already freed
if( host.state == HOST_ERROR ) return;
if( host.type == HOST_DEDICATED ) return;
if( !cls.initialized ) return;
Host_WriteConfig();

View File

@ -16,6 +16,12 @@ bool CL_IsPredicted( void )
if( !player )
return false;
if( !cl.validsequence )
return false;
if( cls.netchan.outgoing_sequence - cls.netchan.incoming_sequence >= CL_UPDATE_BACKUP - 1 )
return false;
if( player->pvClientData->current.ed_flags & ESF_NO_PREDICTION )
return false;
if( !cl_predict->integer )
@ -31,7 +37,6 @@ CL_CreateCmd
usercmd_t CL_CreateCmd( void )
{
usercmd_t cmd;
static double extramsec = 0;
int ms;
// catch windowState for client.dll
@ -51,9 +56,7 @@ usercmd_t CL_CreateCmd( void )
}
// send milliseconds of time to apply the move
extramsec += cls.frametime * 1000;
ms = extramsec;
extramsec -= ms; // fractional part is left for next frame
ms = ( cl.time - cl.oldtime ) * 1000;
if( ms > 250 ) ms = 100; // time was unreasonable
Mem_Set( &cmd, 0, sizeof( cmd ));
@ -100,7 +103,7 @@ void CL_WritePacket( void )
if( cls.state == ca_connected )
{
// just update reliable
if( cls.netchan.message.cursize || cls.realtime - cls.netchan.last_sent > 1000 )
if( cls.netchan.message.cursize )
Netchan_Transmit( &cls.netchan, 0, NULL );
return;
}
@ -122,12 +125,6 @@ void CL_WritePacket( void )
key = buf.cursize;
MSG_WriteByte( &buf, 0 );
// let the server know what the last frame we
// got was, so the next message can be delta compressed
if( cl_nodelta->integer || !cl.frame.valid || cls.demowaiting )
MSG_WriteLong( &buf, -1 ); // no compression
else MSG_WriteLong( &buf, cl.frame.serverframe );
// send this and the previous cmds in the message, so
// if the last packet was dropped, it can be recovered
cmd = &cl.cmds[(cls.netchan.outgoing_sequence - 2) & CMD_MASK];
@ -145,6 +142,18 @@ void CL_WritePacket( void )
// calculate a checksum over the move commands
buf.data[key] = CRC_Sequence( buf.data + key + 1, buf.cursize - key - 1, cls.netchan.outgoing_sequence );
// request delta compression of entities
if( cls.netchan.outgoing_sequence - cl.validsequence >= CL_UPDATE_BACKUP - 1 )
cl.validsequence = 0;
if( cl.validsequence && !cl_nodelta->integer && !cls.demowaiting )
{
cl.frames[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].delta_sequence = cl.validsequence;
MSG_WriteByte( &buf, clc_delta );
MSG_WriteByte( &buf, cl.validsequence & 255 );
}
else cl.frames[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].delta_sequence = -1;
// deliver the message
Netchan_Transmit( &cls.netchan, buf.cursize, buf.data );
}
@ -158,6 +167,8 @@ Called every frame to builds and sends a command packet to the server.
*/
void CL_SendCmd( void )
{
if( host.type == HOST_DEDICATED ) return;
// we create commands even if a demo is playing,
cl.refdef.cmd = &cl.cmds[cls.netchan.outgoing_sequence & CMD_MASK];
*cl.refdef.cmd = CL_CreateCmd();
@ -303,6 +314,17 @@ static chull_t *PM_HullForBsp( edict_t *ent, float *offset )
return CM_HullForBsp( ent, clgame.pmove->player->v.mins, clgame.pmove->player->v.maxs, offset );
}
static void PM_CheckMovingGround( edict_t *ent, float frametime )
{
if(!( ent->v.flags & FL_BASEVELOCITY ))
{
// apply momentum (add in half of the previous frame of velocity first)
VectorMA( ent->v.velocity, 1.0f + (frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
VectorClear( ent->v.basevelocity );
}
ent->v.flags &= ~FL_BASEVELOCITY;
}
static void PM_SetupMove( playermove_t *pmove, edict_t *clent, usercmd_t *ucmd, const char *physinfo )
{
edict_t *hit, *touch[MAX_EDICTS];
@ -316,6 +338,8 @@ static void PM_SetupMove( playermove_t *pmove, edict_t *clent, usercmd_t *ucmd,
pmove->realtime = clgame.globals->time;
com.strncpy( pmove->physinfo, physinfo, MAX_INFO_STRING );
pmove->clientmaxspeed = clent->v.maxspeed;
pmove->bInDuck = (ucmd->buttons & IN_DUCK) ? 1 : 0; // reset hull
pmove->usehull = (clent->v.flags & FL_DUCKING) ? 1 : 0; // reset hull
pmove->cmd = *ucmd; // setup current cmds
pmove->player = clent; // ptr to client state
@ -429,23 +453,9 @@ CL_RunCmd
*/
void CL_RunCmd( edict_t *clent, usercmd_t *ucmd )
{
int oldmsec;
static usercmd_t cmd;
if( !CL_IsValidEdict( clent )) return;
cmd = *ucmd;
if( !clent ) return;
// chop up very long commands
if( cmd.msec > 50 )
{
oldmsec = ucmd->msec;
cmd.msec = oldmsec / 2;
CL_RunCmd( clent, &cmd );
cmd.msec = oldmsec / 2;
cmd.impulse = 0;
CL_RunCmd( clent, &cmd );
return;
}
PM_CheckMovingGround( clent, ucmd->msec * 0.001f );
// VectorCopy( ucmd->viewangles, clgame.pmove->oldangles ); // save oldangles
// if( !clent->v.fixangle ) VectorCopy( ucmd->viewangles, clent->v.viewangles );
@ -518,8 +528,7 @@ void CL_CheckPredictionError( void )
}
else
{
if( cl_showmiss->integer && flen > 0.5f )
Msg( "prediction miss on %i: %g\n", cl.frame.serverframe, flen );
if( cl_showmiss->integer && flen > 0.1f ) Msg( "prediction miss: %g\n", flen );
VectorCopy( player->pvClientData->current.origin, cl.predicted_origins[frame] );
// save for error itnerpolation
@ -537,10 +546,8 @@ Sets cl.predicted_origin and cl.predicted_angles
void CL_PredictMovement( void )
{
int frame;
int oldframe;
int ack, current;
edict_t *player, *viewent;
float step, oldstep, oldz;
usercmd_t *cmd;
if( cls.state != ca_active ) return;
@ -607,20 +614,6 @@ void CL_PredictMovement( void )
VectorCopy( clgame.pmove->origin, cl.predicted_origins[frame] );
}
oldframe = (ack - 2) & CMD_MASK;
oldz = cl.predicted_origins[oldframe][2];
step = clgame.pmove->origin[2] - oldz;
if( player->v.flags & FL_ONGROUND && step > 0 && step < clgame.movevars.stepsize )
{
if( cls.realtime - cl.predicted_step_time < 150 )
oldstep = cl.predicted_step * (150 - (cls.realtime - cl.predicted_step_time)) * (1.0f/150.0f);
else oldstep = 0.0f;
cl.predicted_step = oldstep + step;
cl.predicted_step_time = cls.realtime - cls.frametime * 500;
}
// copy results out for rendering
VectorCopy( player->v.view_ofs, cl.predicted_viewofs );
VectorCopy( clgame.pmove->origin, cl.predicted_origin );

View File

@ -27,7 +27,8 @@ char *svc_strings[256] =
"svc_changing",
"svc_physinfo",
"svc_packetentities",
"svc_frame",
"svc_deltapacketentities",
"svc_time",
"svc_sound",
"svc_ambientsound",
"svc_setangle",
@ -43,7 +44,8 @@ char *svc_strings[256] =
"svc_bspdecal",
"svc_event",
"svc_event_reliable",
"svc_serverinfo"
"svc_serverinfo",
"svc_chokecount"
};
typedef struct
@ -667,32 +669,14 @@ add the view angle yaw
*/
void CL_ParseAddAngle( sizebuf_t *msg )
{
float ang_total;
float ang_final;
float apply_now;
add_angle_t *a;
float add_angle;
ang_total = MSG_ReadAngle32( msg );
ang_final = MSG_ReadAngle32( msg );
add_angle = MSG_ReadAngle32( msg );
if( ang_total > 180.0f )
{
ang_total -= 360.0f;
}
if( add_angle > 180.0f )
add_angle -= 360.0f;
if( ang_final > 180.0f )
{
ang_final -= 360.0f;
}
// apply this angle after prediction
a = &cl.addangle[(cl.frame.serverframe) & CMD_MASK];
a->yawdelta = ang_final;
a->accum = 0.0f;
apply_now = ang_total - ang_final;
cl.refdef.cl_viewangles[1] += apply_now;
cl.refdef.cl_viewangles[1] += add_angle;
}
/*
================
@ -770,7 +754,7 @@ CL_ParseServerMessage
void CL_ParseServerMessage( sizebuf_t *msg )
{
char *s;
int i, cmd;
int i, j, cmd;
int bufStart;
cls_message_debug.parsing = true; // begin parsing
@ -856,6 +840,11 @@ void CL_ParseServerMessage( sizebuf_t *msg )
case svc_physinfo:
com.strncpy( cl.physinfo, MSG_ReadString( msg ), sizeof( cl.physinfo ));
break;
case svc_chokecount:
i = MSG_ReadByte( msg );
for( j = 0; j < i; j++ )
cl.frames[(cls.netchan.incoming_acknowledged-1-j) & CL_UPDATE_MASK].recv_time = -2;
break;
case svc_print:
i = MSG_ReadByte( msg );
if( i == PRINT_CHAT ) // chat
@ -892,11 +881,15 @@ void CL_ParseServerMessage( sizebuf_t *msg )
case svc_serverinfo:
CL_ServerInfo( msg );
break;
case svc_frame:
CL_ParseFrame( msg );
case svc_time:
cl.mtime[1] = cl.mtime[0];
cl.mtime[0] = MSG_ReadFloat( msg );
break;
case svc_packetentities:
Host_Error( "CL_ParseServerMessage: out of place frame data\n" );
CL_ParsePacketEntities( msg, false );
break;
case svc_deltapacketentities:
CL_ParsePacketEntities( msg, true );
break;
case svc_bad:
Host_Error( "CL_ParseServerMessage: svc_bad\n" );

View File

@ -432,7 +432,7 @@ void SCR_UpdateScreen( void )
}
if( clgame.hInstance )
clgame.dllFuncs.pfnFrame( cl.time * 0.001f );
clgame.dllFuncs.pfnFrame( cl.time );
}
void SCR_RegisterShaders( void )

View File

@ -44,10 +44,10 @@ void V_SetupRefDef( void )
cl.refdef.num_entities = clgame.globals->numEntities;
cl.refdef.max_entities = clgame.globals->maxEntities;
cl.refdef.maxclients = clgame.globals->maxClients;
cl.refdef.time = cl.time * 0.001f;
cl.refdef.frametime = cls.frametime;
cl.refdef.time = cl.time;
cl.refdef.frametime = cl.time - cl.oldtime;
cl.refdef.demoplayback = cls.demoplayback;
cl.refdef.smoothing = CL_IsPredicted() ? false : true;
cl.refdef.smoothing = cl_smooth->integer;
cl.refdef.waterlevel = clent->v.waterlevel;
cl.refdef.flags = cl.render_flags;
cl.refdef.viewsize = 120; // FIXME if you can
@ -57,19 +57,14 @@ void V_SetupRefDef( void )
if( CL_IsPredicted( ) && !cl.refdef.demoplayback )
{
// use predicted values
uint i, delta;
float backlerp = 1.0f - cl.lerpFrac;
int i;
for( i = 0; i < 3; i++ )
{
cl.refdef.simorg[i] = cl.predicted_origin[i] - backlerp * cl.prediction_error[i];
cl.refdef.viewheight[i] = cl.predicted_viewofs[i] - backlerp * cl.prediction_error[i];
}
// smooth out stair climbing
delta = cls.realtime - cl.predicted_step_time;
if( delta < 150 )
cl.refdef.simorg[2] -= cl.predicted_step * (150 - delta) / 150;
VectorCopy( cl.predicted_velocity, cl.refdef.simvel );
}
else
@ -125,8 +120,8 @@ void V_RenderView( void )
if( !cl.video_prepped ) return; // still loading
// update cl_globalvars
clgame.globals->time = cl.time * 0.001f; // clamped
clgame.globals->frametime = cls.frametime; // used by input code
clgame.globals->time = cl.time; // clamped
clgame.globals->frametime = cl.time - cl.oldtime; // used by input code
if( cl.frame.valid && (cl.force_refdef || !cl.refdef.paused ))
{
@ -188,7 +183,7 @@ void V_PostRender( void )
SCR_RSpeeds();
SCR_DrawNet();
SCR_DrawFPS();
UI_UpdateMenu( cls.realtime );
UI_UpdateMenu( host.realtime * 1000 ); // FIXME: convert time to double properly
Con_DrawConsole();
}
SCR_MakeScreenShot();

View File

@ -20,13 +20,6 @@
#define STRING( offset ) CL_GetString( offset )
#define MAKE_STRING(str) CL_AllocString( str )
// add angles
typedef struct
{
float yawdelta;
float accum;
} add_angle_t;
// console stuff
typedef struct
{
@ -46,15 +39,14 @@ typedef struct player_info_s
//=============================================================================
typedef struct frame_s
{
bool valid; // cleared if delta parsing was invalid
int serverframe;
int servertime;
int deltaframe;
int num_entities;
int parse_entities; // non-masked index into cl_parse_entities array
bool valid; // cleared if delta parsing was invalid
double recv_time; // time message was received, or -1
int delta_sequence;
int num_entities;
int parse_entities; // non-masked index into cl_parse_entities array
} frame_t;
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
#define CMD_MASK (CMD_BACKUP - 1)
#define CL_UPDATE_MASK (CL_UPDATE_BACKUP - 1)
@ -83,11 +75,20 @@ typedef struct
int surpressCount; // number of messages rate supressed
frame_t *frames; // alloced on svc_serverdata
int time; // this is the time value that the client
// is rendering at. always <= cls.realtime
int render_flags; // clearing at end of frame
float lerpFrac; // interpolation value
ref_params_t refdef; // shared refdef
int validsequence; // this is the sequence number of the last good
// packetentity_t we got. If this is 0, we can't
// render a frame yet
double time; // clients view of time, should be between
// servertime and oldservertime to generate
// a lerp point for other data
double oldtime; // previous cl.time, time-oldtime is used
// to decay light values and smooth step ups
double mtime[2]; // the timestamp of the last two messages
int render_flags; // clearing at end of frame
float lerpFrac; // interpolation value
ref_params_t refdef; // shared refdef
cinematics_t *cin;
@ -97,13 +98,6 @@ typedef struct
// predicting stuff
vec3_t predicted_origins[CMD_BACKUP];// for debug comparing against server
add_angle_t addangle[CMD_BACKUP]; // accumulate angles from server
float old_addangle;
float cur_addangle;
float predicted_step; // for stair up smoothing
uint predicted_step_time;
vec3_t predicted_origin; // generated by CL_PredictMovement
vec3_t predicted_viewofs;
vec3_t predicted_angles;
@ -113,7 +107,6 @@ typedef struct
// server state information
int playernum;
int servercount; // server identification for prespawns
int serverframetime; // server frametime
char configstrings[MAX_CONFIGSTRINGS][CS_SIZE];
char physinfo[MAX_INFO_STRING]; // physics info string
@ -171,8 +164,6 @@ struct cl_priv_s
link_t area; // linked to a division node or leaf
bool linked;
int serverframe; // if not current, this ent isn't in the frame
entity_state_t current;
entity_state_t prev; // will always be valid, but might just be a copy of current
lerpframe_t frame; // holds the studio values for right lerping
@ -277,15 +268,11 @@ typedef struct
byte *mempool; // client premamnent pool: edicts etc
int framecount;
float frametime; // seconds since last frame
int realtime;
int quakePort; // a 16 bit value that allows quake servers
// to work around address translating routers
// connection information
string servername; // name of server from original connect
int connect_time; // for connection retransmits
double connect_time; // for connection retransmits
netchan_t netchan;
int serverProtocol; // in case we are doing some kind of version hack
@ -321,7 +308,6 @@ typedef struct
string demoname; // for demo looping
file_t *demofile;
int pingtime; // servers timebase
} client_static_t;
extern client_static_t cls;
@ -353,6 +339,7 @@ extern rgba_t g_color_table[8];
// cvars
//
extern cvar_t *cl_predict;
extern cvar_t *cl_smooth;
extern cvar_t *cl_showfps;
extern cvar_t *cl_shownet;
extern cvar_t *cl_envshot_size;
@ -374,9 +361,6 @@ extern cvar_t *con_font;
//=============================================================================
bool CL_CheckOrDownloadFile( const char *filename );
//=================================================
void CL_ParseFrame( sizebuf_t *msg );
void CL_ParseConfigString( sizebuf_t *msg );
void CL_SetLightstyle( int i );
void CL_RunLightStyles( void );
@ -553,6 +537,7 @@ void CL_UpdateBaseVelocity( edict_t *ent );
//
// cl_frame.c
//
void CL_ParsePacketEntities( sizebuf_t *msg, bool delta );
void CL_GetEntitySoundSpatialization( int ent, vec3_t origin, vec3_t velocity );
//

View File

@ -20,6 +20,13 @@
#include "com_export.h"
#include "net_msg.h"
// PERFORMANCE INFO
#define MIN_FPS 0.1 // host minimum fps value for maxfps.
#define MAX_FPS 1000.0 // upper limit for maxfps.
#define MAX_FRAMETIME 0.1
#define MIN_FRAMETIME 0.001
#define MAX_RENDERS 8 // max libraries to keep tracking
#define MAX_ENTNUMBER 99999 // for server and client parsing
#define MAX_HEARTBEAT -99999 // connection time
@ -57,8 +64,7 @@ typedef enum
{
RD_NONE = 0,
RD_CLIENT,
RD_PACKET,
RD_PACKET
} rdtype_t;
typedef struct host_redirect_s
@ -74,13 +80,16 @@ typedef struct host_parm_s
{
host_state state; // global host state
uint type; // running at
host_redirect_t rd; // remote console
jmp_buf abortframe; // abort current frame
dword errorframe; // to avoid each-frame host error
byte *mempool; // static mempool for misc allocations
string finalmsg; // server shutdown final message
host_redirect_t rd; // remote console
double realtime; // host.curtime
double frametime; // time between engine frames
double realframetime; // for some system events, e.g. console animations
int frametime; // time between engine frames
uint framecount; // global framecount
int events_head;
@ -89,7 +98,7 @@ typedef struct host_parm_s
HWND hWnd; // main window
int developer; // show all developer's message
bool key_overstrike; // global key overstrike mode
bool key_overstrike; // key overstrike mode
} host_parm_t;
extern host_parm_t host;
@ -126,12 +135,12 @@ CLIENT / SERVER SYSTEMS
*/
void CL_Init( void );
void CL_Shutdown( void );
void CL_Frame( int time );
void Host_ClientFrame( void );
bool CL_Active( void );
void SV_Init( void );
void SV_Shutdown( bool reconnect );
void SV_Frame( int time );
void Host_ServerFrame( void );
bool SV_Active( void );
/*
@ -190,7 +199,7 @@ float pfnTime( void );
//
bool Key_IsDown( int keynum );
const char *Key_IsBind( int keynum );
void Key_Event( int key, bool down, int time );
void Key_Event( int key, bool down );
void Key_Init( void );
void Key_WriteBindings( file_t *f );
void Key_SetBinding( int keynum, char *binding );
@ -227,6 +236,7 @@ edict_t *CL_GetEdictByIndex( int index );
mouth_t *CL_GetEntityMouth( edict_t *ent );
edict_t *CL_GetLocalPlayer( void );
int CL_GetMaxClients( void );
bool CL_IsPlaybackDemo( void );
byte CL_GetMouthOpen( int entityIndex );
bool SV_GetComment( const char *savename, char *comment );
bool SV_NewGame( const char *mapName, bool loadGame );
@ -234,7 +244,7 @@ bool SV_LoadProgs( const char *name );
void SV_ForceError( void );
void CL_WriteMessageHistory( void );
void CL_MouseEvent( int mx, int my );
void CL_AddLoopingSounds( void );
void CL_SendCmd( void );
void CL_Disconnect( void );
bool CL_NextDemo( void );
void CL_Drop( void );

View File

@ -346,7 +346,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, b
// draw the cursor
if( !showCursor ) return;
if((int)( cls.realtime>>8 ) & 1 )
if((int)( host.realtime * 4 ) & 1 )
return; // off blink
if( host.key_overstrike ) cursorChar = 11;
@ -1068,7 +1068,7 @@ Key_Event
Called by the system for both key up and key down events
===================
*/
void Key_Event( int key, bool down, int time )
void Key_Event( int key, bool down )
{
const char *kb;
char cmd[1024];
@ -1168,7 +1168,7 @@ void Key_Event( int key, bool down, int time )
{
// button commands add keynum and time as parms so that multiple
// sources can be discriminated and subframe corrected
com.sprintf( cmd, "%s %i %i\n", button, key, time );
com.sprintf( cmd, "%s %i\n", button, key );
Cbuf_AddText( cmd );
}
else
@ -1235,7 +1235,7 @@ void Key_ClearStates( void )
anykeydown = false;
for ( i = 0; i < 256; i++ )
{
if( keys[i].down ) Key_Event( i, false, 0 );
if( keys[i].down ) Key_Event( i, false );
keys[i].down = 0;
keys[i].repeats = 0;
}

View File

@ -20,7 +20,7 @@ cvar_t *con_font;
#define COLOR_MAGENTA '6'
#define COLOR_WHITE '7'
#define NUM_CON_TIMES 5 // need for 4 lines
#define CON_TIMES 5 // need for 4 lines
#define CON_TEXTSIZE (MAX_MSGLEN * 4) // 128 kb buffer
int g_console_field_width = 78;
@ -56,7 +56,7 @@ typedef struct
float finalFrac; // 0.0 to 1.0 lines of console to display
int vislines; // in scanlines
int times[NUM_CON_TIMES]; // cls.realtime the line was generated for transparent notify lines
double times[CON_TIMES]; // host.realtime the line was generated for transparent notify lines
rgba_t color;
} console_t;
@ -86,8 +86,8 @@ void Con_ClearNotify( void )
{
int i;
for( i = 0; i < NUM_CON_TIMES; i++ )
con.times[i] = 0;
for( i = 0; i < CON_TIMES; i++ )
con.times[i] = 0.0;
}
void Con_ClearTyping( void )
@ -229,8 +229,8 @@ void Con_Linefeed( bool skipnotify )
// mark time for transparent overlay
if( con.current >= 0 )
{
if( skipnotify ) con.times[con.current % NUM_CON_TIMES] = 0;
else con.times[con.current % NUM_CON_TIMES] = cls.realtime;
if( skipnotify ) con.times[con.current % CON_TIMES] = 0;
else con.times[con.current % CON_TIMES] = host.realtime;
}
con.x = 0;
@ -313,11 +313,11 @@ void Con_Print( const char *txt )
{
if( skipnotify )
{
prev = con.current % NUM_CON_TIMES - 1;
if( prev < 0 ) prev = NUM_CON_TIMES - 1;
prev = con.current % CON_TIMES - 1;
if( prev < 0 ) prev = CON_TIMES - 1;
con.times[prev] = 0;
}
else con.times[con.current % NUM_CON_TIMES] = cls.realtime;
else con.times[con.current % CON_TIMES] = host.realtime;
}
}
@ -357,32 +357,32 @@ Draws the last few lines of output transparently over the game top
*/
void Con_DrawNotify( void )
{
int x, v = 0;
short *text;
int i, time;
int i, x, v = 0;
int currentColor;
short *text;
float time;
currentColor = 7;
re->SetColor( g_color_table[currentColor] );
for( i = con.current - NUM_CON_TIMES + 1; i <= con.current; i++ )
for( i = con.current - CON_TIMES + 1; i <= con.current; i++ )
{
if( i < 0 ) continue;
time = con.times[i % NUM_CON_TIMES];
if( time == 0 ) continue;
time = cls.realtime - time;
if( time > (con_notifytime->value * 1000)) continue;
time = con.times[i % CON_TIMES];
if( time == 0.0 ) continue;
time = host.realtime - time;
if( time > con_notifytime->value ) continue;
text = con.text + (i % con.totallines) * con.linewidth;
for( x = 0; x < con.linewidth; x++ )
{
if((text[x] & 0xff ) == ' ' ) continue;
if(((text[x]>>8) & 7 ) != currentColor )
if(( ( text[x] >> 8 ) & 7 ) != currentColor )
{
currentColor = (text[x]>>8) & 7;
currentColor = ( text[x] >> 8 ) & 7;
re->SetColor(g_color_table[currentColor]);
}
SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff );
SCR_DrawSmallChar( con.xadjust + (x+1) * SMALLCHAR_WIDTH, v, text[x] & 0xff );
}
v += SMALLCHAR_HEIGHT;
}
@ -549,13 +549,13 @@ void Con_RunConsole( void )
if( con.finalFrac < con.displayFrac )
{
con.displayFrac -= con_speed->value * cls.frametime;
con.displayFrac -= con_speed->value * host.realframetime;
if( con.finalFrac > con.displayFrac )
con.displayFrac = con.finalFrac;
}
else if( con.finalFrac > con.displayFrac )
{
con.displayFrac += con_speed->value * cls.frametime;
con.displayFrac += con_speed->value * host.realframetime;
if( con.finalFrac < con.displayFrac )
con.displayFrac = con.finalFrac;
}

View File

@ -260,7 +260,7 @@ void IN_MouseMove( void )
my = current_pos.y - window_center_y;
if( !mx && !my ) return;
Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
Sys_QueEvent( SE_MOUSE, mx, my, 0, NULL );
}
/*
@ -280,11 +280,11 @@ void IN_MouseEvent( int mstate )
{
if(( mstate & (1<<i)) && !( in_mouse_oldbuttonstate & (1<<i)) )
{
Sys_QueEvent( -1, SE_KEY, K_MOUSE1 + i, true, 0, NULL );
Sys_QueEvent( SE_KEY, K_MOUSE1 + i, true, 0, NULL );
}
if(!( mstate & (1<<i)) && ( in_mouse_oldbuttonstate & (1<<i)) )
{
Sys_QueEvent( -1, SE_KEY, K_MOUSE1 + i, false, 0, NULL );
Sys_QueEvent( SE_KEY, K_MOUSE1 + i, false, 0, NULL );
}
}
in_mouse_oldbuttonstate = mstate;
@ -390,13 +390,13 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
case WM_MOUSEWHEEL:
if(( short )HIWORD( wParam ) > 0 )
{
Sys_QueEvent( -1, SE_KEY, K_MWHEELUP, true, 0, NULL );
Sys_QueEvent( -1, SE_KEY, K_MWHEELUP, false, 0, NULL );
Sys_QueEvent( SE_KEY, K_MWHEELUP, true, 0, NULL );
Sys_QueEvent( SE_KEY, K_MWHEELUP, false, 0, NULL );
}
else
{
Sys_QueEvent( -1, SE_KEY, K_MWHEELDOWN, true, 0, NULL );
Sys_QueEvent( -1, SE_KEY, K_MWHEELDOWN, false, 0, NULL );
Sys_QueEvent( SE_KEY, K_MWHEELDOWN, true, 0, NULL );
Sys_QueEvent( SE_KEY, K_MWHEELDOWN, false, 0, NULL );
}
break;
case WM_CREATE:
@ -478,14 +478,14 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
}
// intentional fallthrough
case WM_KEYDOWN:
Sys_QueEvent( -1, SE_KEY, Host_MapKey( lParam ), true, 0, NULL );
Sys_QueEvent( SE_KEY, Host_MapKey( lParam ), true, 0, NULL );
break;
case WM_SYSKEYUP:
case WM_KEYUP:
Sys_QueEvent( -1, SE_KEY, Host_MapKey( lParam ), false, 0, NULL );
Sys_QueEvent( SE_KEY, Host_MapKey( lParam ), false, 0, NULL );
break;
case WM_CHAR:
Sys_QueEvent( -1, SE_CHAR, wParam, 0, 0, NULL );
Sys_QueEvent( SE_CHAR, wParam, false, 0, NULL );
break;
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );

View File

@ -34,7 +34,7 @@ If the message buffer is overflowed, either by a single message, or by
multiple frames worth piling up while the last reliable transmit goes
unacknowledged, the netchan signals a fatal error.
Reliable messages are always placed first in a packet, then the unreliable
Reliable messages are allways placed first in a packet, then the unreliable
message is included if there is sufficient room.
To the receiver, there is no distinction between the reliable and unreliable
@ -45,7 +45,6 @@ not kill the connection. This, combined with the tight window of valid
reliable acknowledgement numbers provides protection against malicious
address spoofing.
The qport field is a workaround for bad address translating routers that
sometimes remap the client's source port on a packet during gameplay.
@ -98,10 +97,11 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport )
chan->sock = sock;
chan->remote_address = adr;
chan->qport = qport;
chan->last_received = Sys_Milliseconds();
chan->last_received = host.realtime;
chan->incoming_sequence = 0;
chan->outgoing_sequence = 1;
chan->compress = true;
chan->rate = 1.0f / 2500;
MSG_Init( &chan->message, chan->message_buf, sizeof( chan->message_buf ));
}
@ -147,6 +147,38 @@ void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, char *format, ... )
Netchan_OutOfBand( net_socket, adr, com.strlen( string ), string );
}
/*
===============
Netchan_CanPacket
Returns true if the bandwidth choke isn't active
================
*/
bool Netchan_CanPacket( netchan_t *chan )
{
// never drop over the loopback
if( NET_IsLocalAddress( chan->remote_address ))
return true;
if( chan->cleartime < host.realtime + MAX_BACKUP * chan->rate )
return true;
return false;
}
/*
===============
Netchan_CanReliable
Returns true if the bandwidth choke isn't
================
*/
bool Netchan_CanReliable( netchan_t *chan )
{
if( chan->reliable_length )
return false; // waiting for ack
return Netchan_CanPacket( chan );
}
bool Netchan_NeedReliable( netchan_t *chan )
{
bool send_reliable = false;
@ -189,7 +221,7 @@ void Netchan_Transmit( netchan_t *chan, int length, byte *data )
byte send_buf[MAX_MSGLEN];
bool send_reliable;
size_t size1, size2;
uint w1, w2;
uint i, w1, w2;
// check for message overflow
if( chan->message.overflowed )
@ -208,7 +240,6 @@ void Netchan_Transmit( netchan_t *chan, int length, byte *data )
w2 = (chan->incoming_sequence & ~(1<<31)) | (chan->incoming_reliable_sequence<<31);
chan->outgoing_sequence++;
chan->last_sent = Sys_Milliseconds();
MSG_WriteLong( &send, w1 );
MSG_WriteLong( &send, w2 );
@ -240,9 +271,18 @@ void Netchan_Transmit( netchan_t *chan, int length, byte *data )
if( chan->compress ) Huff_CompressPacket( &send, (chan->sock == NS_CLIENT) ? 10 : 8 );
size2 = send.cursize;
// record the size for rate estimation
i = chan->outgoing_sequence & (MAX_LATENT - 1);
chan->outgoing_size[i] = send.cursize;
chan->outgoing_time[i] = host.realtime;
// send the datagram
NET_SendPacket( chan->sock, send.cursize, send.data, chan->remote_address );
if( chan->cleartime < host.realtime )
chan->cleartime = host.realtime + send.cursize * chan->rate;
else chan->cleartime += send.cursize * chan->rate;
if( net_showpackets->integer )
{
const char *s1, *s2;
@ -287,6 +327,41 @@ bool Netchan_Process( netchan_t *chan, sizebuf_t *msg )
sequence &= ~(1<<31);
sequence_ack &= ~(1<<31);
#if 0
// get a rate estimation
if( chan->outgoing_sequence - sequence_ack < MAX_LATENT )
{
int i;
double time, rate;
i = sequence_ack & (MAX_LATENT - 1);
time = host.realtime - chan->outgoing_time[i];
time -= 0.1f; // subtract 100 ms
if( time <= 0 )
{
// gotta be a digital link for <100 ms ping
if( chan->rate > 1.0f / 5000 )
chan->rate = 1.0f / 5000;
}
else
{
if( chan->outgoing_size[i] < 512 )
{
// only deal with small messages
rate = chan->outgoing_size[i] / time;
if( rate > 5000 ) rate = 5000;
rate = 1.0f / rate;
if( chan->rate > rate )
chan->rate = rate;
}
}
if( chan->sock == NS_SERVER )
Msg( "Adjust rate: %g\n", chan->rate );
}
#endif
// discard stale or duplicated packets
if( sequence <= chan->incoming_sequence )
{
@ -330,10 +405,15 @@ bool Netchan_Process( netchan_t *chan, sizebuf_t *msg )
MsgDev( D_INFO, "Netchan_Process: %s[%s] : %sreliable\n", s1, s2, recv_reliable ? "" : "un" );
}
// the message can now be read from the current message pointer
// update statistics counters
chan->frame_latency = chan->frame_latency * OLD_AVG + (chan->outgoing_sequence-sequence_ack) * (1.0f - OLD_AVG);
chan->frame_rate = chan->frame_rate * OLD_AVG + (host.realtime - chan->last_received) * (1.0f - OLD_AVG);
chan->good_count += 1;
// the message can now be read from the current message pointer
chan->last_received = Sys_Milliseconds();
chan->last_received = host.realtime;
return true;
}

View File

@ -63,7 +63,8 @@ enum svc_ops_e
svc_changing, // changelevel server request
svc_physinfo, // [physinfo string]
svc_packetentities, // [...]
svc_frame, // server frame
svc_deltapacketentities, // [...]
svc_time, // [float] server time
svc_sound, // <see code>
svc_ambientsound, // <see code>
svc_setangle, // [short short short] set the view angle to this absolute value
@ -81,6 +82,7 @@ enum svc_ops_e
svc_event_reliable, // playback event directly from message, not queue
svc_updateuserinfo, // [byte] playernum, [string] userinfo
svc_serverinfo, // [string] key [string] value
svc_chokecount, // [byte] surpress count
};
// client to server
@ -91,7 +93,7 @@ enum clc_ops_e
// engine messages
clc_nop = 201,
clc_move, // [[usercmd_t]
clc_deltamove, // [[usercmd_t]
clc_delta, // [byte] sequence number, requests delta compression of message
clc_userinfo, // [[userinfo string]
clc_stringcmd, // [string] message
};
@ -243,7 +245,9 @@ NET
==============================================================
*/
#define MAX_LATENT 32
#define MAX_LATENT 32
#define OLD_AVG 0.99 // total = oldtotal * OLD_AVG + new * ( 1 - OLD_AVG )
#define MAX_BACKUP 200
typedef struct netchan_s
{
@ -253,8 +257,12 @@ typedef struct netchan_s
int dropped; // between last packet and previous
bool compress; // enable huffman compression
long last_received; // for timeouts
long last_sent; // for retransmits
float last_received; // for timeouts
// the statistics are cleared at each client begin, because
// the server connecting process gives a bogus picture of the data
float frame_latency; // rolling average
float frame_rate;
int drop_count; // dropped packets, cleared each level
int good_count; // cleared each level
@ -262,6 +270,10 @@ typedef struct netchan_s
netadr_t remote_address;
int qport; // qport value to write when transmitting
// bandwidth estimator
double cleartime; // if host.realtime > nc->cleartime, free to go
double rate; // seconds / byte
// sequencing variables
int incoming_sequence;
int incoming_acknowledged;
@ -283,7 +295,7 @@ typedef struct netchan_s
// time and size data to calculate bandwidth
int outgoing_size[MAX_LATENT];
long outgoing_time[MAX_LATENT];
double outgoing_time[MAX_LATENT];
} netchan_t;
@ -308,4 +320,7 @@ void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data );
void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, char *format, ... );
bool Netchan_Process( netchan_t *chan, sizebuf_t *msg );
bool Netchan_CanPacket( netchan_t *chan );
bool Netchan_CanReliable( netchan_t *chan );
#endif//NET_MSG_H

View File

@ -24,12 +24,10 @@ dll_info_t render_dll = { "", NULL, "CreateAPI", NULL, NULL, 0, sizeof(render_ex
dll_info_t vsound_dll = { "", NULL, "CreateAPI", NULL, NULL, 0, sizeof(vsound_exp_t), sizeof(stdlib_api_t) };
dll_info_t physic_dll = { "physic.dll", NULL, "CreateAPI", NULL, NULL, 0, sizeof(physic_exp_t), sizeof(stdlib_api_t) };
cvar_t *timescale;
cvar_t *sys_sharedstrings;
cvar_t *host_serverstate;
cvar_t *host_cheats;
cvar_t *host_maxfps;
cvar_t *host_minfps;
cvar_t *host_nosound;
cvar_t *host_framerate;
cvar_t *host_registered;
@ -393,6 +391,13 @@ void Host_Minimize_f( void )
if( host.hWnd ) ShowWindow( host.hWnd, SW_MINIMIZE );
}
bool Host_IsLocalGame( void )
{
if( CL_Active() && SV_Active() && CL_GetMaxClients() == 1 )
return true;
return false;
}
/*
=================
Host_InitEvents
@ -455,7 +460,7 @@ Host_EventLoop
Returns last event time
=================
*/
int Host_EventLoop( void )
bool Host_EventLoop( void )
{
sys_event_t ev;
@ -465,9 +470,11 @@ int Host_EventLoop( void )
switch( ev.type )
{
case SE_NONE:
return ev.time;
// done
Cbuf_Execute();
return true;
case SE_KEY:
Key_Event( ev.value[0], ev.value[1], ev.time );
Key_Event( ev.value[0], ev.value[1] );
break;
case SE_CHAR:
CL_CharEvent( ev.value[0] );
@ -479,72 +486,64 @@ int Host_EventLoop( void )
Cbuf_AddText( va( "%s\n", ev.data ));
break;
default:
Host_Error( "Host_EventLoop: bad event type %i", ev.type );
break;
MsgDev( D_ERROR, "Host_EventLoop: bad event type %i", ev.type );
return false;
}
if( ev.data ) Mem_Free( ev.data );
}
return 0; // never reached
// shut up the compiler
return false;
}
/*
================
Host_Milliseconds
===================
Host_FilterTime
Can be used for profiling, but will be journaled accurately
================
Returns false if the time is too short to run a frame
===================
*/
int Host_Milliseconds( void )
bool Host_FilterTime( float time )
{
sys_event_t ev;
static double oldtime;
float fps;
// get events and push them until we get a null event with the current time
do {
ev = Sys_GetEvent();
if( ev.type != SE_NONE )
Host_PushEvent( &ev );
} while( ev.type != SE_NONE );
return ev.time;
}
host.realtime += time;
/*
================
Host_ModifyTime
================
*/
int Host_ModifyTime( int msec )
{
int clamp_time;
// dedicated's tic_rate regulates server frame rate. Don't apply fps filter here.
fps = host_maxfps->value;
// modify time for debugging values
if( host_framerate->value ) msec = host_framerate->value * 1000;
else if( timescale->value ) msec *= timescale->value;
if( msec < 1 && timescale->value ) msec = 1;
if( host.type == HOST_DEDICATED )
if( fps != 0 )
{
// dedicated servers don't want to clamp for a much longer
// period, because it would mess up all the client's views of time.
if( msec > 500 ) MsgDev( D_NOTE, "Host_ModifyTime: %i msec frame time\n", msec );
clamp_time = 5000;
float minframetime;
// limit fps to withing tolerable range
fps = bound( MIN_FPS, fps, MAX_FPS );
minframetime = 1.0f / fps;
if(( host.realtime - oldtime ) < minframetime )
{
// framerate is too high
return false;
}
}
else if( SV_Active( ))
host.frametime = host.realframetime = host.realtime - oldtime;
oldtime = host.realtime;
if( host_framerate->value > 0 && ( Host_IsLocalGame() || CL_IsPlaybackDemo() ))
{
// for local single player gaming
// we may want to clamp the time to prevent players from
// flying off edges when something hitches.
clamp_time = 200;
float fps = host_framerate->value;
if( fps > 1 ) fps = 1.0f / fps;
host.frametime = fps;
}
else
{
// clients of remote servers do not want to clamp time, because
// it would skew their view of the server's time temporarily
clamp_time = 5000;
{ // don't allow really long or short frames
host.frametime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
}
if( msec > clamp_time ) msec = clamp_time;
return msec;
return true;
}
/*
@ -552,34 +551,21 @@ int Host_ModifyTime( int msec )
Host_Frame
=================
*/
void Host_Frame( void )
void Host_Frame( float time )
{
int time, min_time;
static int last_time;
if( setjmp( host.abortframe ))
return;
rand(); // keep the random time dependent
// decide the simulation time
if( !Host_FilterTime( time ))
return;
// we may want to spin here if things are going too fast
if( host.type != HOST_DEDICATED && host_maxfps->integer > 0 )
min_time = 1000 / host_maxfps->integer;
else min_time = 1;
Host_EventLoop();
do {
host.frametime = Host_EventLoop();
if( last_time > host.frametime )
last_time = host.frametime;
time = host.frametime - last_time;
} while( time < min_time );
Cbuf_Execute();
rand (); // keep the random time dependent
last_time = host.frametime;
time = Host_ModifyTime( time );
SV_Frame ( time ); // server frame
CL_Frame ( time ); // client frame
Host_ServerFrame (); // server frame
Host_ClientFrame (); // client frame
host.framecount++;
}
@ -808,13 +794,11 @@ void Host_Init( const int argc, const char **argv )
sys_sharedstrings = Cvar_Get( "sys_sharedstrings", "0", CVAR_INIT|CVAR_ARCHIVE, "hl1 compatible strings" );
host_cheats = Cvar_Get( "sv_cheats", "1", CVAR_SYSTEMINFO, "allow cheat variables to enable" );
host_minfps = Cvar_Get( "host_minfps", "10", CVAR_ARCHIVE, "host fps lower limit" );
host_maxfps = Cvar_Get( "host_maxfps", "100", CVAR_ARCHIVE, "host fps upper limit" );
host_maxfps = Cvar_Get( "fps_max", "72", CVAR_ARCHIVE, "host fps upper limit" );
host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" );
host_serverstate = Cvar_Get( "host_serverstate", "0", CVAR_SERVERINFO, "displays current server state" );
host_registered = Cvar_Get( "registered", "1", CVAR_SYSTEMINFO, "indicate shareware version of game" );
host_nosound = Cvar_Get( "host_nosound", "0", CVAR_SYSTEMINFO, "disable sound system" );
timescale = Cvar_Get( "timescale", "1.0", 0, "slow-mo timescale" );
s = va( "^1Xash %g ^3%s", SI->version, buildstring );
Cvar_Get( "version", s, CVAR_INIT, "engine current version" );
@ -861,15 +845,21 @@ Host_Main
*/
void Host_Main( void )
{
static double oldtime, newtime;
oldtime = Sys_DoubleTime();
// main window message loop
while( host.state != HOST_OFFLINE )
{
IN_Frame();
Host_Frame();
newtime = Sys_DoubleTime ();
Host_Frame( newtime - oldtime );
oldtime = newtime;
}
}
/*
=================
Host_Shutdown

View File

@ -12,9 +12,7 @@
//=============================================================================
#define MAX_MASTERS 8 // max recipients for heartbeat packets
#define LATENCY_COUNTS 16
#define MAX_ENT_LEAFS 48
#define RATE_MESSAGES 10
#define SV_UPDATE_MASK (SV_UPDATE_BACKUP - 1)
extern int SV_UPDATE_BACKUP;
@ -57,10 +55,9 @@ typedef struct server_s
bool loadgame; // client begins should reuse existing entity
int time; // sv.time += sv.frametime
int frametime;
int framenum;
int net_framenum;
double time; // sv.time += sv.frametime
float frametime;
int net_framenum; // to avoid send edicts twice through portals
int hostflags; // misc server flags: predicting etc
@ -86,8 +83,8 @@ typedef struct
entity_state_t ps; // player state
int num_entities;
int first_entity; // into the circular sv_packet_entities[]
int senttime; // time the message was transmitted
int latency;
double senttime; // time the message was transmitted
float latency;
int index; // client edict index
} client_frame_t;
@ -103,25 +100,16 @@ typedef struct sv_client_s
bool sendmovevars;
bool sendinfo;
int lastframe; // for delta compression
int delta_sequence; // for delta compression ( -1 = no compression )
usercmd_t lastcmd; // for filling in big drops
int usehull; // current hull that client used
int modelindex; // custom playermodel index
int commandMsec; // every seconds this is reset, if user
// commands exhaust it, assume time cheating
int packet_loss;
int ping;
int message_size[RATE_MESSAGES]; // used to rate drop packets
int rate;
int surpressCount; // number of messages rate supressed
float anglechangetotal; // add angles to client position
float anglechangefinal; // add angles to client position
float addangle; // add angles to client position
edict_t *edict; // EDICT_NUM(clientnum+1)
edict_t *pViewEntity; // svc_setview member
@ -145,8 +133,8 @@ typedef struct sv_client_s
int downloadsize; // total bytes (can't use EOF because of paks)
int downloadcount; // bytes sent
int lastmessage; // sv.framenum when packet was last received
int lastconnect;
double lastmessage; // time when packet was last received
double lastconnect;
int challenge; // challenge of this user, randomly generated
@ -190,15 +178,12 @@ typedef struct
{
netadr_t adr;
int challenge;
int time;
double time;
bool connected;
} challenge_t;
typedef struct
{
float time; // cached sv.time
float frametime; // cached sv.frametime
// user messages stuff
const char *msg_name; // just for debug
int msg_sizes[MAX_USER_MESSAGES]; // user messages bounds checker
@ -235,13 +220,12 @@ typedef struct
typedef struct
{
bool initialized; // sv_init has completed
int realtime; // always increasing, no clamping, etc
double timestart; // just for profiling
int groupmask;
int groupop;
float changelevel_next_time; // don't execute multiple changelevels at once time
double changelevel_next_time; // don't execute multiple changelevels at once time
int spawncount; // incremented each server start
// used to check late spawns
sv_client_t *clients; // [sv_maxclients->integer]
@ -250,7 +234,7 @@ typedef struct
entity_state_t *client_entities; // [num_client_entities]
entity_state_t *baselines; // [GI->max_edicts]
int last_heartbeat;
double last_heartbeat;
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
} server_static_t;
@ -272,10 +256,7 @@ extern cvar_t *sv_idealpitchscale;
extern cvar_t *sv_maxvelocity;
extern cvar_t *sv_gravity;
extern cvar_t *sv_stopspeed;
extern cvar_t *sv_fps; // running server at
extern cvar_t *sv_check_errors;
extern cvar_t *sv_synchthink;
extern cvar_t *sv_enforcetime;
extern cvar_t *sv_reconnect_limit;
extern cvar_t *rcon_password;
extern cvar_t *hostname;
@ -308,7 +289,6 @@ void SV_InitOperatorCommands( void );
void SV_KillOperatorCommands( void );
void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo );
void SV_PrepWorldFrame( void );
void SV_CalcFrameTime( void );
void Master_Heartbeat( void );
void Master_Packet( void );

View File

@ -29,7 +29,7 @@ challenge, they must give a valid IP address.
void SV_GetChallenge( netadr_t from )
{
int i, oldest = 0;
int oldestTime;
double oldestTime;
oldestTime = 0x7fffffff;
// see if we already have a challenge for this ip
@ -47,9 +47,9 @@ void SV_GetChallenge( netadr_t from )
if( i == MAX_CHALLENGES )
{
// this is the first time this client has asked for a challenge
svs.challenges[oldest].challenge = ((rand()<<16) ^ rand()) ^ svs.realtime;
svs.challenges[oldest].challenge = (rand()<<16) ^ rand();
svs.challenges[oldest].adr = from;
svs.challenges[oldest].time = svs.realtime;
svs.challenges[oldest].time = host.realtime;
svs.challenges[oldest].connected = false;
i = oldest;
}
@ -93,9 +93,9 @@ void SV_DirectConnect( netadr_t from )
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->state == cs_free ) continue;
if( NET_CompareBaseAdr(from, cl->netchan.remote_address) && (cl->netchan.qport == qport || from.port == cl->netchan.remote_address.port))
if( NET_CompareBaseAdr(from, cl->netchan.remote_address) && (cl->netchan.qport == qport || from.port == cl->netchan.remote_address.port ))
{
if(!NET_IsLocalAddress( from ) && (svs.realtime - cl->lastconnect) < sv_reconnect_limit->value * 1000 )
if( !NET_IsLocalAddress( from ) && ( host.realtime - cl->lastconnect ) < sv_reconnect_limit->value )
{
MsgDev( D_INFO, "%s:reconnect rejected : too soon\n", NET_AdrToString( from ));
return;
@ -197,8 +197,8 @@ gotnewcl:
MSG_Init( &newcl->datagram, newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf
newcl->state = cs_connected;
newcl->lastmessage = svs.realtime;
newcl->lastconnect = svs.realtime;
newcl->lastmessage = host.realtime;
newcl->lastconnect = host.realtime;
// if this was the first client on the server, or the last client
// the server can hold, send a heartbeat to the master.
@ -272,8 +272,8 @@ edict_t *SV_FakeConnect( const char *netname )
SV_UserinfoChanged( newcl, userinfo );
newcl->state = cs_spawned;
newcl->lastmessage = svs.realtime; // don't timeout
newcl->lastconnect = svs.realtime;
newcl->lastmessage = host.realtime; // don't timeout
newcl->lastconnect = host.realtime;
return ent;
}
@ -349,7 +349,9 @@ void SV_DropClient( sv_client_t *drop )
if( svs.clients[i].state >= cs_connected )
break;
}
if( i == sv_maxclients->integer ) svs.last_heartbeat = MAX_HEARTBEAT;
if( i == sv_maxclients->integer )
svs.last_heartbeat = MAX_HEARTBEAT;
}
/*
@ -1032,10 +1034,8 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
if( com.strlen( val ))
{
i = com.atoi( val );
cl->rate = i;
cl->rate = bound ( 100, cl->rate, 15000 );
cl->netchan.rate = 1.0f / (bound( 500, i, 10000 ));
}
else cl->rate = 5000;
// msg command
val = Info_ValueForKey( cl->userinfo, "msg" );
@ -1369,24 +1369,12 @@ each of the backup packets.
*/
static void SV_ReadClientMove( sv_client_t *cl, sizebuf_t *msg )
{
int key, net_drop;
int checksum1, checksum2;
int key, lastframe, net_drop;
usercmd_t oldest, oldcmd, newcmd, nulcmd;
key = msg->readcount;
checksum1 = MSG_ReadByte( msg );
lastframe = MSG_ReadLong( msg );
if( lastframe != cl->lastframe )
{
cl->lastframe = lastframe;
if( cl->lastframe > 0 )
{
client_frame_t *frame = &cl->frames[cl->lastframe & SV_UPDATE_MASK];
frame->latency = svs.realtime - frame->senttime;
}
}
cl->packet_loss = SV_CalcPacketLoss( cl );
Mem_Set( &nulcmd, 0, sizeof( nulcmd ));
@ -1395,10 +1383,7 @@ static void SV_ReadClientMove( sv_client_t *cl, sizebuf_t *msg )
MSG_ReadDeltaUsercmd( msg, &oldcmd, &newcmd );
if( cl->state != cs_spawned )
{
cl->lastframe = -1;
return;
}
// if the checksum fails, ignore the rest of the packet
checksum2 = CRC_Sequence( msg->data + key + 1, msg->readcount - key - 1, cl->netchan.incoming_sequence );
@ -1443,14 +1428,25 @@ Parse a client packet
*/
void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
{
int c, stringCmdCount = 0;
bool move_issued = false;
char *s;
int c, stringCmdCount = 0;
bool move_issued = false;
client_frame_t *frame;
char *s;
// calc ping time
frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
frame->latency = host.realtime - frame->senttime;
// make sure the reply sequence number matches the incoming sequence number
if( cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence )
cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
else cl->send_message = false; // don't reply, sequences have slipped
// save time for ping calculations
cl->frames[cl->netchan.outgoing_sequence & SV_UPDATE_MASK].senttime = host.realtime;
cl->frames[cl->netchan.outgoing_sequence & SV_UPDATE_MASK].latency = -1.0f;
cl->delta_sequence = -1; // no delta unless requested
// read optional clientCommand strings
while( cl->state != cs_zombie )
@ -1469,6 +1465,9 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
{
case clc_nop:
break;
case clc_delta:
cl->delta_sequence = MSG_ReadByte( msg );
break;
case clc_userinfo:
SV_UserinfoChanged( cl, MSG_ReadString( msg ));
break;

View File

@ -471,12 +471,14 @@ void SV_Kick_f( void )
Msg( "^3no server running.\n" );
return;
}
if( !SV_SetPlayer()) return;
if( !SV_SetPlayer( )) return;
SV_BroadcastPrintf( PRINT_HIGH, "%s was kicked\n", sv_client->name );
SV_ClientPrintf( sv_client, PRINT_HIGH, "You were kicked from the game\n" );
SV_DropClient( sv_client );
sv_client->lastmessage = svs.realtime; // min case there is a funny zombie
// min case there is a funny zombie
sv_client->lastmessage = host.realtime;
}
/*
@ -563,7 +565,7 @@ void SV_Status_f( void )
Msg( "%s", cl->name );
l = 24 - com.strlen( cl->name );
for( j = 0; j < l; j++ ) Msg( " " );
Msg( "%g ", (svs.realtime - cl->lastmessage) * 0.001f );
Msg( "%g ", host.realtime - cl->lastmessage );
s = NET_AdrToString( cl->netchan.remote_address );
Msg( "%s", s );
l = 22 - com.strlen( s );

View File

@ -67,10 +67,9 @@ void SV_UpdateEntityState( const edict_t *ent, bool baseline )
break;
case 2:
MSG_WriteByte( &sv.multicast, svc_addangle );
MSG_WriteAngle32( &sv.multicast, client->anglechangetotal );
MSG_WriteAngle32( &sv.multicast, client->anglechangefinal );
MSG_WriteAngle32( &sv.multicast, client->addangle );
MSG_DirectSend( MSG_ONE, vec3_origin, client->edict );
client->anglechangetotal = client->anglechangefinal = 0;
client->addangle = 0;
break;
}
client->edict->v.fixangle = 0; // reset fixangle
@ -126,17 +125,24 @@ SV_EmitPacketEntities
Writes a delta update of an entity_state_t list to the message->
=============
*/
void SV_EmitPacketEntities( client_frame_t *from, client_frame_t *to, sizebuf_t *msg )
void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *from, client_frame_t *to, sizebuf_t *msg )
{
entity_state_t *oldent, *newent;
int oldindex, newindex;
int oldnum, newnum;
int from_num_entities;
MSG_WriteByte( msg, svc_packetentities );
if( !from ) from_num_entities = 0;
else from_num_entities = from->num_entities;
if( !from )
{
from_num_entities = 0;
MSG_WriteByte( msg, svc_packetentities );
}
else
{
from_num_entities = from->num_entities;
MSG_WriteByte( msg, svc_deltapacketentities );
MSG_WriteByte( msg, cl->delta_sequence );
}
newent = NULL;
oldent = NULL;
@ -320,36 +326,22 @@ SV_WriteFrameToClient
void SV_WriteFrameToClient( sv_client_t *cl, sizebuf_t *msg )
{
client_frame_t *frame, *oldframe;
int lastframe;
// this is the frame we are creating
frame = &cl->frames[sv.framenum & SV_UPDATE_MASK];
if( cl->lastframe <= 0 )
{
// client is asking for a retransmit
oldframe = NULL;
lastframe = -1;
}
else if( sv.framenum - cl->lastframe >= (SV_UPDATE_BACKUP - 3))
// this is the frame that we are going to delta update from
if( cl->delta_sequence != -1 )
{
// client hasn't gotten a good message through in a long time
oldframe = NULL;
lastframe = -1;
}
else
{ // we have a valid message to delta from
oldframe = &cl->frames[cl->lastframe & SV_UPDATE_MASK];
lastframe = cl->lastframe;
oldframe = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK];
// the snapshot's entities may still have rolled off the buffer, though
if( oldframe->first_entity <= svs.next_client_entities - svs.num_client_entities )
{
MsgDev( D_WARN, "%s: ^7delta request from out of date entities.\n", cl->name );
MsgDev( D_ERROR, "%s: ^7delta request from out of date entities.\n", cl->name );
oldframe = NULL;
lastframe = 0;
}
}
else oldframe = NULL; // no delta update
frame = &cl->frames[cl->netchan.incoming_sequence & SV_UPDATE_MASK];
// refresh physinfo if needs
if( cl->physinfo_modified )
@ -359,20 +351,23 @@ void SV_WriteFrameToClient( sv_client_t *cl, sizebuf_t *msg )
MSG_WriteString( msg, cl->physinfo );
}
// send the chokecount for r_netgraph
if( cl->surpressCount )
{
MSG_WriteByte( msg, svc_chokecount );
MSG_WriteByte( msg, cl->surpressCount );
cl->surpressCount = 0;
}
// delta encode the events
SV_EmitEvents( cl, frame, msg );
MSG_WriteByte( msg, svc_frame );
MSG_WriteLong( msg, sv.framenum );
MSG_WriteLong( msg, sv.time ); // send a servertime each frame
MSG_WriteLong( msg, sv.frametime );
MSG_WriteLong( msg, lastframe ); // what we are delta'ing from
MSG_WriteByte( msg, cl->surpressCount ); // rate dropped packets
MSG_WriteByte( msg, frame->index ); // send a client index
cl->surpressCount = 0;
// send a servertime each frame
MSG_WriteByte( msg, svc_time );
MSG_WriteFloat( msg, sv.time );
// delta encode the entities
SV_EmitPacketEntities( oldframe, frame, msg );
SV_EmitPacketEntities( cl, oldframe, frame, msg );
}
@ -406,8 +401,8 @@ void SV_BuildClientFrame( sv_client_t *cl )
sv.net_framenum++;
// this is the frame we are creating
frame = &cl->frames[sv.framenum & SV_UPDATE_MASK];
frame->senttime = svs.realtime; // save it for ping calc later
frame = &cl->frames[cl->netchan.incoming_sequence & SV_UPDATE_MASK];
frame->senttime = host.realtime; // save it for ping calculation
// clear everything in this snapshot
frame_ents.num_entities = c_fullsend = 0;
@ -504,40 +499,9 @@ bool SV_SendClientDatagram( sv_client_t *cl )
// send the datagram
Netchan_Transmit( &cl->netchan, msg.cursize, msg.data );
// record the size for rate estimation
cl->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;
return true;
}
/*
=======================
SV_RateDrop
Returns true if the client is over its current
bandwidth estimation and should not be sent another packet
=======================
*/
bool SV_RateDrop( sv_client_t *cl )
{
int i, total = 0;
// never drop over the loopback
if( NET_IsLocalAddress( cl->netchan.remote_address ))
return false;
for( i = 0; i < RATE_MESSAGES; i++ )
total += cl->message_size[i];
if( total > cl->rate )
{
cl->surpressCount++;
cl->message_size[sv.framenum % RATE_MESSAGES] = 0;
return true;
}
return false;
}
/*
=======================
SV_SendClientMessages
@ -556,7 +520,7 @@ void SV_SendClientMessages( void )
{
if( !cl->state ) continue;
if( !cl->edict || (cl->edict->v.flags & (FL_FAKECLIENT|FL_SPECTATOR)))
if( !cl->edict || (cl->edict->v.flags & ( FL_FAKECLIENT|FL_SPECTATOR )))
continue;
// update any userinfo packets that have changed
@ -581,24 +545,27 @@ void SV_SendClientMessages( void )
SV_BroadcastPrintf( PRINT_HIGH, "%s overflowed\n", cl->name );
SV_DropClient( cl );
cl->send_message = true;
cl->netchan.cleartime = 0; // don't choke this message
}
// only send messages if the client has sent one
if( !cl->send_message ) continue;
if( !sv.paused && !Netchan_CanPacket( &cl->netchan ))
{
cl->surpressCount++;
continue; // bandwidth choke
}
if( cl->state == cs_spawned )
{
// don't overrun bandwidth
if( SV_RateDrop( cl )) continue;
SV_SendClientDatagram( cl );
}
else
{
// just update reliable
if( cl->netchan.message.cursize || svs.realtime - cl->netchan.last_sent > 1000 )
if( cl->netchan.message.cursize )
Netchan_Transmit( &cl->netchan, 0, NULL );
}
// yes, message really sended
cl->send_message = false;
}

View File

@ -361,7 +361,7 @@ void SV_FreeEdict( edict_t *pEdict )
Mem_Set( pEdict, 0, sizeof( *pEdict ));
// mark edict as freed
pEdict->freetime = svgame.time;
pEdict->freetime = sv.time;
pEdict->v.nextthink = -1;
pEdict->free = true;
}
@ -376,7 +376,7 @@ edict_t *SV_AllocEdict( void )
pEdict = EDICT_NUM( i );
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if( pEdict->free && ( pEdict->freetime < 2.0 || svgame.time - pEdict->freetime > 0.5 ))
if( pEdict->free && ( pEdict->freetime < 2.0 || sv.time - pEdict->freetime > 0.5 ))
{
SV_InitEdict( pEdict );
return pEdict;
@ -749,10 +749,10 @@ void pfnChangeLevel( const char* s1, const char* s2 )
if( !s1 || s1[0] <= ' ' ) return;
// make sure we don't issue two changelevels
if( svs.changelevel_next_time > svgame.time )
if( svs.changelevel_next_time > sv.time )
return;
svs.changelevel_next_time = svgame.time + 1.0f; // rest 1 secs if failed
svs.changelevel_next_time = sv.time + 1.0f; // rest 1 secs if failed
if( !s2 ) Cbuf_AddText( va( "changelevel %s\n", s1 )); // Quake changlevel
else Cbuf_AddText( va( "changelevel %s %s\n", s1, s2 )); // Half-Life changelevel
@ -3615,6 +3615,7 @@ void SV_SpawnEntities( const char *mapname, script_t *entities )
svgame.globals->maxClients = sv_maxclients->integer;
svgame.globals->mapname = MAKE_STRING( sv.name );
svgame.globals->startspot = MAKE_STRING( sv.startspot );
svgame.globals->time = sv.time;
// spawn the rest of the entities on the map
SV_LoadFromFile( entities );

View File

@ -142,6 +142,8 @@ activate server on changed map, run physics
*/
void SV_ActivateServer( void )
{
int i;
if( !svs.initialized )
{
// probably server.dll doesn't loading
@ -155,13 +157,12 @@ void SV_ActivateServer( void )
// create a baseline for more efficient communications
SV_CreateBaseline();
svgame.frametime = ( sv.frametime * 0.001f );
svgame.time = ( sv.time * 0.001f );
// run two frames to allow everything to settle
if( !sv.loadgame ) SV_Physics();
svgame.time = ( sv.time * 0.001f );
SV_Physics();
for( i = 0; i < 2; i++ )
{
sv.frametime = 0.1f;
SV_Physics();
}
// invoke to refresh all movevars
Mem_Set( &svgame.oldmovevars, 0, sizeof( movevars_t ));
@ -187,6 +188,7 @@ void SV_ActivateServer( void )
sv.state = ss_active;
physinfo->modified = true;
sv.paused = false;
Host_SetServerState( sv.state );
}
@ -296,7 +298,6 @@ bool SV_SpawnServer( const char *mapname, const char *startspot )
svgame.globals->changelevel = false; // will be restored later if needed
svs.timestart = Sys_DoubleTime();
svs.spawncount++; // any partially connected client will be restarted
svs.realtime = 0;
if( startspot )
{
@ -318,7 +319,8 @@ bool SV_SpawnServer( const char *mapname, const char *startspot )
// restore state
sv.paused = paused;
sv.loadgame = loadgame;
sv.time = 1.0f; // server spawn time it's always 1.0 second
// initialize buffers
MSG_Init( &sv.multicast, sv.multicast_buf, sizeof( sv.multicast_buf ));
MSG_Init( &sv.signon, sv.signon_buf, sizeof( sv.signon_buf ));
@ -329,7 +331,6 @@ bool SV_SpawnServer( const char *mapname, const char *startspot )
// needs to reconnect
if( svs.clients[i].state > cs_connected )
svs.clients[i].state = cs_connected;
svs.clients[i].lastframe = -1;
}
// make cvars consistant
@ -339,13 +340,6 @@ bool SV_SpawnServer( const char *mapname, const char *startspot )
Cvar_SetValue( "skill", (float)current_skill );
sv.time = 1000; // server spawn time it's always 1.0 second
sv.frametime = 100;
// half-life compatibility
svgame.globals->time = 1.0f;
svgame.globals->frametime = 0;
// make sure what server name doesn't contain path and extension
FS_FileBase( mapname, sv.name );
com.strncpy( sv.configstrings[CS_NAME], sv.name, CS_SIZE );

View File

@ -6,13 +6,11 @@
#include "common.h"
#include "server.h"
#define HEARTBEAT_SECONDS 300 * 1000 // 300 seconds
#define HEARTBEAT_SECONDS 300.0 // 300 seconds
netadr_t master_adr[MAX_MASTERS]; // address of group servers
cvar_t *sv_zmax;
cvar_t *sv_fps;
cvar_t *sv_enforcetime;
cvar_t *sv_pausable;
cvar_t *sv_newunit;
cvar_t *sv_wateramp;
@ -132,32 +130,6 @@ int SV_CalcPacketLoss( sv_client_t *cl )
return (int)losspercent;
}
/*
===================
SV_GiveMsec
Every few frames, gives all clients an allotment of milliseconds
for their command moves. If they exceed it, assume cheating.
===================
*/
void SV_GiveMsec( void )
{
int i;
sv_client_t *cl;
if( sv.framenum & 15 )
return;
for( i = 0; i < sv_maxclients->integer; i++ )
{
cl = &svs.clients[i];
if( cl->state == cs_free )
continue;
cl->commandMsec = 1800; // 1600 + some slop
}
}
/*
===================
SV_UpdateMovevars
@ -255,24 +227,6 @@ void SV_UpdateServerInfo( void )
serverinfo->modified = false;
}
/*
=================
SV_CalcFrameTime
=================
*/
void SV_CalcFrameTime( void )
{
if( sv_fps->modified )
{
if( sv_fps->value < 10 ) Cvar_Set( "sv_fps", "10" ); // too slow, also, netcode uses a byte
else if( sv_fps->value > 90 ) Cvar_Set( "sv_fps", "90" ); // abusive
sv_fps->modified = false;
}
// calc sv.frametime
sv.frametime = ( 1000 / sv_fps->integer );
}
/*
=================
SV_ReadPackets
@ -320,13 +274,15 @@ void SV_ReadPackets( void )
// this is a valid, sequenced packet, so process it
if( cl->state != cs_zombie )
{
cl->lastmessage = svs.realtime; // don't timeout
cl->lastmessage = host.realtime; // don't timeout
SV_ExecuteClientMessage( cl, &net_message );
}
}
break;
}
if( i != sv_maxclients->integer ) continue;
if( i != sv_maxclients->integer )
continue;
}
}
@ -350,8 +306,8 @@ void SV_CheckTimeouts( void )
float zombiepoint;
int i, numclients = 0;
droppoint = svs.realtime - ( timeout->value * 1000 );
zombiepoint = svs.realtime - ( zombietime->value * 1000 );
droppoint = host.realtime - timeout->value;
zombiepoint = host.realtime - zombietime->value;
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
@ -363,9 +319,12 @@ void SV_CheckTimeouts( void )
// fake clients do not timeout
if( cl->edict && (cl->edict->v.flags & FL_FAKECLIENT ))
cl->lastmessage = svs.realtime;
cl->lastmessage = host.realtime;
// message times may be wrong across a changelevel
if( cl->lastmessage > svs.realtime ) cl->lastmessage = svs.realtime;
if( cl->lastmessage > host.realtime )
cl->lastmessage = host.realtime;
if( cl->state == cs_zombie && cl->lastmessage < zombiepoint )
{
cl->state = cs_free; // can now be reused
@ -443,44 +402,28 @@ SV_RunGameFrame
void SV_RunGameFrame( void )
{
if( !SV_HasActivePlayers()) return;
// we always need to bump framenum, even if we
// don't run the world, otherwise the delta
// compression can get confused when a client
// has the "current" frame
sv.framenum++;
// update progs timings
svgame.globals->frametime = svgame.frametime = ( sv.frametime * 0.001f );
svgame.globals->time = svgame.time = ( sv.time * 0.001f );
// don't run if paused or not in game
if( !sv.paused && CL_IsInGame( ))
SV_Physics();
// never get more than one tic behind
if( sv.time < svs.realtime )
svs.realtime = sv.time;
if( sv.frametime ) SV_Physics();
}
/*
==================
SV_Frame
Host_ServerFrame
==================
*/
void SV_Frame( int time )
void Host_ServerFrame( void )
{
// if server is not active, do nothing
if( !svs.initialized ) return;
svs.realtime += time;
// keep the random time dependent
rand ();
// calc sv.frametime
SV_CalcFrameTime ();
// advances servertime
if( !sv.paused && CL_IsInGame( ))
{
if(!( sv.hostflags & SVF_PLAYERSONLY ))
sv.time += host.frametime;
sv.frametime = host.frametime;
}
else sv.frametime = 0;
// check timeouts
SV_CheckTimeouts ();
@ -488,22 +431,9 @@ void SV_Frame( int time )
// read packets from clients
SV_ReadPackets ();
// move autonomous things around if enough time has passed
if( svs.realtime < sv.time )
{
// never let the time get too far off
if( sv.time - svs.realtime > sv.frametime )
svs.realtime = sv.time - sv.frametime;
NET_Sleep( sv.time - svs.realtime );
return;
}
// update ping based on the last known frame from all clients
SV_CalcPings ();
// give the clients some timeslices
SV_GiveMsec ();
// let everything in the world think and move
SV_RunGameFrame ();
@ -538,31 +468,27 @@ void Master_Heartbeat( void )
char *string;
int i;
if( host.type != HOST_DEDICATED )
return; // only dedicated servers send heartbeats
// pgm post3.19 change, cvar pointer not validated before dereferencing
if( !public_server || !public_server->value )
return; // a private dedicated game
if( host.type != HOST_DEDICATED || !public_server->integer )
return; // only dedicated servers send heartbeats
// check for time wraparound
if( svs.last_heartbeat > svs.realtime )
svs.last_heartbeat = svs.realtime;
if( svs.last_heartbeat > host.realtime )
svs.last_heartbeat = host.realtime;
if(( svs.realtime - svs.last_heartbeat ) < HEARTBEAT_SECONDS )
if(( host.realtime - svs.last_heartbeat ) < HEARTBEAT_SECONDS )
return; // not time to send yet
svs.last_heartbeat = svs.realtime;
svs.last_heartbeat = host.realtime;
// send the same string that we would give for a status OOB command
string = SV_StatusString();
string = SV_StatusString( );
// send to group master
for( i = 0; i < MAX_MASTERS; i++ )
{
if( master_adr[i].port )
{
Msg( "Sending heartbeat to %s\n", NET_AdrToString( master_adr[i] ));
MsgDev( D_INFO, "Sending heartbeat to %s\n", NET_AdrToString( master_adr[i] ));
Netchan_OutOfBandPrint( NS_SERVER, master_adr[i], "heartbeat\n%s", string );
}
}
@ -575,23 +501,19 @@ Master_Shutdown
Informs all masters that this server is going down
=================
*/
void Master_Shutdown (void)
void Master_Shutdown( void )
{
int i;
int i;
if( host.type != HOST_DEDICATED )
return; // only dedicated servers send heartbeats
// pgm post3.19 change, cvar pointer not validated before dereferencing
if (!public_server || !public_server->value)
return; // a private dedicated game
if( host.type != HOST_DEDICATED || !public_server->integer )
return; // only dedicated servers send heartbeats
// send to group master
for(i = 0; i < MAX_MASTERS; i++)
for( i = 0; i < MAX_MASTERS; i++ )
{
if (master_adr[i].port)
if( master_adr[i].port )
{
if( i ) Msg ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
if( i ) MsgDev( D_INFO, "Sending heartbeat to %s\n", NET_AdrToString( master_adr[i] ));
Netchan_OutOfBandPrint( NS_SERVER, master_adr[i], "shutdown" );
}
}
@ -610,7 +532,6 @@ void SV_Init( void )
{
SV_InitOperatorCommands();
rcon_password = Cvar_Get( "rcon_password", "", 0, "remote connect password" );
Cvar_Get ("skill", "1", CVAR_LATCH, "game skill level" );
Cvar_Get ("deathmatch", "0", CVAR_SERVERINFO|CVAR_LATCH, "displays deathmatch state" );
Cvar_Get ("teamplay", "0", CVAR_SERVERINFO|CVAR_LATCH, "displays teamplay state" );
@ -633,14 +554,13 @@ void SV_Init( void )
sv_skyvec_y = Cvar_Get ("sv_skyvec_y", "0", 0, "sky direction y (hl1 compatibility)" );
sv_skyvec_z = Cvar_Get ("sv_skyvec_z", "-1", 0, "sky direction z (hl1 compatibility)" );
sv_fps = Cvar_Get( "sv_fps", "72.1", CVAR_ARCHIVE, "running server physics at" );
rcon_password = Cvar_Get( "rcon_password", "", 0, "remote connect password" );
sv_stepheight = Cvar_Get( "sv_stepheight", "18", CVAR_ARCHIVE|CVAR_PHYSICINFO, "how high you can step up" );
sv_newunit = Cvar_Get( "sv_newunit", "0", 0, "sets to 1 while new unit is loading" );
hostname = Cvar_Get( "sv_hostname", "unnamed", CVAR_SERVERINFO | CVAR_ARCHIVE, "host name" );
timeout = Cvar_Get( "timeout", "125", 0, "connection timeout" );
zombietime = Cvar_Get( "zombietime", "2", 0, "timeout for clients-zombie (who died but not respawned)" );
sv_pausable = Cvar_Get( "pausable", "1", 0, "allow players to pause or not" );
sv_enforcetime = Cvar_Get( "sv_enforcetime", "0", 0, "client enforce time" );
allow_download = Cvar_Get( "allow_download", "0", CVAR_ARCHIVE, "allow download resources" );
sv_noreload = Cvar_Get( "sv_noreload", "0", 0, "ignore savepoints for singleplayer" );
sv_wallbounce = Cvar_Get( "sv_wallbounce", "1.0", CVAR_PHYSICINFO, "bounce factor for client with MOVETYPE_BOUNCE" );

View File

@ -471,7 +471,7 @@ static void PM_SetupMove( playermove_t *pmove, edict_t *clent, usercmd_t *ucmd,
pmove->serverflags = svgame.globals->serverflags; // shared serverflags
pmove->maxspeed = svgame.movevars.maxspeed;
pmove->realtime = svgame.globals->time;
pmove->frametime = ucmd->msec * 0.001f;
pmove->frametime = svgame.globals->frametime = ucmd->msec * 0.001f;
com.strncpy( pmove->physinfo, physinfo, MAX_INFO_STRING );
pmove->clientmaxspeed = clent->v.maxspeed;
pmove->cmd = *ucmd; // setup current cmds
@ -481,7 +481,7 @@ static void PM_SetupMove( playermove_t *pmove, edict_t *clent, usercmd_t *ucmd,
pmove->flWaterJumpTime = clent->v.teleport_time;
pmove->onground = clent->v.groundentity;
pmove->usehull = (clent->v.flags & FL_DUCKING) ? 1 : 0; // reset hull
pmove->bInDuck = clent->v.bInDuck;
pmove->bInDuck = (ucmd->buttons & IN_DUCK) ? 1 : 0; // reset hull;
VectorCopy( clent->v.origin, pmove->origin );
VectorCopy( clent->v.movedir, pmove->movedir );
VectorCopy( clent->v.velocity, pmove->velocity );
@ -598,17 +598,9 @@ SV_RunCmd
*/
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd )
{
edict_t *clent;
vec3_t oldvel;
int i;
cl->commandMsec -= ucmd->msec;
if( cl->commandMsec < 0 && sv_enforcetime->integer )
{
MsgDev( D_INFO, "SV_ClientThink: commandMsec underflow from %s\n", cl->name );
return;
}
edict_t *clent;
vec3_t oldvel;
int i;
clent = cl->edict;
if( !SV_IsValidEdict( clent )) return;
@ -616,8 +608,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd )
PM_CheckMovingGround( clent, ucmd->msec * 0.001f );
VectorCopy( clent->v.viewangles, svgame.pmove->oldangles ); // save oldangles
if( !clent->v.fixangle )
VectorCopy( ucmd->viewangles, clent->v.viewangles );
if( !clent->v.fixangle ) VectorCopy( ucmd->viewangles, clent->v.viewangles );
// copy player buttons
clent->v.button = ucmd->buttons;
@ -648,7 +639,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd )
VectorCopy( clent->v.basevelocity, clent->v.clbasevelocity );
}
if(( sv_maxclients->integer <= 1 ) && !CL_IsInGame( ) || ( clent->v.flags & FL_FROZEN ) || ( sv.framenum < 3 ))
if(( sv_maxclients->integer <= 1 ) && !CL_IsInGame( ) || ( clent->v.flags & FL_FROZEN ))
ucmd->msec = 0; // pause
// setup playermove state
@ -710,6 +701,6 @@ void SV_PostRunCmd( sv_client_t *cl )
else svgame.dllFuncs.pfnPlayerPostThink( clent );
// restore frametime
svgame.globals->frametime = svgame.frametime;
svgame.globals->frametime = sv.frametime;
svgame.dllFuncs.pfnCmdEnd( cl->edict );
}

View File

@ -161,13 +161,13 @@ bool SV_RunThink( edict_t *ent )
float thinktime;
thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || thinktime > svgame.globals->time + svgame.globals->frametime )
if( thinktime <= 0.0f || thinktime > sv.time + sv.frametime )
return true;
if( thinktime < svgame.globals->time )
thinktime = svgame.globals->time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
if( thinktime < sv.time )
thinktime = sv.time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
ent->v.nextthink = 0;
svgame.globals->time = thinktime;
svgame.dllFuncs.pfnThink( ent );
@ -624,8 +624,8 @@ SV_AddGravity
void SV_AddGravity( edict_t *ent )
{
if( ent->v.gravity ) // gravity modifier
ent->v.velocity[2] -= sv_gravity->value * ent->v.gravity * svgame.frametime;
else ent->v.velocity[2] -= sv_gravity->value * svgame.frametime;
ent->v.velocity[2] -= sv_gravity->value * ent->v.gravity * sv.frametime;
else ent->v.velocity[2] -= sv_gravity->value * sv.frametime;
}
void SV_AddHalfGravity( edict_t *ent, float timestep )
@ -638,7 +638,7 @@ void SV_AddHalfGravity( edict_t *ent, float timestep )
// Add 1/2 of the total gravitational effects over this timestep
ent->v.velocity[2] -= ( 0.5f * ent_gravity * sv_gravity->value * timestep );
ent->v.velocity[2] += ent->v.basevelocity[2] * svgame.frametime;
ent->v.velocity[2] += ent->v.basevelocity[2] * sv.frametime;
ent->v.basevelocity[2] = 0.0f;
// bound velocity
@ -680,12 +680,7 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int
if( apush[YAW] && ent->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( ent, true )) != NULL )
{
// Because we can run multiple ticks per server frame,
// accumulate a total offset here instead of straight
// setting it. The engine will reset anglechange to 0
// when the message is actually sent to the client
cl->anglechangetotal += apush[1];
cl->anglechangefinal = apush[1];
cl->addangle = apush[1];
ent->v.fixangle = 2;
}
@ -953,7 +948,7 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
if( ed->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( ed, true )) != NULL )
{
cl->anglechangetotal = cl->anglechangefinal = 0.0f;
cl->addangle = 0.0f;
ed->v.fixangle = 0;
}
@ -1158,7 +1153,7 @@ void SV_PushComplex( edict_t *pusher, float movetime )
if( ed->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( ed, true )) != NULL )
{
cl->anglechangetotal = cl->anglechangefinal = 0.0f;
cl->addangle = 0.0f;
ed->v.fixangle = 0;
}
@ -1191,12 +1186,12 @@ void SV_Physics_Pusher( edict_t *ent )
oldtime = ent->v.ltime;
thinktime = ent->v.nextthink;
if( thinktime < ent->v.ltime + svgame.frametime )
if( thinktime < ent->v.ltime + sv.frametime )
{
movetime = thinktime - ent->v.ltime;
if( movetime < 0.0f ) movetime = 0.0f;
}
else movetime = svgame.frametime;
else movetime = sv.frametime;
if( movetime )
{
@ -1335,8 +1330,8 @@ void SV_Physics_Noclip( edict_t *ent )
SV_CheckWater( ent );
VectorMA( ent->v.origin, svgame.frametime, ent->v.velocity, ent->v.origin );
VectorMA( ent->v.angles, svgame.frametime, ent->v.avelocity, ent->v.angles );
VectorMA( ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin );
VectorMA( ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles );
SV_LinkEdict( ent, false ); // nocip ents never touch triggers
}
@ -1430,10 +1425,10 @@ void SV_Physics_Toss( edict_t *ent )
{
case MOVETYPE_TOSS:
case MOVETYPE_BOUNCE:
SV_AngularMove( ent, svgame.frametime, ent->v.friction );
SV_AngularMove( ent, sv.frametime, ent->v.friction );
break;
default:
SV_AngularMove( ent, svgame.frametime, 0.0f );
SV_AngularMove( ent, sv.frametime, 0.0f );
break;
}
@ -1443,7 +1438,7 @@ void SV_Physics_Toss( edict_t *ent )
VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
SV_CheckVelocity( ent );
VectorScale( ent->v.velocity, svgame.frametime, move );
VectorScale( ent->v.velocity, sv.frametime, move );
VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
trace = SV_PushEntity( ent, move, vec3_origin, NULL );
@ -1479,7 +1474,7 @@ void SV_Physics_Toss( edict_t *ent )
{
float vel;
if( ent->v.velocity[2] < sv_gravity->value * svgame.frametime )
if( ent->v.velocity[2] < sv_gravity->value * sv.frametime )
{
// we're rolling on the ground, add static friction.
ent->v.groundentity = trace.pHit;
@ -1497,7 +1492,7 @@ void SV_Physics_Toss( edict_t *ent )
}
else
{
VectorScale( ent->v.velocity, (1.0f - trace.flFraction) * svgame.frametime * 0.9f, move );
VectorScale( ent->v.velocity, (1.0f - trace.flFraction) * sv.frametime * 0.9f, move );
trace = SV_PushEntity( ent, move, vec3_origin, NULL );
if( ent->free ) return;
}
@ -1548,14 +1543,14 @@ void SV_Physics_Step( edict_t *ent )
{
if(!( ent->v.flags & (FL_SWIM|FL_FLOAT) && ent->v.waterlevel > 0 ))
{
if( ent->v.velocity[2] < ( sv_gravity->value * -svgame.frametime ))
if( ent->v.velocity[2] < ( sv_gravity->value * -sv.frametime ))
{
hitsound = true;
}
if( !inwater )
{
SV_AddHalfGravity( ent, svgame.frametime );
SV_AddHalfGravity( ent, sv.frametime );
isfalling = true;
}
}
@ -1564,13 +1559,13 @@ void SV_Physics_Step( edict_t *ent )
if( ent->v.waterlevel > 1 )
{
VectorScale( ent->v.velocity, 0.9f, ent->v.velocity );
ent->v.velocity[2] += ( ent->v.skin * svgame.frametime );
ent->v.velocity[2] += ( ent->v.skin * sv.frametime );
}
else if( ent->v.waterlevel == 1 )
{
if( ent->v.velocity[2] > 0.0f )
ent->v.velocity[2] = svgame.frametime;
ent->v.velocity[2] -= ( ent->v.skin * svgame.frametime );
ent->v.velocity[2] = sv.frametime;
ent->v.velocity[2] -= ( ent->v.skin * sv.frametime );
}
}
}
@ -1599,7 +1594,7 @@ void SV_Physics_Step( edict_t *ent )
if( speed )
{
control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
newspeed = speed - svgame.frametime * control * friction;
newspeed = speed - sv.frametime * control * friction;
if( newspeed < 0.0f )
newspeed = 0.0f;
@ -1612,10 +1607,10 @@ void SV_Physics_Step( edict_t *ent )
VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
SV_AngularMove( ent, svgame.frametime, friction );
SV_AngularMove( ent, sv.frametime, friction );
SV_CheckVelocity( ent );
SV_TryMove( ent, svgame.frametime, NULL );
SV_TryMove( ent, sv.frametime, NULL );
SV_CheckVelocity( ent );
VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
@ -1652,7 +1647,7 @@ void SV_Physics_Step( edict_t *ent )
if(!( ent->v.flags & FL_ONGROUND ) && isfalling )
{
SV_AddHalfGravity( ent, svgame.frametime );
SV_AddHalfGravity( ent, sv.frametime );
}
if( !SV_RunThink( ent )) return;
@ -1679,7 +1674,7 @@ void SV_Physics_Conveyor( edict_t *ent )
vec3_t point, end;
VectorScale( ent->v.movedir, ent->v.speed, v );
VectorScale( v, svgame.frametime, move );
VectorScale( v, sv.frametime, move );
for( i = 0; i < svgame.globals->maxClients; i++ )
{
@ -1704,7 +1699,7 @@ void SV_Physics_Conveyor( edict_t *ent )
v[2] = ent->v.speed * com.sqrt( 1.0f - tr.vecPlaneNormal[2] * tr.vecPlaneNormal[2] ) / tr.vecPlaneNormal[2];
if(DotProduct( ent->v.movedir, tr.vecPlaneNormal) > 0.0f )
v[2] = -v[2]; // then we're moving down
move[2] = v[2] * svgame.frametime;
move[2] = v[2] * sv.frametime;
}
VectorAdd( player->v.origin, move, end );
tr = SV_Move( player->v.origin, player->v.mins, player->v.maxs, end, MOVE_NORMAL, player );
@ -1736,7 +1731,7 @@ static void SV_Physics_Entity( edict_t *ent )
if(!( ent->v.flags & FL_BASEVELOCITY ) && !VectorIsNull( ent->v.basevelocity ))
{
// Apply momentum (add in half of the previous frame of velocity first)
VectorMA( ent->v.velocity, 1.0f + (svgame.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
VectorMA( ent->v.velocity, 1.0f + (sv.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
VectorClear( ent->v.basevelocity );
}
ent->v.flags &= ~FL_BASEVELOCITY;
@ -1812,6 +1807,9 @@ void SV_Physics( void )
int i;
edict_t *ent;
svgame.globals->time = sv.time;
svgame.globals->frametime = sv.frametime;
// let the progs know that a new frame has started
svgame.dllFuncs.pfnStartFrame();
@ -1840,7 +1838,7 @@ void SV_Physics( void )
}
// let everything in the world think and move
CM_Frame( svgame.frametime );
CM_Frame( sv.frametime );
// at end of frame kill all entities which supposed to it
SV_FreeOldEntities();
@ -1849,7 +1847,4 @@ void SV_Physics( void )
svgame.globals->force_retouch = max( 0, svgame.globals->force_retouch - 1 );
svgame.dllFuncs.pfnEndFrame();
if( !( sv.hostflags & SVF_PLAYERSONLY ))
sv.time += sv.frametime;
}

View File

@ -294,7 +294,7 @@ void SV_BuildSaveComment( char *text, int maxlength )
{
const char *pName;
edict_t *pWorld = EDICT_NUM( 0 );
float time = svgame.time;
float time = sv.time;
if( pWorld && pWorld->v.message )
{
@ -1033,7 +1033,7 @@ int SV_LoadGameState( char const *level, bool createPlayers )
SV_SaveFinish( pSaveData );
// restore server time
sv.time = header.time * 1000;
sv.time = header.time;
return 1;
}
@ -1188,7 +1188,7 @@ void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName )
SV_EntityPatchRead( pSaveData, currentLevelData.levelList[i].mapName );
pSaveData->time = (sv.time * 0.001f); // - header.time;
pSaveData->time = sv.time; // - header.time;
pSaveData->fUseLandmark = true;
// calculate landmark offset

View File

@ -252,7 +252,7 @@ static void UI_PlayerSetup_Ownerdraw( void *self )
// update renderer timings
uiPlayerSetup.refdef.time = realtime;
uiPlayerSetup.refdef.frametime = cls.frametime;
uiPlayerSetup.refdef.frametime = cl.time - cl.oldtime;
// draw the player model
re->AddRefEntity( uiPlayerSetup.ent, ED_NORMAL, -1 );

View File

@ -125,10 +125,9 @@ Cbuf_Execute
*/
void Cbuf_Execute( void )
{
int i;
char *text;
char line[MAX_CMD_LINE];
int quotes;
int i, quotes;
while( cmd_text.cursize )
{

View File

@ -56,7 +56,6 @@ typedef struct system_s
bool hooked_out;
bool stuffcmdsrun;
byte packet_received[MAX_MSGLEN]; // network data
int msg_time; // GetMessage time
char ModuleName[4096]; // exe.filename
HANDLE hMutex;
@ -145,7 +144,6 @@ void Sys_ParseCommandLine (LPSTR lpCmdLine);
void Sys_LookupInstance( void );
void Sys_NewInstance( const char *name, const char *fmsg );
double Sys_DoubleTime( void );
dword Sys_Milliseconds( void );
char *Sys_GetClipboardData( void );
char *Sys_GetCurrentUser( void );
bool Sys_GetModuleName( char *buffer, size_t length );
@ -168,7 +166,7 @@ void Sys_Print(const char *pMsg);
void Sys_Msg( const char *pMsg, ... );
void Sys_MsgDev( int level, const char *pMsg, ... );
sys_event_t Sys_GetEvent( void );
void Sys_QueEvent( int time, ev_type_t type, int value, int value2, int length, void *ptr );
void Sys_QueEvent( ev_type_t type, int value, int value2, int length, void *ptr );
int Sys_GetThreadWork( void );
void Sys_ThreadWorkerFunction( int threadnum );
void Sys_ThreadSetDefault( void );

View File

@ -216,7 +216,6 @@ void Sys_GetStdAPI( void )
com.Com_GetProcAddress = Sys_GetProcAddress; // gpa
com.Com_ShellExecute = Sys_ShellExecute; // shell execute
com.Com_DoubleTime = Sys_DoubleTime; // hi-res timer
com.Com_Milliseconds = Sys_Milliseconds;
// built-in imagelib functions
com.ImageLoad = FS_LoadImage; // load image from disk or wad-file
@ -789,24 +788,6 @@ double Sys_DoubleTime( void )
return Clock.curtime;
}
/*
================
Sys_Milliseconds
================
*/
dword Sys_Milliseconds( void )
{
dword curtime;
if( !Clock.timebase )
{
timeBeginPeriod( 1 );
Clock.timebase = timeGetTime();
}
curtime = timeGetTime() - Clock.timebase;
return curtime;
}
/*
================
Sys_GetClipboardData
@ -1398,7 +1379,7 @@ Ptr should either be null, or point to a block of data that can
be freed by the game later.
================
*/
void Sys_QueEvent( int time, ev_type_t type, int value, int value2, int length, void *ptr )
void Sys_QueEvent( ev_type_t type, int value, int value2, int length, void *ptr )
{
sys_event_t *ev;
@ -1412,11 +1393,6 @@ void Sys_QueEvent( int time, ev_type_t type, int value, int value2, int length,
}
event_head++;
// presets
if( time == 0 ) time = Sys_Milliseconds();
else if( time == -1 ) time = Sys.msg_time;
ev->time = time;
ev->type = type;
ev->value[0] = value;
ev->value[1] = value2;
@ -1446,12 +1422,11 @@ sys_event_t Sys_GetEvent( void )
// pump the message loop
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
{
if(!GetMessage( &msg, NULL, 0, 0 ))
if( !GetMessage( &msg, NULL, 0, 0 ))
{
Sys.error = true;
Sys_Exit();
}
Sys.msg_time = msg.time;
TranslateMessage(&msg );
DispatchMessage( &msg );
}
@ -1463,10 +1438,10 @@ sys_event_t Sys_GetEvent( void )
char *b;
int len;
len = com_strlen( s ) + 1;
len = com.strlen( s ) + 1;
b = Malloc( len );
com.strncpy( b, s, len - 1 );
Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
Sys_QueEvent( SE_CONSOLE, 0, 0, len, b );
}
// return if we have data
@ -1478,7 +1453,6 @@ sys_event_t Sys_GetEvent( void )
// create an empty event to return
Mem_Set( &ev, 0, sizeof( ev ));
ev.time = timeGetTime(); // should be replace with Sys_Milliseconds ?
return ev;
}

View File

@ -196,15 +196,12 @@ typedef enum
SE_KEY, // ev.value[0] is a key code, ev.value[1] is the down flag
SE_CHAR, // ev.value[0] is an ascii char
SE_MOUSE, // ev.value[0] and ev.value[1] are reletive signed x / y moves
SE_JOYSTICK, // evValue is an axis number and evValue2 is the current state (-127 to 127)
SE_CONSOLE, // ev.data is a char*
SE_PACKET, // ev.data is a netadr_t followed by data bytes to ev.length
} ev_type_t;
typedef struct
{
ev_type_t type;
int time; // actual timestamp
int value[2];
void *data;
size_t length;
@ -492,7 +489,7 @@ typedef struct stdilib_api_s
void (*exit)( void ); // normal silent termination
void (*sleep)( int msec ); // sleep for some msec
char *(*clipboard)( void ); // get clipboard data
void (*queevent)( int time, ev_type_t type, int value, int value2, int length, void *ptr );
void (*queevent)( ev_type_t type, int value, int value2, int length, void *ptr );
sys_event_t (*getevent)( void ); // get system events
// crclib.c funcs
@ -663,7 +660,6 @@ typedef struct stdilib_api_s
bool (*Com_FreeLibrary)( dll_info_t *dll ); // free library
void*(*Com_GetProcAddress)( dll_info_t *dll, const char* name ); // gpa
double (*Com_DoubleTime)( void ); // hi-res timer
dword (*Com_Milliseconds)( void ); // hi-res timer
void (*Com_ShellExecute)( const char *p1, const char *p2, bool exit );// execute shell programs
// built-in imagelib functions
@ -1024,7 +1020,6 @@ misc utils
#define Sys_Quit com.exit
#define Sys_Break com.abort
#define Sys_DoubleTime com.Com_DoubleTime
#define Sys_Milliseconds com.Com_Milliseconds
#define GetNumThreads com.Com_NumThreads
#define ThreadLock com.Com_ThreadLock
#define ThreadUnlock com.Com_ThreadUnlock

View File

@ -51,4 +51,5 @@ Xash 0.72 Stable 13.12.10
27.implement dlights OK
28.rework SV_PointContents
29.implement sound library
30.rewrite engine timer
30.rewrite engine timer OK
31.fixup demos