summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2009-03-24 14:54:32 +0000
committerAndrey Nazarov <skuller@skuller.net>2009-03-24 14:54:32 +0000
commit385ccd0e9a518933019a8c6f1fecad2ae660b766 (patch)
tree6b86f96c16a6d89a5803fce5081af64ac76165ab
parentfd8cba03f93046e892a732da27f221406f726b7c (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-xdebian/rules2
-rw-r--r--source/cl_main.c12
-rw-r--r--source/cl_parse.c61
-rw-r--r--source/cl_pred.c2
-rw-r--r--source/cmd.c5
-rw-r--r--source/gl_surf.c2
-rw-r--r--source/mvd_client.c2
-rw-r--r--source/mvd_game.c24
-rw-r--r--source/mvd_local.h1
-rw-r--r--source/pmove.c51
-rw-r--r--source/pmove.h18
-rw-r--r--source/prompt.c18
-rw-r--r--source/protocol.h3
-rw-r--r--source/sv_ents.c604
-rw-r--r--source/sv_init.c16
-rw-r--r--source/sv_local.h304
-rw-r--r--source/sv_main.c62
-rw-r--r--source/sv_mvd.c8
-rw-r--r--source/sv_send.c2
-rw-r--r--source/sv_user.c9
-rw-r--r--source/sv_world.c2
-rw-r--r--wiki/download.mdwn33
-rw-r--r--wiki/local.css2
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: ; }*/