diff options
author | Andrey Nazarov <skuller@skuller.net> | 2009-03-24 14:54:32 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2009-03-24 14:54:32 +0000 |
commit | 385ccd0e9a518933019a8c6f1fecad2ae660b766 (patch) | |
tree | 6b86f96c16a6d89a5803fce5081af64ac76165ab | |
parent | fd8cba03f93046e892a732da27f221406f726b7c (diff) |
Implemented a workaround for Q2 pmove bug resulting in swimming velocity in ‘z’ direction being heavily dependent of client's FPS when ‘+moveup’ is used.
New minor Q2PRO protocol version 1015.
Fixed command completion mode cursor positioning.
Disable ‘cl_updaterate’ variable until it is fully supported.
Added ‘sv_waterjump_hack’ variable, enabling the pmove bug workaround described above for supported clients.
Properly count connected MVD spectators in menus.
Update MVD menus as spectators join/leave the channels.
-rwxr-xr-x | debian/rules | 2 | ||||
-rw-r--r-- | source/cl_main.c | 12 | ||||
-rw-r--r-- | source/cl_parse.c | 61 | ||||
-rw-r--r-- | source/cl_pred.c | 2 | ||||
-rw-r--r-- | source/cmd.c | 5 | ||||
-rw-r--r-- | source/gl_surf.c | 2 | ||||
-rw-r--r-- | source/mvd_client.c | 2 | ||||
-rw-r--r-- | source/mvd_game.c | 24 | ||||
-rw-r--r-- | source/mvd_local.h | 1 | ||||
-rw-r--r-- | source/pmove.c | 51 | ||||
-rw-r--r-- | source/pmove.h | 18 | ||||
-rw-r--r-- | source/prompt.c | 18 | ||||
-rw-r--r-- | source/protocol.h | 3 | ||||
-rw-r--r-- | source/sv_ents.c | 604 | ||||
-rw-r--r-- | source/sv_init.c | 16 | ||||
-rw-r--r-- | source/sv_local.h | 304 | ||||
-rw-r--r-- | source/sv_main.c | 62 | ||||
-rw-r--r-- | source/sv_mvd.c | 8 | ||||
-rw-r--r-- | source/sv_send.c | 2 | ||||
-rw-r--r-- | source/sv_user.c | 9 | ||||
-rw-r--r-- | source/sv_world.c | 2 | ||||
-rw-r--r-- | wiki/download.mdwn | 33 | ||||
-rw-r--r-- | wiki/local.css | 2 |
23 files changed, 677 insertions, 566 deletions
diff --git a/debian/rules b/debian/rules index 68cc988..72a59c2 100755 --- a/debian/rules +++ b/debian/rules @@ -5,6 +5,6 @@ include /usr/share/cdbs/1/class/autotools.mk DEB_DH_INSTALL_SOURCEDIR := debian/tmp -DEB_CONFIGURE_NORMAL_ARGS := --prefix=$(DEB_CONFIGURE_PREFIX) \ +DEB_CONFIGURE_NORMAL_ARGS := --prefix=$(DEB_CONFIGURE_PREFIX) --cpu=$(DEB_HOST_GNU_CPU) \ --enable-png --enable-jpg --enable-dsound --enable-server --enable-anticheat --enable-openffa diff --git a/source/cl_main.c b/source/cl_main.c index 55fee6e..ed28ba0 100644 --- a/source/cl_main.c +++ b/source/cl_main.c @@ -69,9 +69,11 @@ cvar_t *cl_changemapcmd; cvar_t *cl_beginmapcmd; cvar_t *cl_gibs; +#if USE_FPS cvar_t *cl_updaterate; +#endif -cvar_t *cl_protocol; +cvar_t *cl_protocol; cvar_t *gender_auto; @@ -218,6 +220,7 @@ static void CL_UpdatePredictSetting( void ) { MSG_FlushTo( &cls.netchan->message ); } +#if USE_FPS static void CL_UpdateRateSetting( void ) { if( cls.state < ca_connected ) { return; @@ -231,6 +234,7 @@ static void CL_UpdateRateSetting( void ) { MSG_WriteShort( cl_updaterate->integer ); MSG_FlushTo( &cls.netchan->message ); } +#endif /* =================== @@ -1939,7 +1943,9 @@ void CL_RequestNextDownload ( void ) { CL_UpdateGibSetting(); CL_UpdateFootstepsSetting(); CL_UpdatePredictSetting(); +#if USE_FPS CL_UpdateRateSetting(); +#endif cls.state = ca_precached; } @@ -2359,9 +2365,11 @@ static void cl_predict_changed( cvar_t *self ) { CL_UpdatePredictSetting(); } +#if USE_FPS static void cl_updaterate_changed( cvar_t *self ) { CL_UpdateRateSetting(); } +#endif static const cmdreg_t c_client[] = { { "cmd", CL_ForwardToServer_f }, @@ -2467,8 +2475,10 @@ static void CL_InitLocal ( void ) { cl_gibs = Cvar_Get( "cl_gibs", "1", 0 ); cl_gibs->changed = cl_gibs_changed; +#if USE_FPS cl_updaterate = Cvar_Get( "cl_updaterate", "0", 0 ); cl_updaterate->changed = cl_updaterate_changed; +#endif cl_chat_notify = Cvar_Get( "cl_chat_notify", "1", 0 ); cl_chat_sound = Cvar_Get( "cl_chat_sound", "misc/talk.wav", 0 ); diff --git a/source/cl_parse.c b/source/cl_parse.c index dde6ed3..a98f468 100644 --- a/source/cl_parse.c +++ b/source/cl_parse.c @@ -717,7 +717,7 @@ static void CL_ParseConfigstring( int index ) { cl.image_precache[index-CS_IMAGES] = R_RegisterPic (string); } else if (index >= CS_PLAYERSKINS && index < CS_PLAYERSKINS+MAX_CLIENTS) { CL_LoadClientinfo( &cl.clientinfo[index - CS_PLAYERSKINS], string ); - } else if( index == CS_AIRACCEL && !cl.pmp.qwmod ) { + } else if( index == CS_AIRACCEL && !cl.pmp.qwmode ) { cl.pmp.airaccelerate = atoi( string ) ? qtrue : qfalse; } } @@ -827,16 +827,7 @@ static void CL_ParseServerData( void ) { MSG_ReadString( levelname, sizeof( levelname ) ); // setup default pmove parameters - cl.pmp.speedMultiplier = 1; - cl.pmp.maxspeed = 300; -// cl.pmp.upspeed = 350; - cl.pmp.friction = 6; - cl.pmp.waterfriction = 1; - cl.pmp.flyfriction = 9; - cl.pmp.airaccelerate = 0; -#ifdef PMOVE_HACK - cl.pmp.highprec = qtrue; -#endif + PmoveInit( &cl.pmp ); // setup default frame times cl.frametime = 100; @@ -860,15 +851,13 @@ static void CL_ParseServerData( void ) { } Com_DPrintf( "Using minor R1Q2 protocol version %d\n", i ); cls.protocolVersion = i; + MSG_ReadByte(); // used to be advanced deltas i = MSG_ReadByte(); - if( i ) { // seems to be no longer used - Com_DPrintf( "R1Q2 advancedDeltas enabled\n" ); - } - cl.pmp.strafeHack = MSG_ReadByte(); - if( cl.pmp.strafeHack ) { - Com_DPrintf( "R1Q2 strafeHack enabled\n" ); + if( i ) { + Com_DPrintf( "R1Q2 strafejump hack enabled\n" ); + cl.pmp.strafehack = qtrue; } - cl.pmp.speedMultiplier = 2; + cl.pmp.speedmult = 2; } else if( cls.serverProtocol == PROTOCOL_VERSION_Q2PRO ) { i = MSG_ReadShort(); if( !Q2PRO_SUPPORTED( i ) ) { @@ -879,24 +868,26 @@ static void CL_ParseServerData( void ) { Com_DPrintf( "Using minor Q2PRO protocol version %d\n", i ); cls.protocolVersion = i; MSG_ReadByte(); // used to be gametype - cl.pmp.strafeHack = MSG_ReadByte(); - cl.pmp.qwmod = MSG_ReadByte(); //atu QWMod - cl.pmp.speedMultiplier = 2; - cl.pmp.flyfix = qtrue; - cl.pmp.flyfriction = 4; - - if( cl.pmp.strafeHack ) { - Com_DPrintf( "Q2PRO strafeHack enabled\n" ); + i = MSG_ReadByte(); + if( i ) { + Com_DPrintf( "Q2PRO strafejump hack enabled\n" ); + cl.pmp.strafehack = qtrue; + } + i = MSG_ReadByte(); //atu QWMod + if( i ) { + Com_DPrintf( "Q2PRO QW mode enabled\n" ); + PmoveEnableQW( &cl.pmp ); } - if( cl.pmp.qwmod ) { - Com_DPrintf( "Q2PRO QWMod enabled\n" ); - - cl.pmp.maxspeed = 320; - //cl.pmp.upspeed = ((cl.pmp.qwmod == 2) ? 310 : 350); - cl.pmp.friction = 4; - cl.pmp.waterfriction = 4; - cl.pmp.airaccelerate = qtrue; + if( cls.protocolVersion >= PROTOCOL_VERSION_Q2PRO_WATERJUMP_HACK ) { + i = MSG_ReadByte(); + if( i ) { + Com_DPrintf( "Q2PRO waterjump hack enabled\n" ); + cl.pmp.waterhack = qtrue; + } } + cl.pmp.speedmult = 2; + cl.pmp.flyhack = qtrue; // fly hack is unconditionally enabled + cl.pmp.flyfriction = 4; } if( cl.clientNum == -1 ) { @@ -1374,6 +1365,7 @@ static void CL_ParseSetting( void ) { value = MSG_ReadLong(); switch( index ) { +#if USE_FPS case SVS_FPS: if( !value ) { value = 10; @@ -1381,6 +1373,7 @@ static void CL_ParseSetting( void ) { cl.frametime = 1000 / value; cl.framefrac = value * 0.001f; break; +#endif default: break; } diff --git a/source/cl_pred.c b/source/cl_pred.c index 05edcb3..c240aba 100644 --- a/source/cl_pred.c +++ b/source/cl_pred.c @@ -68,7 +68,7 @@ void CL_CheckPredictionError( void ) { VectorClear( cl.prediction_error ); } else { if( cl_showmiss->integer && ( delta[0] || delta[1] || delta[2] ) ) { - Com_Printf( "prediction miss on %i: %i\n", cl.frame.number, len ); + Com_Printf( "prediction miss on %i: %i (%d %d %d)\n", cl.frame.number, len, delta[0], delta[1], delta[2]); } VectorCopy( ps->pmove.origin, cl.predicted_origins[cmd] ); diff --git a/source/cmd.c b/source/cmd.c index c575c55..8e9ac11 100644 --- a/source/cmd.c +++ b/source/cmd.c @@ -521,6 +521,7 @@ static char *cmd_null_string = ""; // complete command string, left untouched static char cmd_string[MAX_STRING_CHARS]; static size_t cmd_string_len; +size_t cmd_string_tail; // offsets of individual tokens into cmd_string static size_t cmd_offsets[MAX_STRING_TOKENS]; @@ -553,7 +554,7 @@ int Cmd_FindArgForOffset( size_t offset ) { break; } } - return i - 1; + return i - 1; } /* @@ -1075,12 +1076,14 @@ void Cmd_TokenizeString( const char *text, qboolean macroExpand ) { } // strip off any trailing whitespace + cmd_string_tail = 0; while( cmd_string_len ) { if( cmd_string[ cmd_string_len - 1 ] > ' ' ) { break; } cmd_string[ cmd_string_len - 1 ] = 0; cmd_string_len--; + cmd_string_tail++; } dest = cmd_data; diff --git a/source/gl_surf.c b/source/gl_surf.c index c069575..f39fd53 100644 --- a/source/gl_surf.c +++ b/source/gl_surf.c @@ -344,7 +344,7 @@ void GL_LoadWorld( const char *name ) { gl_static.world.cache = bsp; - // registers all texinfo + // register all texinfo for( i = 0, info = bsp->texinfo; i < bsp->numtexinfo; i++, info++ ) { Q_concat( buffer, sizeof( buffer ), "textures/", info->name, ".wal", NULL ); image = IMG_Find( buffer, it_wall ); diff --git a/source/mvd_client.c b/source/mvd_client.c index 3219ddb..7d9e314 100644 --- a/source/mvd_client.c +++ b/source/mvd_client.c @@ -680,6 +680,7 @@ static qboolean gtv_wait_stop( mvd_t *mvd ) { stop: mvd->state = MVD_READING; + mvd->dirty = qtrue; return qtrue; } @@ -711,6 +712,7 @@ static void gtv_wait_start( mvd_t *mvd ) { } mvd->underflows++; mvd->state = MVD_WAITING; + mvd->dirty = qtrue; // notify spectators if( Com_IsDedicated() ) { diff --git a/source/mvd_game.c b/source/mvd_game.c index 22bedec..270c00a 100644 --- a/source/mvd_game.c +++ b/source/mvd_game.c @@ -125,6 +125,18 @@ static void MVD_LayoutClients( mvd_client_t *client ) { client->layout_time = svs.realtime; } +static int MVD_CountClients( mvd_t *mvd ) { + mvd_client_t *c; + int count = 0; + + LIST_FOR_EACH( mvd_client_t, c, &mvd->clients, entry ) { + if( c->cl->state == cs_spawned ) { + count++; + } + } + return count; +} + static void MVD_LayoutChannels( mvd_client_t *client ) { static const char header[] = "xv 32 yv 8 picn inventory " @@ -163,8 +175,7 @@ static void MVD_LayoutChannels( mvd_client_t *client ) { mvd == client->mvd ? "2" : "", cursor == client->layout_cursor ? 0x8d : 0x20, mvd->name, mvd->mapname, - List_Count( &mvd->clients ), - mvd->numplayers ); + MVD_CountClients( mvd ), mvd->numplayers ); if( len >= sizeof( buffer ) ) { continue; } @@ -231,7 +242,7 @@ static void MVD_LayoutMenu( mvd_client_t *client ) { total = Q_scnprintf( layout, sizeof( layout ), format, cur[0], client->target ? "Leave" : "Enter", cur[1], - cur[2], List_Count( &client->mvd->clients ), + cur[2], MVD_CountClients( client->mvd ), cur[3], List_Count( &mvd_channel_list ), cur[4], cur[5], ( client->uf & UF_MUTE_OBSERVERS ) ? YES : NO, cur[6], ( client->uf & UF_MUTE_MISC ) ? YES : NO, @@ -340,7 +351,7 @@ static void MVD_UpdateLayouts( mvd_t *mvd ) { } break; case LAYOUT_MENU: - if( !client->layout_time ) { + if( mvd->dirty || !client->layout_time ) { MVD_LayoutMenu( client ); } break; @@ -358,6 +369,8 @@ static void MVD_UpdateLayouts( mvd_t *mvd ) { break; } } + + mvd->dirty = qfalse; } @@ -1327,6 +1340,8 @@ static void MVD_GameClientBegin( edict_t *ent ) { VectorCopy( mvd->spawnAngles, client->ps.viewangles ); MVD_FollowStop( client ); } + + mvd_dirty = qtrue; } static void MVD_GameClientUserinfoChanged( edict_t *ent, char *userinfo ) { @@ -1548,6 +1563,7 @@ update: MVD_InfoSet( "mvd_channels", va( "%d", List_Count( &mvd_channel_list ) ) ); mvd_dirty = qfalse; } + if( numplayers != mvd_numplayers ) { MVD_InfoSet( "mvd_players", va( "%d", numplayers ) ); mvd_numplayers = numplayers; diff --git a/source/mvd_local.h b/source/mvd_local.h index da578f3..29af571 100644 --- a/source/mvd_local.h +++ b/source/mvd_local.h @@ -145,6 +145,7 @@ typedef struct mvd_s { char layout[MAX_STRING_CHARS]; char oldscores[MAX_STRING_CHARS]; // layout is copied here qboolean intermission; + qboolean dirty; // UDP client list list_t clients; diff --git a/source/pmove.c b/source/pmove.c index 546b935..8bc3843 100644 --- a/source/pmove.c +++ b/source/pmove.c @@ -504,8 +504,7 @@ static void PM_WaterMove (void) VectorScale (wishvel, pmp->maxspeed / wishspeed, wishvel); wishspeed = pmp->maxspeed; } - wishspeed *= ( (pmp->qwmod) ? 0.7 : 0.5 ); //atu QWMod - + wishspeed *= pmp->watermult; PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); @@ -630,7 +629,7 @@ static void PM_CategorizePosition (void) // see if standing on something solid point[0] = pml.origin[0]; point[1] = pml.origin[1]; - point[2] = pml.origin[2] - ( (pmp->qwmod == 2) ? 1 : 0.25 ); //atu QWMod + point[2] = pml.origin[2] - 0.25f; if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel) { pm->s.pm_flags &= ~PMF_ON_GROUND; @@ -663,7 +662,7 @@ static void PM_CategorizePosition (void) { // just hit the ground pm->s.pm_flags |= PMF_ON_GROUND; // don't do landing time if we were just going down a slope - if (pml.velocity[2] < -200 && !pmp->strafeHack ) + if (pml.velocity[2] < -200 && !pmp->strafehack ) { pm->s.pm_flags |= PMF_TIME_LAND; // don't allow another jump for a little while @@ -742,9 +741,14 @@ static void PM_CheckJump (void) { // swimming, not jumping pm->groundentity = NULL; + if (pmp->waterhack) + return; + if (pml.velocity[2] <= -300) return; + // FIXME: makes velocity dependent on client FPS, + // even causes prediction misses if (pm->watertype == CONTENTS_WATER) pml.velocity[2] = 100; else if (pm->watertype == CONTENTS_SLIME) @@ -823,7 +827,7 @@ static void PM_CheckSpecialMovement (void) PM_FlyMove =============== */ -static void PM_FlyMove (qboolean doclip) +static void PM_FlyMove (void) { float speed, drop, friction, control, newspeed; float currentspeed, addspeed, accelspeed; @@ -832,8 +836,6 @@ static void PM_FlyMove (qboolean doclip) float fmove, smove; vec3_t wishdir; float wishspeed; - vec3_t end; - trace_t trace; pm->viewheight = 22; @@ -887,7 +889,7 @@ static void PM_FlyMove (qboolean doclip) currentspeed = DotProduct(pml.velocity, wishdir); addspeed = wishspeed - currentspeed; if (addspeed <= 0) { - if (!pmp->flyfix) { + if (!pmp->flyhack) { return; // original buggy behaviour } } else { @@ -899,6 +901,7 @@ static void PM_FlyMove (qboolean doclip) pml.velocity[i] += accelspeed*wishdir[i]; } +#if 0 if (doclip) { for (i=0 ; i<3 ; i++) end[i] = pml.origin[i] + pml.frametime * pml.velocity[i]; @@ -906,7 +909,9 @@ static void PM_FlyMove (qboolean doclip) trace = pm->trace (pml.origin, pm->mins, pm->maxs, end); VectorCopy (trace.endpos, pml.origin); - } else { + } else +#endif + { // move VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin); } @@ -1190,7 +1195,7 @@ void Pmove( pmove_t *pmove, pmoveParams_t *params ) pm->numtouch = 0; VectorClear (pm->viewangles); pm->viewheight = 0; - pm->groundentity = 0; + pm->groundentity = NULL; pm->watertype = 0; pm->waterlevel = 0; @@ -1208,8 +1213,8 @@ void Pmove( pmove_t *pmove, pmoveParams_t *params ) if (pm->s.pm_type == PM_SPECTATOR) { - pml.frametime = pmp->speedMultiplier * pm->cmd.msec * 0.001f; - PM_FlyMove (qfalse); + pml.frametime = pmp->speedmult * pm->cmd.msec * 0.001f; + PM_FlyMove (); PM_SnapPosition (); return; } @@ -1299,3 +1304,25 @@ void Pmove( pmove_t *pmove, pmoveParams_t *params ) PM_SnapPosition (); } +void PmoveInit( pmoveParams_t *pmp ) { + // set up default pmove parameters + memset( pmp, 0, sizeof( *pmp ) ); + + pmp->speedmult = 1; + pmp->watermult = 0.5f; + pmp->maxspeed = 300; + pmp->friction = 6; + pmp->waterfriction = 1; + pmp->flyfriction = 9; +} + +void PmoveEnableQW( pmoveParams_t *pmp ) { + pmp->qwmode = qtrue; + pmp->watermult = 0.7f; + pmp->maxspeed = 320; + //pmp->upspeed = ( sv_qwmod->integer > 1 ) ? 310 : 350; + pmp->friction = 4; + pmp->waterfriction = 4; + pmp->airaccelerate = qtrue; +} + diff --git a/source/pmove.h b/source/pmove.h index c47b1c8..725ec82 100644 --- a/source/pmove.h +++ b/source/pmove.h @@ -29,22 +29,20 @@ Common between server and client so prediction matches */ typedef struct { + qboolean qwmode; qboolean airaccelerate; - qboolean strafeHack; - qboolean flyfix; - int qwmod; - float speedMultiplier; -// float upspeed; + qboolean strafehack; + qboolean flyhack; + qboolean waterhack; + float speedmult; + float watermult; float maxspeed; float friction; float waterfriction; float flyfriction; -#ifdef PMOVE_HACK - vec3_t origin; - vec3_t velocity; - qboolean highprec; -#endif } pmoveParams_t; void Pmove( pmove_t *pmove, pmoveParams_t *params ); +void PmoveInit( pmoveParams_t *pmp ); +void PmoveEnableQW( pmoveParams_t *pmp ); diff --git a/source/prompt.c b/source/prompt.c index 49f5e0a..df4148a 100644 --- a/source/prompt.c +++ b/source/prompt.c @@ -160,6 +160,7 @@ void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) { genctx_t ctx; char *matches[MAX_MATCHES], *sortedMatches[MAX_MATCHES]; int numCommands = 0, numCvars = 0, numAliases = 0; + extern size_t cmd_string_tail; text = inputLine->text; size = inputLine->maxChars + 1; @@ -180,13 +181,13 @@ void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) { argc = Cmd_Argc(); + // determine argument number to be completed currentArg = Cmd_FindArgForOffset( pos ); - len = strlen( text ); - if( len > 0 && text[ len - 1 ] == ' ' ) { - if( currentArg == argc - 1 ) { - currentArg++; - } + if( currentArg == argc - 1 && cmd_string_tail ) { + // start completing new argument if command line has trailing whitespace + currentArg++; } + argnum = 0; s = Cmd_Argv( 0 ); for( i = 0; i < currentArg; i++ ) { @@ -236,6 +237,13 @@ void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) { text += pos; size -= pos; + // append whitespace since Cmd_TokenizeString eats it + if( currentArg == argc && cmd_string_tail ) { + *text++ = ' '; + pos++; + size--; + } + if( ctx.count == 1 ) { // we have finished completion! s = Cmd_RawArgsFrom( currentArg + 1 ); diff --git a/source/protocol.h b/source/protocol.h index 68fba83..5a19065 100644 --- a/source/protocol.h +++ b/source/protocol.h @@ -38,7 +38,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PROTOCOL_VERSION_Q2PRO_UCMD 1012 // r179 #define PROTOCOL_VERSION_Q2PRO_CLIENTNUM_FIX 1013 // r226 #define PROTOCOL_VERSION_Q2PRO_LONG_SOLID 1014 // r243 -#define PROTOCOL_VERSION_Q2PRO_CURRENT 1014 // r243 +#define PROTOCOL_VERSION_Q2PRO_WATERJUMP_HACK 1015 // r335 +#define PROTOCOL_VERSION_Q2PRO_CURRENT 1015 // r335 #define PROTOCOL_VERSION_MVD_MINIMUM 2009 // r168 #define PROTOCOL_VERSION_MVD_CURRENT 2010 // r177 diff --git a/source/sv_ents.c b/source/sv_ents.c index 3e66233..1f1622a 100644 --- a/source/sv_ents.c +++ b/source/sv_ents.c @@ -41,46 +41,46 @@ static void SV_EmitPacketEntities( client_t *client, int clientEntityNum, msgEsFlags_t baseflags ) { - entity_state_t *oldent, *newent; + entity_state_t *oldent, *newent; const entity_state_t *base; - unsigned oldindex, newindex; - int oldnum, newnum; - unsigned from_num_entities; - msgEsFlags_t flags; + unsigned oldindex, newindex; + int oldnum, newnum; + unsigned from_num_entities; + msgEsFlags_t flags; unsigned i; - if( !from ) - from_num_entities = 0; - else - from_num_entities = from->numEntities; - - newindex = 0; - oldindex = 0; - oldent = newent = NULL; - while( newindex < to->numEntities || oldindex < from_num_entities ) { - if( newindex >= to->numEntities ) { - newnum = 9999; - } else { + if( !from ) + from_num_entities = 0; + else + from_num_entities = from->numEntities; + + newindex = 0; + oldindex = 0; + oldent = newent = NULL; + while( newindex < to->numEntities || oldindex < from_num_entities ) { + if( newindex >= to->numEntities ) { + newnum = 9999; + } else { i = ( to->firstEntity + newindex ) % svs.numEntityStates; - newent = &svs.entityStates[i]; - newnum = newent->number; - } + newent = &svs.entityStates[i]; + newnum = newent->number; + } - if( oldindex >= from_num_entities ) { - oldnum = 9999; - } else { + if( oldindex >= from_num_entities ) { + oldnum = 9999; + } else { i = ( from->firstEntity + oldindex ) % svs.numEntityStates; - oldent = &svs.entityStates[i]; - oldnum = oldent->number; - } - - if( newnum == oldnum ) { - // delta update from old position - // because the force parm is false, this will not result - // in any bytes being emited if the entity has not changed at all - // note that players are always 'newentities', this updates their + oldent = &svs.entityStates[i]; + oldnum = oldent->number; + } + + if( newnum == oldnum ) { + // delta update from old position + // because the force parm is false, this will not result + // in any bytes being emited if the entity has not changed at all + // note that players are always 'newentities', this updates their // oldorigin always and prevents warping - flags = baseflags; + flags = baseflags; if( client->protocol < PROTOCOL_VERSION_Q2PRO ) { // don't waste bandwidth for Q2PRO clients if( newent->number <= client->maxclients ) { @@ -89,44 +89,44 @@ static void SV_EmitPacketEntities( client_t *client, } if( newent->number == clientEntityNum ) { flags |= MSG_ES_FIRSTPERSON; - VectorCopy( oldent->origin, newent->origin ); - VectorCopy( oldent->angles, newent->angles ); + VectorCopy( oldent->origin, newent->origin ); + VectorCopy( oldent->angles, newent->angles ); + } + MSG_WriteDeltaEntity( oldent, newent, flags ); + oldindex++; + newindex++; + continue; + } + + if( newnum < oldnum ) { + // this is a new entity, send it from the baseline + flags = baseflags|MSG_ES_FORCE|MSG_ES_NEWENTITY; + base = client->baselines[newnum >> SV_BASELINES_SHIFT]; + if( base ) { + base += ( newnum & SV_BASELINES_MASK ); + } else { + base = &nullEntityState; } - MSG_WriteDeltaEntity( oldent, newent, flags ); - oldindex++; - newindex++; - continue; - } - - if( newnum < oldnum ) { - // this is a new entity, send it from the baseline - flags = baseflags|MSG_ES_FORCE|MSG_ES_NEWENTITY; - base = client->baselines[newnum >> SV_BASELINES_SHIFT]; - if( base ) { - base += ( newnum & SV_BASELINES_MASK ); - } else { - base = &nullEntityState; - } if( newent->number == clientEntityNum ) { flags |= MSG_ES_FIRSTPERSON; - VectorCopy( base->origin, newent->origin ); - VectorCopy( base->angles, newent->angles ); - VectorCopy( base->old_origin, newent->old_origin ); + VectorCopy( base->origin, newent->origin ); + VectorCopy( base->angles, newent->angles ); + VectorCopy( base->old_origin, newent->old_origin ); } - MSG_WriteDeltaEntity( base, newent, flags ); - newindex++; - continue; - } - - if( newnum > oldnum ) { - // the old entity isn't present in the new message - MSG_WriteDeltaEntity( oldent, NULL, MSG_ES_FORCE ); - oldindex++; - continue; - } - } - - MSG_WriteShort( 0 ); // end of packetentities + MSG_WriteDeltaEntity( base, newent, flags ); + newindex++; + continue; + } + + if( newnum > oldnum ) { + // the old entity isn't present in the new message + MSG_WriteDeltaEntity( oldent, NULL, MSG_ES_FORCE ); + oldindex++; + continue; + } + } + + MSG_WriteShort( 0 ); // end of packetentities } /* @@ -135,55 +135,55 @@ SV_WriteFrameToClient_Default ================== */ void SV_WriteFrameToClient_Default( client_t *client ) { - client_frame_t *frame, *oldframe; - player_state_t *oldstate; - int lastframe; + client_frame_t *frame, *oldframe; + player_state_t *oldstate; + int lastframe; - // this is the frame we are creating - frame = &client->frames[sv.framenum & UPDATE_MASK]; + // this is the frame we are creating + frame = &client->frames[sv.framenum & UPDATE_MASK]; - if( client->lastframe <= 0 ) { - // client is asking for a retransmit - oldframe = NULL; + if( client->lastframe <= 0 ) { + // client is asking for a retransmit + oldframe = NULL; oldstate = NULL; - lastframe = -1; - } else if( sv.framenum - client->lastframe > UPDATE_BACKUP - 1 ) { - // client hasn't gotten a good message through in a long time - Com_DPrintf( "%s: delta request from out-of-date packet.\n", client->name ); - oldframe = NULL; + lastframe = -1; + } else if( sv.framenum - client->lastframe > UPDATE_BACKUP - 1 ) { + // client hasn't gotten a good message through in a long time + Com_DPrintf( "%s: delta request from out-of-date packet.\n", client->name ); + oldframe = NULL; oldstate = NULL; - lastframe = -1; - } else { - // we have a valid message to delta from - oldframe = &client->frames[client->lastframe & UPDATE_MASK]; - oldstate = &oldframe->ps; - lastframe = client->lastframe; - if( svs.nextEntityStates - oldframe->firstEntity > svs.numEntityStates ) { - Com_DPrintf( "%s: delta request from out-of-date entities.\n", client->name ); - oldframe = NULL; + lastframe = -1; + } else { + // we have a valid message to delta from + oldframe = &client->frames[client->lastframe & UPDATE_MASK]; + oldstate = &oldframe->ps; + lastframe = client->lastframe; + if( svs.nextEntityStates - oldframe->firstEntity > svs.numEntityStates ) { + Com_DPrintf( "%s: delta request from out-of-date entities.\n", client->name ); + oldframe = NULL; oldstate = NULL; - lastframe = -1; - } - } - - MSG_WriteByte( svc_frame ); - MSG_WriteLong( sv.framenum ); - MSG_WriteLong( lastframe ); // what we are delta'ing from - MSG_WriteByte( client->surpressCount ); // rate dropped packets - client->surpressCount = 0; + lastframe = -1; + } + } + + MSG_WriteByte( svc_frame ); + MSG_WriteLong( sv.framenum ); + MSG_WriteLong( lastframe ); // what we are delta'ing from + MSG_WriteByte( client->surpressCount ); // rate dropped packets + client->surpressCount = 0; client->frameflags = 0; - // send over the areabits - MSG_WriteByte( frame->areabytes ); - MSG_WriteData( frame->areabits, frame->areabytes ); - - // delta encode the playerstate - MSG_WriteByte( svc_playerinfo ); - MSG_WriteDeltaPlayerstate_Default( oldstate, &frame->ps ); - - // delta encode the entities - MSG_WriteByte( svc_packetentities ); - SV_EmitPacketEntities( client, oldframe, frame, 0, 0 ); + // send over the areabits + MSG_WriteByte( frame->areabytes ); + MSG_WriteData( frame->areabits, frame->areabytes ); + + // delta encode the playerstate + MSG_WriteByte( svc_playerinfo ); + MSG_WriteDeltaPlayerstate_Default( oldstate, &frame->ps ); + + // delta encode the entities + MSG_WriteByte( svc_packetentities ); + SV_EmitPacketEntities( client, oldframe, frame, 0, 0 ); } /* @@ -192,93 +192,93 @@ SV_WriteFrameToClient_Enhanced ================== */ void SV_WriteFrameToClient_Enhanced( client_t *client ) { - client_frame_t *frame, *oldframe; - player_state_t *oldstate; - uint32_t extraflags; - int delta, surpressed; - byte *b1, *b2; - msgPsFlags_t psFlags; - int clientEntityNum; - int baseflags; - - // this is the frame we are creating - frame = &client->frames[sv.framenum & UPDATE_MASK]; - - if( client->lastframe <= 0 ) { - // client is asking for a retransmit - oldframe = NULL; + client_frame_t *frame, *oldframe; + player_state_t *oldstate; + uint32_t extraflags; + int delta, surpressed; + byte *b1, *b2; + msgPsFlags_t psFlags; + int clientEntityNum; + int baseflags; + + // this is the frame we are creating + frame = &client->frames[sv.framenum & UPDATE_MASK]; + + if( client->lastframe <= 0 ) { + // client is asking for a retransmit + oldframe = NULL; oldstate = NULL; - delta = 31; - } else if( sv.framenum - client->lastframe > UPDATE_BACKUP - 1 ) { - // client hasn't gotten a good message through in a long time - Com_DPrintf( "%s: delta request from out-of-date packet.\n", client->name ); - oldframe = NULL; + delta = 31; + } else if( sv.framenum - client->lastframe > UPDATE_BACKUP - 1 ) { + // client hasn't gotten a good message through in a long time + Com_DPrintf( "%s: delta request from out-of-date packet.\n", client->name ); + oldframe = NULL; oldstate = NULL; - delta = 31; - } else { - // we have a valid message to delta from - oldframe = &client->frames[client->lastframe & UPDATE_MASK]; - oldstate = &oldframe->ps; - delta = sv.framenum - client->lastframe; - if( svs.nextEntityStates - oldframe->firstEntity > svs.numEntityStates ) { - Com_DPrintf( "%s: delta request from out-of-date entities.\n", client->name ); - oldframe = NULL; + delta = 31; + } else { + // we have a valid message to delta from + oldframe = &client->frames[client->lastframe & UPDATE_MASK]; + oldstate = &oldframe->ps; + delta = sv.framenum - client->lastframe; + if( svs.nextEntityStates - oldframe->firstEntity > svs.numEntityStates ) { + Com_DPrintf( "%s: delta request from out-of-date entities.\n", client->name ); + oldframe = NULL; oldstate = NULL; - delta = 31; - } - } - - // first byte to be patched - b1 = SZ_GetSpace( &msg_write, 1 ); - - MSG_WriteLong( ( sv.framenum & FRAMENUM_MASK ) | ( delta << FRAMENUM_BITS ) ); - - // second byte to be patched - b2 = SZ_GetSpace( &msg_write, 1 ); - - // send over the areabits - MSG_WriteByte( frame->areabytes ); - MSG_WriteData( frame->areabits, frame->areabytes ); - - // ignore some parts of playerstate if not recording demo - psFlags = 0; - if( !client->settings[CLS_RECORDING] ) { - if( client->settings[CLS_NOGUN] ) { - psFlags |= MSG_PS_IGNORE_GUNFRAMES; - if( client->settings[CLS_NOGUN] != 2 ) { - psFlags |= MSG_PS_IGNORE_GUNINDEX; - } - } - if( client->settings[CLS_NOBLEND] ) { - psFlags |= MSG_PS_IGNORE_BLEND; - } - if( frame->ps.pmove.pm_type < PM_DEAD ) { - if( !( frame->ps.pmove.pm_flags & PMF_NO_PREDICTION ) ) { - psFlags |= MSG_PS_IGNORE_VIEWANGLES; - } - } else { - // lying dead on a rotating platform? - psFlags |= MSG_PS_IGNORE_DELTAANGLES; - } - } - - clientEntityNum = 0; - if( client->protocol == PROTOCOL_VERSION_Q2PRO ) { + delta = 31; + } + } + + // first byte to be patched + b1 = SZ_GetSpace( &msg_write, 1 ); + + MSG_WriteLong( ( sv.framenum & FRAMENUM_MASK ) | ( delta << FRAMENUM_BITS ) ); + + // second byte to be patched + b2 = SZ_GetSpace( &msg_write, 1 ); + + // send over the areabits + MSG_WriteByte( frame->areabytes ); + MSG_WriteData( frame->areabits, frame->areabytes ); + + // ignore some parts of playerstate if not recording demo + psFlags = 0; + if( !client->settings[CLS_RECORDING] ) { + if( client->settings[CLS_NOGUN] ) { + psFlags |= MSG_PS_IGNORE_GUNFRAMES; + if( client->settings[CLS_NOGUN] != 2 ) { + psFlags |= MSG_PS_IGNORE_GUNINDEX; + } + } + if( client->settings[CLS_NOBLEND] ) { + psFlags |= MSG_PS_IGNORE_BLEND; + } + if( frame->ps.pmove.pm_type < PM_DEAD ) { + if( !( frame->ps.pmove.pm_flags & PMF_NO_PREDICTION ) ) { + psFlags |= MSG_PS_IGNORE_VIEWANGLES; + } + } else { + // lying dead on a rotating platform? + psFlags |= MSG_PS_IGNORE_DELTAANGLES; + } + } + + clientEntityNum = 0; + if( client->protocol == PROTOCOL_VERSION_Q2PRO ) { if( frame->ps.pmove.pm_type < PM_DEAD ) { clientEntityNum = frame->clientNum + 1; } - if( client->settings[CLS_NOPREDICT] ) { - psFlags |= MSG_PS_IGNORE_PREDICTION; - } + if( client->settings[CLS_NOPREDICT] ) { + psFlags |= MSG_PS_IGNORE_PREDICTION; + } surpressed = client->frameflags; - } else { + } else { surpressed = client->surpressCount; } - // delta encode the playerstate - extraflags = MSG_WriteDeltaPlayerstate_Enhanced( oldstate, &frame->ps, psFlags ); + // delta encode the playerstate + extraflags = MSG_WriteDeltaPlayerstate_Enhanced( oldstate, &frame->ps, psFlags ); - if( client->protocol == PROTOCOL_VERSION_Q2PRO ) { + if( client->protocol == PROTOCOL_VERSION_Q2PRO ) { // delta encode the clientNum if( client->version < PROTOCOL_VERSION_Q2PRO_CLIENTNUM_FIX ) { if( !oldframe || frame->clientNum != oldframe->clientNum ) { @@ -294,14 +294,14 @@ void SV_WriteFrameToClient_Enhanced( client_t *client ) { } } - // save 3 high bits of extraflags - *b1 = svc_frame | ( ( ( extraflags & 0x70 ) << 1 ) ); + // save 3 high bits of extraflags + *b1 = svc_frame | ( ( ( extraflags & 0x70 ) << 1 ) ); - // save 4 low bits of extraflags - *b2 = ( surpressed & SURPRESSCOUNT_MASK ) | + // save 4 low bits of extraflags + *b2 = ( surpressed & SURPRESSCOUNT_MASK ) | ( ( extraflags & 0x0F ) << SURPRESSCOUNT_BITS ); - client->surpressCount = 0; + client->surpressCount = 0; client->frameflags = 0; baseflags = 0; @@ -309,7 +309,7 @@ void SV_WriteFrameToClient_Enhanced( client_t *client ) { baseflags |= MSG_ES_LONGSOLID; } - // delta encode the entities + // delta encode the entities SV_EmitPacketEntities( client, oldframe, frame, clientEntityNum, baseflags ); } @@ -326,7 +326,7 @@ qboolean SV_EdictPV( cm_t *cm, edict_t *ent, byte *mask ) { mnode_t *node; int i, l; - if( ent->num_clusters == -1 ) { + if( ent->num_clusters == -1 ) { // too many leafs for individual check, go by headnode node = CM_NodeNum( cm, ent->headnode ); return CM_HeadnodeVisible( node, mask ); @@ -339,7 +339,7 @@ qboolean SV_EdictPV( cm_t *cm, edict_t *ent, byte *mask ) { return qtrue; } } - return qfalse; // not visible + return qfalse; // not visible } /* @@ -351,158 +351,158 @@ copies off the playerstat and areabits. ============= */ void SV_BuildClientFrame( client_t *client ) { - int e; - vec3_t org; - edict_t *ent; - edict_t *clent; - client_frame_t *frame; - entity_state_t *state; + int e; + vec3_t org; + edict_t *ent; + edict_t *clent; + client_frame_t *frame; + entity_state_t *state; player_state_t *ps; - int l; - int clientarea, clientcluster; - mleaf_t *leaf; - byte clientphs[MAX_MAP_VIS]; - byte clientpvs[MAX_MAP_VIS]; - extern cvar_t *sv_novis; - - clent = client->edict; - if( !clent->client ) - return; // not in game yet - - // this is the frame we are creating - frame = &client->frames[sv.framenum & UPDATE_MASK]; - client->frame_latency[sv.framenum & LATENCY_MASK] = -1; + int l; + int clientarea, clientcluster; + mleaf_t *leaf; + byte clientphs[MAX_MAP_VIS]; + byte clientpvs[MAX_MAP_VIS]; + + clent = client->edict; + if( !clent->client ) + return; // not in game yet + + // this is the frame we are creating + frame = &client->frames[sv.framenum & UPDATE_MASK]; + client->frame_latency[sv.framenum & LATENCY_MASK] = -1; client->frames_sent++; - frame->sentTime = com_eventTime; // save it for ping calc later + frame->sentTime = com_eventTime; // save it for ping calc later - // find the client's PVS + // find the client's PVS ps = &clent->client->ps; - VectorMA( ps->viewoffset, 0.125f, ps->pmove.origin, org ); + VectorMA( ps->viewoffset, 0.125f, ps->pmove.origin, org ); - leaf = CM_PointLeaf( client->cm, org ); - clientarea = CM_LeafArea( leaf ); - clientcluster = CM_LeafCluster( leaf ); + leaf = CM_PointLeaf( client->cm, org ); + clientarea = CM_LeafArea( leaf ); + clientcluster = CM_LeafCluster( leaf ); - // calculate the visible areas - frame->areabytes = CM_WriteAreaBits( client->cm, frame->areabits, clientarea ); + // calculate the visible areas + frame->areabytes = CM_WriteAreaBits( client->cm, frame->areabits, clientarea ); if( !frame->areabytes && client->protocol != PROTOCOL_VERSION_Q2PRO ) { frame->areabits[0] = 255; frame->areabytes = 1; } - // grab the current player_state_t - frame->ps = *ps; + // grab the current player_state_t + frame->ps = *ps; // grab the current clientNum if( g_features->integer & GMF_CLIENTNUM ) { - frame->clientNum = clent->client->clientNum; + frame->clientNum = clent->client->clientNum; } else { - frame->clientNum = client->number; + frame->clientNum = client->number; } - CM_FatPVS( client->cm, clientpvs, org ); - BSP_ClusterVis( client->cm->cache, clientphs, clientcluster, DVIS_PHS ); + CM_FatPVS( client->cm, clientpvs, org ); + BSP_ClusterVis( client->cm->cache, clientphs, clientcluster, DVIS_PHS ); - // build up the list of visible entities - frame->numEntities = 0; - frame->firstEntity = svs.nextEntityStates; + // build up the list of visible entities + frame->numEntities = 0; + frame->firstEntity = svs.nextEntityStates; - for( e = 1; e < client->pool->num_edicts; e++ ) { - ent = EDICT_POOL( client, e ); + for( e = 1; e < client->pool->num_edicts; e++ ) { + ent = EDICT_POOL( client, e ); // ignore entities not in use if( ( g_features->integer & GMF_PROPERINUSE ) && !ent->inuse ) { continue; } - // ignore ents without visible models - if( ent->svflags & SVF_NOCLIENT ) - continue; - - // ignore ents without visible models unless they have an effect - if( !ent->s.modelindex && !ent->s.effects && !ent->s.sound ) { - if( !ent->s.event ) { - continue; - } - if( ent->s.event == EV_FOOTSTEP && client->settings[CLS_NOFOOTSTEPS] ) { - continue; - } - } - - if( ( ent->s.effects & EF_GIB ) && client->settings[CLS_NOGIBS] ) { - continue; - } - - // ignore if not touching a PV leaf - if( ent != clent && !sv_novis->integer ) { - // check area - if( !CM_AreasConnected( client->cm, clientarea, ent->areanum ) ) { - // doors can legally straddle two areas, so - // we may need to check another one - if( !CM_AreasConnected( client->cm, clientarea, ent->areanum2 ) ) { - continue; // blocked by a door + // ignore ents without visible models + if( ent->svflags & SVF_NOCLIENT ) + continue; + + // ignore ents without visible models unless they have an effect + if( !ent->s.modelindex && !ent->s.effects && !ent->s.sound ) { + if( !ent->s.event ) { + continue; + } + if( ent->s.event == EV_FOOTSTEP && client->settings[CLS_NOFOOTSTEPS] ) { + continue; + } + } + + if( ( ent->s.effects & EF_GIB ) && client->settings[CLS_NOGIBS] ) { + continue; + } + + // ignore if not touching a PV leaf + if( ent != clent && !sv_novis->integer ) { + // check area + if( !CM_AreasConnected( client->cm, clientarea, ent->areanum ) ) { + // doors can legally straddle two areas, so + // we may need to check another one + if( !CM_AreasConnected( client->cm, clientarea, ent->areanum2 ) ) { + continue; // blocked by a door } - } - - // beams just check one point for PHS - if( ent->s.renderfx & RF_BEAM ) { - l = ent->clusternums[0]; - if( !Q_IsBitSet( clientphs, l ) ) - continue; - } else { + } + + // beams just check one point for PHS + if( ent->s.renderfx & RF_BEAM ) { + l = ent->clusternums[0]; + if( !Q_IsBitSet( clientphs, l ) ) + continue; + } else { if( !SV_EdictPV( client->cm, ent, clientpvs ) ) { continue; } - if( !ent->s.modelindex ) { - // don't send sounds if they will be attenuated away - vec3_t delta; - float len; - - VectorSubtract( org, ent->s.origin, delta ); - len = VectorLength( delta ); - if( len > 400 ) - continue; - } - } - } - - if( ent->s.number != e ) { - Com_DPrintf( "FIXING ENT->S.NUMBER!!!\n" ); - ent->s.number = e; - } - - // add it to the circular client_entities array + if( !ent->s.modelindex ) { + // don't send sounds if they will be attenuated away + vec3_t delta; + float len; + + VectorSubtract( org, ent->s.origin, delta ); + len = VectorLength( delta ); + if( len > 400 ) + continue; + } + } + } + + if( ent->s.number != e ) { + Com_WPrintf( "%s: fixing ent->s.number: %d to %d\n", + __func__, ent->s.number, e ); + ent->s.number = e; + } + + // add it to the circular client_entities array state = &svs.entityStates[svs.nextEntityStates % svs.numEntityStates]; - *state = ent->s; + *state = ent->s; // clear footsteps - if( ent->s.event == EV_FOOTSTEP && client->settings[CLS_NOFOOTSTEPS] ) { - state->event = 0; - } + if( ent->s.event == EV_FOOTSTEP && client->settings[CLS_NOFOOTSTEPS] ) { + state->event = 0; + } // XXX: hide this enitity from renderer - if( ( client->protocol != PROTOCOL_VERSION_Q2PRO || + if( ( client->protocol != PROTOCOL_VERSION_Q2PRO || client->settings[CLS_RECORDING] ) && ( g_features->integer & GMF_CLIENTNUM ) && - e == frame->clientNum + 1 && ent != clent ) - { - state->modelindex = 0; - } - - // don't mark players missiles as solid - if( ent->owner == client->edict ) { - state->solid = 0; + e == frame->clientNum + 1 && ent != clent ) + { + state->modelindex = 0; + } + + // don't mark players missiles as solid + if( ent->owner == client->edict ) { + state->solid = 0; } else if( LONG_SOLID_SUPPORTED( client->protocol, client->version ) ) { state->solid = sv.entities[e].solid32; } svs.nextEntityStates++; - if( ++frame->numEntities == MAX_PACKET_ENTITIES ) { - break; - } - } + if( ++frame->numEntities == MAX_PACKET_ENTITIES ) { + break; + } + } } diff --git a/source/sv_init.c b/source/sv_init.c index e95210c..dbfaccf 100644 --- a/source/sv_init.c +++ b/source/sv_init.c @@ -36,6 +36,19 @@ void SV_ClientReset( client_t *client ) { memset( &client->lastcmd, 0, sizeof( client->lastcmd ) ); } +#if USE_FPS +static void SV_SetFrameTime( void ) { + int i = sv_fps->integer / 10; + + clamp( i, 1, 6 ); + + sv.frametime = 100 / i; + sv.framemult = i; + + Cvar_SetInteger( sv_fps, i * 10, CVAR_SET_DIRECT ); +} +#endif + /* ================ SV_SpawnServer @@ -97,6 +110,9 @@ static void SV_SpawnServer( cm_t *cm, const char *server, const char *spawnpoint // // spawn the rest of the entities on the map // +#if USE_FPS + SV_SetFrameTime(); +#endif // precache and static commands can be issued during // map initialization diff --git a/source/sv_local.h b/source/sv_local.h index 224dc87..f4cfaf9 100644 --- a/source/sv_local.h +++ b/source/sv_local.h @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // server.h -//define PARANOID // speed sapping error checking +//define PARANOID // speed sapping error checking #include "com_local.h" #include "q_list.h" @@ -45,31 +45,31 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //============================================================================= -#define MAX_MASTERS 8 // max recipients for heartbeat packets -#define HEARTBEAT_SECONDS 300 +#define MAX_MASTERS 8 // max recipients for heartbeat packets +#define HEARTBEAT_SECONDS 300 #define SV_Malloc( size ) Z_TagMalloc( size, TAG_SERVER ) #define SV_Mallocz( size ) Z_TagMallocz( size, TAG_SERVER ) -#define SV_CopyString( s ) Z_TagCopyString( s, TAG_SERVER ) +#define SV_CopyString( s ) Z_TagCopyString( s, TAG_SERVER ) -#define SV_BASELINES_SHIFT 6 -#define SV_BASELINES_PER_CHUNK ( 1 << SV_BASELINES_SHIFT ) -#define SV_BASELINES_MASK ( SV_BASELINES_PER_CHUNK - 1 ) -#define SV_BASELINES_CHUNKS ( MAX_EDICTS >> SV_BASELINES_SHIFT ) +#define SV_BASELINES_SHIFT 6 +#define SV_BASELINES_PER_CHUNK ( 1 << SV_BASELINES_SHIFT ) +#define SV_BASELINES_MASK ( SV_BASELINES_PER_CHUNK - 1 ) +#define SV_BASELINES_CHUNKS ( MAX_EDICTS >> SV_BASELINES_SHIFT ) #define SV_InfoSet( var, val ) \ - Cvar_FullSet( var, val, CVAR_SERVERINFO|CVAR_ROM, CVAR_SET_DIRECT ) + Cvar_FullSet( var, val, CVAR_SERVERINFO|CVAR_ROM, CVAR_SET_DIRECT ) // game features this server supports #define SV_FEATURES (GMF_CLIENTNUM|GMF_PROPERINUSE|GMF_MVDSPEC|GMF_WANT_ALL_DISCONNECTS) typedef struct { - unsigned numEntities; - unsigned firstEntity; + unsigned numEntities; + unsigned firstEntity; player_state_t ps; - int areabytes; - byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits - unsigned sentTime; // for ping calculations + int areabytes; + byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits + unsigned sentTime; // for ping calculations int clientNum; } client_frame_t; @@ -77,21 +77,28 @@ typedef struct { int solid32; } server_entity_t; +#define SV_FPS 10 +#define SV_FRAMETIME 100 + typedef struct { - server_state_t state; // precache commands are only valid during load - int spawncount; // random number generated each server spawn + server_state_t state; // precache commands are only valid during load + int spawncount; // random number generated each server spawn - int framenum; - unsigned frametime; + int framenum; +#if 0 + int framemult; // 0 or 1 + unsigned frametime; // 100 or 50 +#endif + unsigned frameresidual; - char name[MAX_QPATH]; // map name, or cinematic name - cm_t cm; + char name[MAX_QPATH]; // map name, or cinematic name + cm_t cm; - char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; + char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; server_entity_t entities[MAX_EDICTS]; - unsigned tracecount; + unsigned tracecount; } server_t; #define EDICT_POOL(c,n) ((edict_t *)((byte *)(c)->pool->edicts + (c)->pool->edict_size*(n))) @@ -99,16 +106,16 @@ typedef struct { #define EDICT_NUM(n) ((edict_t *)((byte *)ge->edicts + ge->edict_size*(n))) #define NUM_FOR_EDICT(e) ( ((byte *)(e)-(byte *)ge->edicts ) / ge->edict_size) -#define MAX_TOTAL_ENT_LEAFS 128 +#define MAX_TOTAL_ENT_LEAFS 128 typedef enum { - cs_free, // can be reused for a new connection - cs_zombie, // client has been disconnected, but don't reuse - // connection for a couple seconds + cs_free, // can be reused for a new connection + cs_zombie, // client has been disconnected, but don't reuse + // connection for a couple seconds cs_assigned, // client_t assigned, but no data received from client yet - cs_connected, // netchan fully established, but not in game yet - cs_primed, // sent serverdata, client is precaching - cs_spawned // client is fully in game + cs_connected, // netchan fully established, but not in game yet + cs_primed, // sent serverdata, client is precaching + cs_spawned // client is fully in game } clstate_t; #if USE_AC_SERVER @@ -127,19 +134,19 @@ typedef enum { #endif // USE_AC_SERVER -#define MSG_POOLSIZE 1024 -#define MSG_TRESHOLD ( 64 - 10 ) // keep pmsg_s 64 bytes aligned +#define MSG_POOLSIZE 1024 +#define MSG_TRESHOLD ( 64 - 10 ) // keep pmsg_s 64 bytes aligned -#define MSG_RELIABLE 1 -#define MSG_CLEAR 2 +#define MSG_RELIABLE 1 +#define MSG_CLEAR 2 #define MAX_SOUND_PACKET 14 typedef struct { - list_t entry; - uint16_t cursize; // zero means sound packet + list_t entry; + uint16_t cursize; // zero means sound packet union { - uint8_t data[MSG_TRESHOLD]; + uint8_t data[MSG_TRESHOLD]; struct { uint8_t flags; uint8_t index; @@ -147,16 +154,16 @@ typedef struct { uint8_t volume; uint8_t attenuation; uint8_t timeofs; - int16_t pos[3]; // saved in case entity is freed + int16_t pos[3]; // saved in case entity is freed }; }; } message_packet_t; -#define LATENCY_COUNTS 16 -#define LATENCY_MASK ( LATENCY_COUNTS - 1 ) +#define LATENCY_COUNTS 16 +#define LATENCY_MASK ( LATENCY_COUNTS - 1 ) -#define RATE_MESSAGES 10 +#define RATE_MESSAGES 10 #define FOR_EACH_CLIENT( client ) \ LIST_FOR_EACH( client_t, client, &svs.udp_client_list, entry ) @@ -172,66 +179,66 @@ typedef enum { typedef struct client_s { list_t entry; - clstate_t state; + clstate_t state; client_flags_t flags; - char userinfo[MAX_INFO_STRING]; // name, etc - char *versionString; + char userinfo[MAX_INFO_STRING]; // name, etc + char *versionString; char reconnect_var[16]; char reconnect_val[16]; - int lastframe; // for delta compression - usercmd_t lastcmd; // for filling in big drops + int lastframe; // for delta compression + usercmd_t lastcmd; // for filling in big drops - int commandMsec; // every seconds this is reset, if user - // commands exhaust it, assume time cheating + int commandMsec; // every seconds this is reset, if user + // commands exhaust it, assume time cheating int numMoves; int fps; - int frame_latency[LATENCY_COUNTS]; - int ping, min_ping, max_ping; + int frame_latency[LATENCY_COUNTS]; + int ping, min_ping, max_ping; int avg_ping_time, avg_ping_count; - size_t message_size[RATE_MESSAGES]; // used to rate drop packets - size_t rate; - int surpressCount; // number of messages rate supressed - unsigned send_time, send_delta; // used to rate drop async packets + size_t message_size[RATE_MESSAGES]; // used to rate drop packets + size_t rate; + int surpressCount; // number of messages rate supressed + unsigned send_time, send_delta; // used to rate drop async packets frameflags_t frameflags; - edict_t *edict; // EDICT_NUM(clientnum+1) - char name[MAX_CLIENT_NAME]; // extracted from userinfo, + edict_t *edict; // EDICT_NUM(clientnum+1) + char name[MAX_CLIENT_NAME]; // extracted from userinfo, // high bits masked - int messagelevel; // for filtering printed messages - int number; // client slot number + int messagelevel; // for filtering printed messages + int number; // client slot number - clientSetting_t settings[CLS_MAX]; + clientSetting_t settings[CLS_MAX]; - client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here + client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here unsigned frames_sent, frames_acked; - byte *download; // file being downloaded - int downloadsize; // total bytes (can't use EOF because of paks) - int downloadcount; // bytes sent + byte *download; // file being downloaded + int downloadsize; // total bytes (can't use EOF because of paks) + int downloadcount; // bytes sent char *downloadname; // name of the file - unsigned lastmessage; // svs.realtime when packet was last received + unsigned lastmessage; // svs.realtime when packet was last received - int challenge; // challenge of this user, randomly generated - int protocol; // major version + int challenge; // challenge of this user, randomly generated + int protocol; // major version int version; // minor version time_t connect_time; // spectator speed, etc - pmoveParams_t pmp; + pmoveParams_t pmp; // packetized messages - list_t msg_free_list; - list_t msg_unreliable_list; - list_t msg_reliable_list; - message_packet_t *msg_pool; + list_t msg_free_list; + list_t msg_unreliable_list; + list_t msg_reliable_list; + message_packet_t *msg_pool; size_t msg_unreliable_bytes; // total size of unreliable datagram size_t msg_dynamic_bytes; // total size of dynamic memory allocated @@ -248,11 +255,11 @@ typedef struct client_s { int maxclients; // netchan type dependent methods - void (*AddMessage)( struct client_s *, byte *, size_t, qboolean ); - void (*WriteFrame)( struct client_s * ); - void (*WriteDatagram)( struct client_s * ); + void (*AddMessage)( struct client_s *, byte *, size_t, qboolean ); + void (*WriteFrame)( struct client_s * ); + void (*WriteDatagram)( struct client_s * ); - netchan_t *netchan; + netchan_t *netchan; int numpackets; // for that nasty packetdup hack #if USE_AC_SERVER @@ -278,23 +285,23 @@ typedef struct client_s { // MAX_CHALLENGES is made large to prevent a denial // of service attack that could cycle all of them // out before legitimate users connected -#define MAX_CHALLENGES 1024 +#define MAX_CHALLENGES 1024 typedef struct { - netadr_t adr; - unsigned challenge; - unsigned time; + netadr_t adr; + unsigned challenge; + unsigned time; } challenge_t; typedef struct { - unsigned limit; - unsigned period; - unsigned time; - unsigned count; + unsigned limit; + unsigned period; + unsigned time; + unsigned count; } ratelimit_t; typedef struct { - list_t entry; + list_t entry; uint32_t addr; uint32_t mask; unsigned hits; @@ -302,9 +309,9 @@ typedef struct { } addrmatch_t; typedef struct { - list_t entry; - int len; - char string[1]; + list_t entry; + int len; + char string[1]; } stuffcmd_t; typedef enum { @@ -317,97 +324,97 @@ typedef enum { } filteraction_t; typedef struct { - list_t entry; - filteraction_t action; - char *comment; - char string[1]; + list_t entry; + filteraction_t action; + char *comment; + char string[1]; } filtercmd_t; typedef struct server_static_s { - qboolean initialized; // sv_init has completed - unsigned realtime; // always increasing, no clamping, etc + qboolean initialized; // sv_init has completed + unsigned realtime; // always increasing, no clamping, etc - client_t *udp_client_pool; // [maxclients] - list_t udp_client_list; // linked list of non-free clients + client_t *udp_client_pool; // [maxclients] + list_t udp_client_list; // linked list of non-free clients - unsigned numEntityStates; // maxclients*UPDATE_BACKUP*MAX_PACKET_ENTITIES - unsigned nextEntityStates; // next entityState to use - entity_state_t *entityStates; // [numEntityStates] + unsigned numEntityStates; // maxclients*UPDATE_BACKUP*MAX_PACKET_ENTITIES + unsigned nextEntityStates; // next entityState to use + entity_state_t *entityStates; // [numEntityStates] #if USE_ZLIB z_stream z; // for compressing messages at once #endif - unsigned last_heartbeat; + unsigned last_heartbeat; - ratelimit_t ratelimit_status; - ratelimit_t ratelimit_badpass; - ratelimit_t ratelimit_badrcon; + ratelimit_t ratelimit_status; + ratelimit_t ratelimit_badpass; + ratelimit_t ratelimit_badrcon; - challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting + challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting } server_static_t; //============================================================================= -extern netadr_t master_adr[MAX_MASTERS]; // address of the master server +extern netadr_t master_adr[MAX_MASTERS]; // address of the master server -extern list_t sv_banlist; -extern list_t sv_blacklist; +extern list_t sv_banlist; +extern list_t sv_blacklist; -extern list_t sv_cmdlist_connect; -extern list_t sv_cmdlist_begin; +extern list_t sv_cmdlist_connect; +extern list_t sv_cmdlist_begin; -extern list_t sv_filterlist; +extern list_t sv_filterlist; -extern server_static_t svs; // persistant server info -extern server_t sv; // local server +extern server_static_t svs; // persistant server info +extern server_t sv; // local server -extern pmoveParams_t sv_pmp; +extern pmoveParams_t sv_pmp; - -extern cvar_t *sv_hostname; -extern cvar_t *sv_maxclients; -extern cvar_t *sv_password; -extern cvar_t *sv_reserved_slots; -extern cvar_t *sv_airaccelerate; // development tool -extern cvar_t *sv_qwmod; // atu QW Physics modificator -extern cvar_t *sv_enforcetime; -extern cvar_t *sv_force_reconnect; -extern cvar_t *sv_iplimit; - -//extern cvar_t *sv_console_auth; +extern cvar_t *sv_hostname; +extern cvar_t *sv_maxclients; +extern cvar_t *sv_password; +extern cvar_t *sv_reserved_slots; +extern cvar_t *sv_airaccelerate; // development tool +extern cvar_t *sv_qwmod; // atu QW Physics modificator +extern cvar_t *sv_enforcetime; +#if USE_FPS +extern cvar_t *sv_fps; +#endif +extern cvar_t *sv_force_reconnect; +extern cvar_t *sv_iplimit; #if USE_CLIENT -extern cvar_t *sv_debug_send; -extern cvar_t *sv_pad_packets; +extern cvar_t *sv_debug_send; +extern cvar_t *sv_pad_packets; #endif -extern cvar_t *sv_lan_force_rate; -extern cvar_t *sv_calcpings_method; -extern cvar_t *sv_changemapcmd; +extern cvar_t *sv_novis; +extern cvar_t *sv_lan_force_rate; +extern cvar_t *sv_calcpings_method; +extern cvar_t *sv_changemapcmd; -extern cvar_t *sv_strafejump_hack; +extern cvar_t *sv_strafejump_hack; #ifndef _WIN32 -extern cvar_t *sv_oldgame_hack; +extern cvar_t *sv_oldgame_hack; #endif #if USE_PACKETDUP -extern cvar_t *sv_packetdup_hack; +extern cvar_t *sv_packetdup_hack; #endif -extern cvar_t *sv_allow_map; +extern cvar_t *sv_allow_map; -extern cvar_t *sv_status_limit; -extern cvar_t *sv_status_show; -extern cvar_t *sv_badauth_time; -extern cvar_t *sv_uptime; +extern cvar_t *sv_status_limit; +extern cvar_t *sv_status_show; +extern cvar_t *sv_badauth_time; +extern cvar_t *sv_uptime; extern cvar_t *g_features; extern cvar_t *sv_timeout; extern cvar_t *sv_zombietime; -extern cvar_t *sv_ghostime; - -extern client_t *sv_client; -extern edict_t *sv_player; +extern cvar_t *sv_ghostime; +extern client_t *sv_client; +extern edict_t *sv_player; //=========================================================== @@ -450,12 +457,12 @@ void SV_ClientReset( client_t *client ); // sv_send.c // typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t; -#define SV_OUTPUTBUF_LENGTH (MAX_PACKETLEN_DEFAULT - 16) +#define SV_OUTPUTBUF_LENGTH (MAX_PACKETLEN_DEFAULT - 16) #define SV_BeginRedirect( target ) \ - Com_BeginRedirect( target, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect ) + Com_BeginRedirect( target, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect ) -extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; +extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; void SV_FlushRedirect( int redirected, char *outputbuf, size_t len ); @@ -470,7 +477,6 @@ void SV_BroadcastCommand( const char *fmt, ... ) q_printf( 1, 2 ); void SV_ClientAddMessage( client_t *client, int flags ); void SV_ShutdownClientSend( client_t *client ); void SV_InitClientSend( client_t *newcl ); -void SV_CalcSendTime( client_t *client, size_t messageSize ); #if USE_MVD_SERVER @@ -492,8 +498,8 @@ void SV_MvdMulticast( int leafnum, multicast_t to ); void SV_MvdConfigstring( int index, const char *string, size_t len ); void SV_MvdBroadcastPrint( int level, const char *string ); void SV_MvdStartSound( int entnum, int channel, int flags, - int soundindex, int volume, - int attenuation, int timeofs ); + int soundindex, int volume, + int attenuation, int timeofs ); #endif // USE_MVD_SERVER #if USE_AC_SERVER @@ -539,7 +545,7 @@ client_t *SV_EnhancedSetPlayer( char *s ); // #define ES_INUSE( s ) \ - ( (s)->modelindex || (s)->effects || (s)->sound || (s)->event ) + ( (s)->modelindex || (s)->effects || (s)->sound || (s)->event ) void SV_BuildProxyClientFrame( client_t *client ); void SV_BuildClientFrame( client_t *client ); @@ -550,7 +556,7 @@ qboolean SV_EdictPV( cm_t *cm, edict_t *ent, byte *mask ); // // sv_game.c // -extern game_export_t *ge; +extern game_export_t *ge; void SV_InitGameProgs( void ); void SV_ShutdownGameProgs (void); @@ -601,7 +607,7 @@ typedef trace_t (*sv_trace_t)( vec3_t, vec3_t, vec3_t, vec3_t, edict_t *, int ); trace_t SV_Trace_Native (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask); trace_t *SV_Trace (trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, - edict_t *passedict, int contentmask); + edict_t *passedict, int contentmask); // mins and maxs are relative // if the entire move stays in a solid volume, trace.allsolid will be set, diff --git a/source/sv_main.c b/source/sv_main.c index affd11c..ce0036e 100644 --- a/source/sv_main.c +++ b/source/sv_main.c @@ -32,6 +32,9 @@ LIST_DECL( sv_filterlist ); client_t *sv_client; // current client cvar_t *sv_enforcetime; +#if USE_FPS +cvar_t *sv_fps; +#endif cvar_t *sv_timeout; // seconds without any message cvar_t *sv_zombietime; // seconds to sink messages after disconnect @@ -65,6 +68,7 @@ cvar_t *sv_calcpings_method; cvar_t *sv_changemapcmd; cvar_t *sv_strafejump_hack; +cvar_t *sv_waterjump_hack; #ifndef _WIN32 cvar_t *sv_oldgame_hack; #endif @@ -803,33 +807,30 @@ static void SVC_DirectConnect( void ) { // copy default pmove parameters newcl->pmp = sv_pmp; newcl->pmp.airaccelerate = sv_airaccelerate->integer ? qtrue : qfalse; -#ifdef PMOVE_HACK - newcl->pmp.highprec = qtrue; -#endif // r1q2 extensions + i = 2; if( protocol == PROTOCOL_VERSION_R1Q2 || protocol == PROTOCOL_VERSION_Q2PRO ) { - newcl->pmp.speedMultiplier = 2; - newcl->pmp.strafeHack = sv_strafejump_hack->integer > 0 ? qtrue : qfalse; - } else { - newcl->pmp.strafeHack = sv_strafejump_hack->integer > 1 ? qtrue : qfalse; + newcl->pmp.speedmult = 2; + i = 1; } + newcl->pmp.strafehack = sv_strafejump_hack->integer >= i ? qtrue : qfalse; // q2pro extensions + i = 2; if( protocol == PROTOCOL_VERSION_Q2PRO ) { if( sv_qwmod->integer ) { - newcl->pmp.qwmod = sv_qwmod->integer; - newcl->pmp.maxspeed = 320; - //newcl->pmp.upspeed = ( sv_qwmod->integer > 1 ) ? 310 : 350; - newcl->pmp.friction = 4; - newcl->pmp.waterfriction = 4; - newcl->pmp.airaccelerate = qtrue; + PmoveEnableQW( &newcl->pmp ); } - newcl->pmp.flyfix = qtrue; + newcl->pmp.flyhack = qtrue; newcl->pmp.flyfriction = 4; + if( version >= PROTOCOL_VERSION_Q2PRO_WATERJUMP_HACK ) { + i = 1; + } } + newcl->pmp.waterhack = sv_waterjump_hack->integer >= i ? qtrue : qfalse; // get the game a chance to reject this connection or modify the userinfo sv_client = newcl; @@ -1072,6 +1073,7 @@ Updates the cl->ping variables static void SV_CalcPings( void ) { client_t *cl; int (*calc)( client_t * ); + int res; switch( sv_calcpings_method->integer ) { case 0: calc = ping_nop; break; @@ -1079,6 +1081,9 @@ static void SV_CalcPings( void ) { default: calc = ping_avg; break; } + // update avg ping every 10 seconds + res = sv.framenum % 100; + FOR_EACH_CLIENT( cl ) { if( cl->state == cs_spawned ) { cl->ping = calc( cl ); @@ -1088,7 +1093,7 @@ static void SV_CalcPings( void ) { } else if( cl->ping > cl->max_ping ) { cl->max_ping = cl->ping; } - if( ( sv.framenum % 100 ) == 0 ) { + if( !res ) { cl->avg_ping_time += cl->ping; cl->avg_ping_count++; } @@ -1118,14 +1123,14 @@ static void SV_GiveMsec( void ) { return; FOR_EACH_CLIENT( cl ) { - cl->commandMsec = 1800; // 1600 + some slop + cl->commandMsec = 18 * SV_FRAMETIME; // 1600 + some slop } if( sv.framenum & 63 ) return; FOR_EACH_CLIENT( cl ) { - cl->fps = ( cl->numMoves * 10 ) >> 6; + cl->fps = ( cl->numMoves * SV_FPS ) >> 6; cl->numMoves = 0; } } @@ -1324,7 +1329,7 @@ static void SV_RunGameFrame( void ) { // compression can get confused when a client // has the "current" frame sv.framenum++; - sv.frametime -= 100; + sv.frameresidual -= SV_FRAMETIME; #if USE_MVD_SERVER // save the entire world state if recording a serverdemo @@ -1478,10 +1483,10 @@ void SV_Frame( unsigned msec ) { SV_SendAsyncPackets(); // move autonomous things around if enough time has passed - sv.frametime += msec; - if( !com_timedemo->integer && sv.frametime < 100 ) { + sv.frameresidual += msec; + if( !com_timedemo->integer && sv.frameresidual < SV_FRAMETIME ) { if( Com_IsDedicated() ) { - NET_Sleep( 100 - sv.frametime ); + NET_Sleep( SV_FRAMETIME - sv.frameresidual ); } return; } @@ -1733,8 +1738,11 @@ void SV_Init( void ) { sv_zombietime = Cvar_Get( "zombietime", "2", 0 ); sv_ghostime = Cvar_Get( "sv_ghostime", "6", 0 ); sv_showclamp = Cvar_Get( "showclamp", "0", 0 ); - sv_enforcetime = Cvar_Get ( "sv_enforcetime", "1", 0 ); - sv_force_reconnect = Cvar_Get ( "sv_force_reconnect", "", CVAR_LATCH ); + sv_enforcetime = Cvar_Get( "sv_enforcetime", "1", 0 ); +#if USE_FPS + sv_fps = Cvar_Get( "sv_fps", "10", CVAR_LATCH ); +#endif + sv_force_reconnect = Cvar_Get( "sv_force_reconnect", "", CVAR_LATCH ); sv_show_name_changes = Cvar_Get( "sv_show_name_changes", "0", 0 ); sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH); @@ -1755,6 +1763,7 @@ void SV_Init( void ) { sv_changemapcmd = Cvar_Get( "sv_changemapcmd", "", 0 ); sv_strafejump_hack = Cvar_Get( "sv_strafejump_hack", "1", CVAR_LATCH ); + sv_waterjump_hack = Cvar_Get( "sv_waterjump_hack", "0", CVAR_LATCH ); #ifndef _WIN32 sv_oldgame_hack = Cvar_Get( "sv_oldgame_hack", "0", CVAR_LATCH ); @@ -1781,12 +1790,7 @@ void SV_Init( void ) { g_features = Cvar_Get( "g_features", "0", CVAR_ROM ); // set up default pmove parameters - sv_pmp.maxspeed = 300; - //sv_pmp.upspeed = 350; - sv_pmp.friction = 6; - sv_pmp.flyfriction = 9; - sv_pmp.waterfriction = 1; - sv_pmp.speedMultiplier = 1; + PmoveInit( &sv_pmp ); #if USE_SYSCON SV_SetConsoleTitle(); diff --git a/source/sv_mvd.c b/source/sv_mvd.c index a5d34d5..2bd373b 100644 --- a/source/sv_mvd.c +++ b/source/sv_mvd.c @@ -747,6 +747,12 @@ static void emit_frame( void ) { continue; } + if( newes->number != i ) { + Com_WPrintf( "%s: fixing ent->s.number: %d to %d\n", + __func__, newes->number, i ); + newes->number = i; + } + // calculate flags flags = 0; if( i <= sv_maxclients->integer ) { @@ -2076,6 +2082,8 @@ static void SV_MvdRecord_f( void ) { case 'z': gzip = qtrue; break; + default: + return; } } diff --git a/source/sv_send.c b/source/sv_send.c index 6c8444d..de45a53 100644 --- a/source/sv_send.c +++ b/source/sv_send.c @@ -79,7 +79,7 @@ static qboolean SV_RateDrop( client_t *client ) { return qfalse; } -void SV_CalcSendTime( client_t *client, size_t size ) { +static void SV_CalcSendTime( client_t *client, size_t size ) { // never drop over the loopback if( !client->rate ) { client->send_time = svs.realtime; diff --git a/source/sv_user.c b/source/sv_user.c index 61ac62c..0145eb1 100644 --- a/source/sv_user.c +++ b/source/sv_user.c @@ -402,13 +402,16 @@ void SV_New_f( void ) { MSG_WriteByte( 0 ); // not enhanced MSG_WriteShort( sv_client->version ); MSG_WriteByte( 0 ); // no advanced deltas - MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); + MSG_WriteByte( sv_client->pmp.strafehack ); break; case PROTOCOL_VERSION_Q2PRO: MSG_WriteShort( sv_client->version ); MSG_WriteByte( 2 ); // used to be GT_DEATHMATCH - MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); - MSG_WriteByte( sv_qwmod->integer ); + MSG_WriteByte( sv_client->pmp.strafehack ); + MSG_WriteByte( sv_client->pmp.qwmode ); + if( sv_client->version >= PROTOCOL_VERSION_Q2PRO_WATERJUMP_HACK ) { + MSG_WriteByte( sv_client->pmp.waterhack ); + } break; default: break; diff --git a/source/sv_world.c b/source/sv_world.c index 432cce4..8a19d52 100644 --- a/source/sv_world.c +++ b/source/sv_world.c @@ -593,7 +593,7 @@ trace_t *SV_Trace( trace_t *trace, } if( ++sv.tracecount > 10000 ) { - Com_EPrintf( "SV_Trace: game DLL caught in infinite loop!\n" ); + Com_EPrintf( "%s: game DLL caught in infinite loop!\n", __func__ ); memset( trace, 0, sizeof( *trace ) ); trace->fraction = 1; trace->ent = ge->edicts; diff --git a/wiki/download.mdwn b/wiki/download.mdwn index 42445bf..a1ea7e2 100644 --- a/wiki/download.mdwn +++ b/wiki/download.mdwn @@ -1,19 +1,34 @@ Debian GNU/Linux ---------------- -Those running stable Debian destribution (currently Etch) on i386 -architecture can conveniently install pre-built Q2PRO packages from -skuller.ath.cx Debian [repository](http://skuller.ath.cx/debian/). -Just add the following line(s) into your `/etc/apt/sources.list` -and run `aptitude update`: +Prebuilt Q2PRO packages are available for the stable Debian distribution +for i386 and amd64 architectures. - deb http://skuller.ath.cx/debian/ etch q2pro - deb-src http://skuller.ath.cx/debian/ etch q2pro +In order to get Q2PRO repository contents automatically managed by APT, +add the following lines into your `/etc/apt/sources.list` file: -Users of Secure APT may need to import the repository signing key first: + deb http://skuller.ath.cx/debian/ lenny q2pro + deb-src http://skuller.ath.cx/debian/ lenny q2pro + +Users of Secure APT also need to import the repository signing key: wget -q -O - http://skuller.ath.cx/debian/archive.key | apt-key add - -Nighly builds +Finally, run the following commands to install or upgrade Q2PRO: + + aptitude update + aptitude install q2pro-client # install the graphical client + aptitude install q2pro-server # install the dedicated server + +It is also possible to download the individual [.deb][debs] packages +and install them manually using `dpkg -i` command. + +Note that Q2PRO packages above are not providing any game media files +for Quake 2 like textures and maps. You need to install them yourself, +otherwise graphical client won't run. + +[debs]: http://skuller.ath.cx/debian/pool/q2pro/ + +Nightly builds ---------------- Generic GNU/Linux and Win32 binary builds from SVN trunk are [available][nightly], along with source snapshots. You might also diff --git a/wiki/local.css b/wiki/local.css index cc5be4a..deae1b3 100644 --- a/wiki/local.css +++ b/wiki/local.css @@ -1,6 +1,6 @@ body { background: #e7e7e7; font-family: sans-serif;} -#content { border: none; /*text-align: justify;*/ max-width: 80ex;} +#content { border: none; /*text-align: justify; max-width: 80ex;*/} /*code { background: ; }*/ |