21 Jun 2010
This commit is contained in:
parent
5caebac360
commit
c593e56413
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
||||
//
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
148
engine/host.c
148
engine/host.c
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Reference in New Issue