summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2009-01-10 22:10:03 +0000
committerAndrey Nazarov <skuller@skuller.net>2009-01-10 22:10:03 +0000
commit9b015c1322a3e8be37c476d1be5f4ef68d2b8b9c (patch)
tree9fb9a7dfd9b5154ecf5d871906ec7a548aab077e
parent7ee7c25e791d374ef960bbfc084b23c579f8a2ed (diff)
Made MinGW built OpenFFA game DLL loadable on Win32.
Server now disallows ‘map’ command by default if no latched variables were changed. Added ‘sv_allow_map’ cvar to turn this check off. Implemented ‘kickban’ server command. Made address/mask matching code endianess safe. Made ‘dumpuser’ server command more verbose. Display client FPS value in the output of ‘status’ command. Fixed a crash when MVD channel with an active GTV connection was destroyed. Made it possible to re-enable old Q2 brush tracing bug via ‘map_allsolid_bug’ cvar. Added ‘allow_download_textures’ and ‘allow_download_pics’ cvar for fine tuning download options on client and server sides. Changed ‘allow_download’ default value to 0.
-rw-r--r--source/bsp.c1
-rw-r--r--source/cl_aastat.c8
-rw-r--r--source/cl_console.c2
-rw-r--r--source/cl_main.c47
-rw-r--r--source/cl_scrn.c8
-rw-r--r--source/cmodel.c8
-rw-r--r--source/com_local.h30
-rw-r--r--source/common.c38
-rw-r--r--source/cvar.c17
-rw-r--r--source/files.c6
-rw-r--r--source/mvd_client.c32
-rw-r--r--source/mvd_game.c12
-rw-r--r--source/mvd_local.h1
-rw-r--r--source/net_chan.c13
-rw-r--r--source/net_chan.h4
-rw-r--r--source/net_common.c6
-rw-r--r--source/q_shared.c87
-rw-r--r--source/q_shared.h42
-rw-r--r--source/sv_ccmds.c118
-rw-r--r--source/sv_local.h6
-rw-r--r--source/sv_main.c92
-rw-r--r--source/sv_null.c33
-rw-r--r--source/sv_send.c2
-rw-r--r--source/sv_user.c28
-rw-r--r--source/sw_local.h3
-rw-r--r--wiki/doc.mdwn5
-rw-r--r--wiki/doc/netcode.mdwn12
-rw-r--r--wiki/doc/q2pro.menu2
-rw-r--r--wiki/doc/server.mdwn13
-rw-r--r--wiki/index.mdwn17
30 files changed, 397 insertions, 296 deletions
diff --git a/source/bsp.c b/source/bsp.c
index 22ab57c..6025475 100644
--- a/source/bsp.c
+++ b/source/bsp.c
@@ -943,6 +943,7 @@ bsp_t *BSP_Load( const char *name ) {
BSP_SetError( "no error" );
if( ( bsp = BSP_Find( name ) ) != NULL ) {
+ Com_PageInMemory( bsp->pool.base, bsp->pool.cursize );
bsp->refcount++;
return bsp;
}
diff --git a/source/cl_aastat.c b/source/cl_aastat.c
index ea5ed98..49ae656 100644
--- a/source/cl_aastat.c
+++ b/source/cl_aastat.c
@@ -181,11 +181,11 @@ static void TH_DrawLayoutString( char *dst, const char *s ) {
len = strlen( ci->name );
TH_DrawString( dst, x + 4, y, ci->name, len );
- len = Q_snprintf( buffer, sizeof( buffer ), "Score: %i", score );
+ len = Q_scnprintf( buffer, sizeof( buffer ), "Score: %i", score );
TH_DrawString( dst, x + 4, y + 1, buffer, len );
- len = Q_snprintf( buffer, sizeof( buffer ), "Ping: %i", ping );
+ len = Q_scnprintf( buffer, sizeof( buffer ), "Ping: %i", ping );
TH_DrawString( dst, x + 4, y + 2, buffer, len );
- len = Q_snprintf( buffer, sizeof( buffer ), "Time: %i", time );
+ len = Q_scnprintf( buffer, sizeof( buffer ), "Time: %i", time );
TH_DrawString( dst, x + 4, y + 3, buffer, len );
continue;
}
@@ -214,7 +214,7 @@ static void TH_DrawLayoutString( char *dst, const char *s ) {
if( ping > 999 )
ping = 999;
- len = Q_snprintf( buffer, sizeof( buffer ), "%3d %3d %-12.12s",
+ len = Q_scnprintf( buffer, sizeof( buffer ), "%3d %3d %-12.12s",
score, ping, ci->name );
TH_DrawString( dst, x, y, buffer, len );
continue;
diff --git a/source/cl_console.c b/source/cl_console.c
index 0e5127d..cf77751 100644
--- a/source/cl_console.c
+++ b/source/cl_console.c
@@ -473,7 +473,7 @@ void Con_Print( const char *txt ) {
int color;
static qboolean cr;
char *p;
- int l;
+ int l;
if( !con.initialized )
return;
diff --git a/source/cl_main.c b/source/cl_main.c
index c427fb7..636be69 100644
--- a/source/cl_main.c
+++ b/source/cl_main.c
@@ -32,7 +32,6 @@ cvar_t *adr6;
cvar_t *adr7;
cvar_t *adr8;
-extern cvar_t *rcon_password;
cvar_t *rcon_address;
cvar_t *cl_noskins;
@@ -398,7 +397,7 @@ static void CL_CheckForResend( void ) {
}
Cvar_BitInfo( userinfo, CVAR_USERINFO );
- ret = Netchan_OutOfBandPrint( NS_CLIENT, &cls.serverAddress,
+ ret = Netchan_OutOfBand( NS_CLIENT, &cls.serverAddress,
"connect %i %i %i \"%s\"%s\n", cls.serverProtocol, cls.quakePort,
cls.challenge, userinfo, tail );
if( ret == NET_ERROR ) {
@@ -522,7 +521,7 @@ void CL_SendRcon( const netadr_t *adr, const char *pass, const char *cmd ) {
CL_AddRequest( adr, REQ_RCON );
- ret = Netchan_OutOfBandPrint( NS_CLIENT, adr,
+ ret = Netchan_OutOfBand( NS_CLIENT, adr,
"rcon \"%s\" %s", pass, cmd );
if( ret == NET_ERROR ) {
Com_Printf( "%s to %s\n", NET_ErrorString(),
@@ -1765,13 +1764,15 @@ void CL_RequestNextDownload ( void ) {
precache_check = CS_IMAGES;
}
if ( precache_check >= CS_IMAGES && precache_check < CS_IMAGES + MAX_IMAGES ) {
- if ( precache_check == CS_IMAGES )
- precache_check++; // zero is blank
- while ( precache_check < CS_IMAGES + MAX_IMAGES &&
- cl.configstrings[ precache_check ][ 0 ] ) {
- Q_concat( fn, sizeof( fn ), "pics/", cl.configstrings[ precache_check++ ], ".pcx", NULL );
- if ( !CL_CheckOrDownloadFile( fn ) )
- return; // started a download
+ if ( allow_download_pics->integer ) {
+ if ( precache_check == CS_IMAGES )
+ precache_check++; // zero is blank
+ while ( precache_check < CS_IMAGES + MAX_IMAGES &&
+ cl.configstrings[ precache_check ][ 0 ] ) {
+ Q_concat( fn, sizeof( fn ), "pics/", cl.configstrings[ precache_check++ ], ".pcx", NULL );
+ if ( !CL_CheckOrDownloadFile( fn ) )
+ return; // started a download
+ }
}
precache_check = CS_PLAYERSKINS;
}
@@ -1877,7 +1878,7 @@ void CL_RequestNextDownload ( void ) {
}
if ( precache_check > ENV_CNT && precache_check < TEXTURE_CNT ) {
- if ( allow_download->integer && allow_download_maps->integer ) {
+ if ( allow_download->integer && allow_download_textures->integer ) {
while ( precache_check < TEXTURE_CNT ) {
int n = precache_check++ - ENV_CNT - 1;
@@ -1901,7 +1902,7 @@ void CL_RequestNextDownload ( void ) {
// confirm existance of textures, download any that don't exist
if ( precache_check == TEXTURE_CNT + 1 ) {
- if ( allow_download->integer && allow_download_maps->integer ) {
+ if ( allow_download->integer && allow_download_textures->integer ) {
while ( precache_tex < cl.bsp->numtexinfo ) {
char *texname = cl.bsp->texinfo[ precache_tex++ ].name;
@@ -2187,7 +2188,7 @@ static size_t CL_Ups_m( char *buffer, size_t size ) {
}
ups = VectorLength( vel );
- return Q_snprintf( buffer, size, "%d", ups );
+ return Q_scnprintf( buffer, size, "%d", ups );
}
static size_t CL_Timer_m( char *buffer, size_t size ) {
@@ -2198,25 +2199,25 @@ static size_t CL_Timer_m( char *buffer, size_t size ) {
hour = min / 60; min %= 60;
if( hour ) {
- return Q_snprintf( buffer, size, "%i:%i:%02i", hour, min, sec );
+ return Q_scnprintf( buffer, size, "%i:%i:%02i", hour, min, sec );
}
- return Q_snprintf( buffer, size, "%i:%02i", min, sec );
+ return Q_scnprintf( buffer, size, "%i:%02i", min, sec );
}
static size_t CL_Fps_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%i", cls.fps );
+ return Q_scnprintf( buffer, size, "%i", cls.fps );
}
static size_t CL_Ping_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%i", cls.ping );
+ return Q_scnprintf( buffer, size, "%i", cls.ping );
}
static size_t CL_Health_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%i", cl.frame.ps.stats[STAT_HEALTH] );
+ return Q_scnprintf( buffer, size, "%i", cl.frame.ps.stats[STAT_HEALTH] );
}
static size_t CL_Ammo_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%i", cl.frame.ps.stats[STAT_AMMO] );
+ return Q_scnprintf( buffer, size, "%i", cl.frame.ps.stats[STAT_AMMO] );
}
static size_t CL_Armor_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%i", cl.frame.ps.stats[STAT_ARMOR] );
+ return Q_scnprintf( buffer, size, "%i", cl.frame.ps.stats[STAT_ARMOR] );
}
/*
@@ -2449,7 +2450,6 @@ static void CL_InitLocal ( void ) {
cl_showclamp = Cvar_Get ( "showclamp", "0", 0 );
cl_timeout = Cvar_Get ( "cl_timeout", "120", 0 );
- rcon_password = Cvar_Get ( "rcon_password", "", CVAR_PRIVATE );
rcon_address = Cvar_Get ( "rcon_address", "", CVAR_PRIVATE );
rcon_address->generator = Com_Address_g;
@@ -2832,11 +2832,12 @@ void CL_Frame( unsigned msec ) {
time_after_ref = Sys_Milliseconds();
ref_extra = 0;
- }
-
+ //
// update audio after the 3D view was drawn
S_Update();
+ }
+
// advance local effects for next frame
CL_RunDLights();
CL_RunLightStyles();
diff --git a/source/cl_scrn.c b/source/cl_scrn.c
index 453a954..579829a 100644
--- a/source/cl_scrn.c
+++ b/source/cl_scrn.c
@@ -185,7 +185,7 @@ void SCR_DrawDebugGraph (void)
static void SCR_DrawPercentBar( int percent ) {
char buffer[16];
int x, w;
- int length;
+ size_t len;
scr_hudHeight -= CHAR_HEIGHT;
@@ -194,8 +194,8 @@ static void SCR_DrawPercentBar( int percent ) {
R_DrawFill( 0, scr_hudHeight, w, CHAR_HEIGHT, 4 );
R_DrawFill( w, scr_hudHeight, scr_hudWidth - w, CHAR_HEIGHT, 0 );
- length = Q_snprintf( buffer, sizeof( buffer ), "%d%%", percent );
- x = ( scr_hudWidth - length * CHAR_WIDTH ) / 2;
+ len = Q_scnprintf( buffer, sizeof( buffer ), "%d%%", percent );
+ x = ( scr_hudWidth - len * CHAR_WIDTH ) / 2;
R_DrawString( x, scr_hudHeight, 0, MAX_STRING_CHARS, buffer, scr_font );
}
@@ -651,7 +651,7 @@ void HUD_DrawNumber( int x, int y, int color, int width, int value ) {
color &= 1;
- l = Q_snprintf( num, sizeof( num ), "%i", value );
+ l = Q_scnprintf( num, sizeof( num ), "%i", value );
if( l > width )
l = width;
x += 2 + DIGIT_WIDTH * ( width - l );
diff --git a/source/cmodel.c b/source/cmodel.c
index 4e1fe28..3e50d68 100644
--- a/source/cmodel.c
+++ b/source/cmodel.c
@@ -34,6 +34,7 @@ static int floodvalid;
static int checkcount;
static cvar_t *map_noareas;
+static cvar_t *map_allsolid_bug;
void CM_FloodAreaConnections( cm_t *cm );
@@ -438,8 +439,12 @@ static void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
{ // original point was inside brush
trace->startsolid = qtrue;
if( !getout ) {
- trace->fraction = 0;
trace->allsolid = qtrue;
+ if( !map_allsolid_bug->integer ) {
+ // original Q2 didn't set these
+ trace->fraction = 0;
+ trace->contents = brush->contents;
+ }
}
return;
}
@@ -1126,5 +1131,6 @@ void CM_Init( void ) {
CM_InitBoxHull();
map_noareas = Cvar_Get( "map_noareas", "0", 0 );
+ map_allsolid_bug = Cvar_Get( "map_allsolid_bug", "0", 0 );
}
diff --git a/source/com_local.h b/source/com_local.h
index 2513758..bd40832 100644
--- a/source/com_local.h
+++ b/source/com_local.h
@@ -290,6 +290,7 @@ void Cvar_Default_g( genctx_t *ctx );
// attempts to match a partial variable name for command line completion
// returns NULL if nothing fits
+int Cvar_CountLatchedVars( void );
void Cvar_GetLatchedVars (void);
// any CVAR_LATCHEDED variables that have been set will now take effect
@@ -458,7 +459,9 @@ uint32_t Com_BlockChecksum( void *buffer, size_t len );
extern cvar_t *developer;
extern cvar_t *dedicated;
+#if USE_CLIENT
extern cvar_t *host_speeds;
+#endif
extern cvar_t *com_version;
#if USE_CLIENT
@@ -470,7 +473,16 @@ extern cvar_t *sv_paused;
extern cvar_t *com_timedemo;
extern cvar_t *com_sleep;
-extern FILE *log_stats_file;
+extern cvar_t *allow_download;
+extern cvar_t *allow_download_players;
+extern cvar_t *allow_download_models;
+extern cvar_t *allow_download_sounds;
+extern cvar_t *allow_download_maps;
+extern cvar_t *allow_download_textures;
+extern cvar_t *allow_download_pics;
+extern cvar_t *allow_download_others;
+
+extern cvar_t *rcon_password;
#if USE_CLIENT
// host_speeds times
@@ -496,20 +508,4 @@ void Qcommon_Init( int argc, char **argv );
void Qcommon_Frame( void );
void Qcommon_Shutdown( qboolean fatalError );
-/*
-==============================================================
-
-CLIENT / SERVER SYSTEMS
-
-==============================================================
-*/
-
-extern cvar_t *allow_download;
-extern cvar_t *allow_download_players;
-extern cvar_t *allow_download_models;
-extern cvar_t *allow_download_sounds;
-extern cvar_t *allow_download_maps;
-extern cvar_t *allow_download_demos;
-extern cvar_t *allow_download_other;
-
diff --git a/source/common.c b/source/common.c
index 5bdd7b0..97ec636 100644
--- a/source/common.c
+++ b/source/common.c
@@ -68,6 +68,17 @@ cvar_t *com_time_format;
cvar_t *com_debug_break;
cvar_t *com_fatal_error;
+cvar_t *allow_download;
+cvar_t *allow_download_players;
+cvar_t *allow_download_models;
+cvar_t *allow_download_sounds;
+cvar_t *allow_download_maps;
+cvar_t *allow_download_textures;
+cvar_t *allow_download_pics;
+cvar_t *allow_download_others;
+
+cvar_t *rcon_password;
+
fileHandle_t com_logFile;
qboolean com_logNewline;
unsigned com_framenum;
@@ -280,13 +291,9 @@ void Com_Printf( const char *fmt, ... ) {
recursive++;
va_start( argptr, fmt );
- len = Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
+ len = Q_vscnprintf( msg, sizeof( msg ), fmt, argptr );
va_end( argptr );
- if( len >= sizeof( msg ) ) {
- len = sizeof( msg ) - 1;
- }
-
if( rd_target ) {
Com_Redirect( msg, len );
} else {
@@ -1057,16 +1064,16 @@ size_t Com_Uptime_m( char *buffer, size_t size ) {
day = hour / 24; hour %= 24;
if( day ) {
- return Q_snprintf( buffer, size, "%d+%d:%02d.%02d", day, hour, min, sec );
+ return Q_scnprintf( buffer, size, "%d+%d:%02d.%02d", day, hour, min, sec );
}
if( hour ) {
- return Q_snprintf( buffer, size, "%d:%02d.%02d", hour, min, sec );
+ return Q_scnprintf( buffer, size, "%d:%02d.%02d", hour, min, sec );
}
- return Q_snprintf( buffer, size, "%02d.%02d", min, sec );
+ return Q_scnprintf( buffer, size, "%02d.%02d", min, sec );
}
size_t Com_Random_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%d", ( rand() ^ ( rand() >> 8 ) ) % 10 );
+ return Q_scnprintf( buffer, size, "%d", ( rand() ^ ( rand() >> 8 ) ) % 10 );
}
static size_t Com_MapList_m( char *buffer, size_t size ) {
@@ -1376,6 +1383,17 @@ void Qcommon_Init( int argc, char **argv ) {
com_fatal_error = Cvar_Get( "com_fatal_error", "0", 0 );
com_version = Cvar_Get( "version", version, CVAR_SERVERINFO|CVAR_ROM );
+ allow_download = Cvar_Get( "allow_download", "0", CVAR_ARCHIVE );
+ allow_download_players = Cvar_Get( "allow_download_players", "1", CVAR_ARCHIVE );
+ allow_download_models = Cvar_Get( "allow_download_models", "1", CVAR_ARCHIVE );
+ allow_download_sounds = Cvar_Get( "allow_download_sounds", "1", CVAR_ARCHIVE );
+ allow_download_maps = Cvar_Get( "allow_download_maps", "1", CVAR_ARCHIVE );
+ allow_download_textures = Cvar_Get( "allow_download_textures", "1", CVAR_ARCHIVE );
+ allow_download_pics = Cvar_Get( "allow_download_pics", "1", CVAR_ARCHIVE );
+ allow_download_others = Cvar_Get( "allow_download_others", "0", 0 );
+
+ rcon_password = Cvar_Get( "rcon_password", "", CVAR_PRIVATE );
+
Cmd_AddCommand ("z_stats", Z_Stats_f);
#ifndef __COREDLL__
@@ -1551,7 +1569,7 @@ void Qcommon_Frame( void ) {
#if USE_CLIENT
// spin until msec is non-zero if running a client
- if( !dedicated->integer ) {
+ if( !dedicated->integer && !com_timedemo->integer ) {
while( msec < 1 ) {
Com_ProcessEvents();
com_eventTime = Sys_Milliseconds();
diff --git a/source/cvar.c b/source/cvar.c
index bbf1dda..8914ab8 100644
--- a/source/cvar.c
+++ b/source/cvar.c
@@ -199,6 +199,8 @@ static void Cvar_EngineGet( cvar_t *var, const char *var_value, int flags ) {
{
Cvar_ChangeString( var, var_value, CVAR_SET_DIRECT );
}
+ } else {
+ flags &= ~CVAR_GAME;
}
// some flags are not saved
@@ -620,6 +622,21 @@ void Cvar_GetLatchedVars( void ) {
}
}
+int Cvar_CountLatchedVars( void ) {
+ cvar_t *var;
+ int total = 0;
+
+ for( var = cvar_vars; var; var = var->next ) {
+ if( !(var->flags & CVAR_LATCH) )
+ continue;
+ if( !var->latched_string )
+ continue;
+ total++;
+ }
+
+ return total;
+}
+
/*
============
Cvar_Command
diff --git a/source/files.c b/source/files.c
index 9816f79..8ea2c4b 100644
--- a/source/files.c
+++ b/source/files.c
@@ -1236,13 +1236,9 @@ void FS_FPrintf( fileHandle_t f, const char *format, ... ) {
size_t len;
va_start( argptr, format );
- len = Q_vsnprintf( string, sizeof( string ), format, argptr );
+ len = Q_vscnprintf( string, sizeof( string ), format, argptr );
va_end( argptr );
- if( len >= sizeof( string ) ) {
- len = sizeof( string ) - 1;
- }
-
FS_Write( string, len, f );
}
diff --git a/source/mvd_client.c b/source/mvd_client.c
index 7244a60..3219ddb 100644
--- a/source/mvd_client.c
+++ b/source/mvd_client.c
@@ -121,14 +121,9 @@ static cvar_t *mvd_password;
// ====================================================================
-void MVD_Free( mvd_t *mvd ) {
+static void MVD_Free( mvd_t *mvd ) {
int i;
- // destroy any existing connection
- if( mvd->gtv ) {
- mvd->gtv->destroy( mvd->gtv );
- }
-
// stop demo recording
if( mvd->demorecording ) {
uint16_t msglen = 0;
@@ -150,7 +145,7 @@ void MVD_Free( mvd_t *mvd ) {
Z_Free( mvd );
}
-void MVD_Destroy( mvd_t *mvd ) {
+static void MVD_Destroy( mvd_t *mvd ) {
mvd_client_t *client, *next;
// update channel menus
@@ -163,6 +158,12 @@ void MVD_Destroy( mvd_t *mvd ) {
MVD_SwitchChannel( client, &mvd_waitingRoom );
}
+ // destroy any existing GTV connection
+ if( mvd->gtv ) {
+ mvd->gtv->mvd = NULL; // don't double destroy
+ mvd->gtv->destroy( mvd->gtv );
+ }
+
// free all channel data
MVD_Free( mvd );
}
@@ -607,11 +608,10 @@ static void demo_free_playlist( gtv_t *gtv ) {
static void demo_destroy( gtv_t *gtv ) {
mvd_t *mvd = gtv->mvd;
+ // destroy any associated MVD channel
if( mvd ) {
mvd->gtv = NULL;
- if( !mvd->state ) {
- MVD_Free( mvd );
- }
+ MVD_Destroy( mvd );
}
if( gtv->demoplayback ) {
@@ -1325,9 +1325,9 @@ static void gtv_run( gtv_t *gtv ) {
static void gtv_destroy( gtv_t *gtv ) {
mvd_t *mvd = gtv->mvd;
- // any associated MVD channel is orphaned
+ // drop any associated MVD channel
if( mvd ) {
- mvd->gtv = NULL;
+ mvd->gtv = NULL; // don't double destroy
if( !mvd->state ) {
// free it here, since it is not yet
// added to global channel list
@@ -2010,13 +2010,17 @@ void MVD_Shutdown( void ) {
gtv_t *gtv, *gtv_next;
mvd_t *mvd, *mvd_next;
- // kill all connections
+ // kill all GTV connections
LIST_FOR_EACH_SAFE( gtv_t, gtv, gtv_next, &mvd_gtv_list, entry ) {
gtv->destroy( gtv );
}
- // kill all channels
+ // kill all MVD channels (including demo GTVs)
LIST_FOR_EACH_SAFE( mvd_t, mvd, mvd_next, &mvd_channel_list, entry ) {
+ if( mvd->gtv ) {
+ mvd->gtv->mvd = NULL; // don't double destroy
+ mvd->gtv->destroy( mvd->gtv );
+ }
MVD_Free( mvd );
}
diff --git a/source/mvd_game.c b/source/mvd_game.c
index 0b89efc..dfcfabb 100644
--- a/source/mvd_game.c
+++ b/source/mvd_game.c
@@ -227,7 +227,7 @@ static void MVD_LayoutMenu( mvd_client_t *client ) {
memset( cur, 0x20, sizeof( cur ) );
cur[client->layout_cursor] = 0x8d;
- total = Q_snprintf( layout, sizeof( layout ), format,
+ total = Q_scnprintf( layout, sizeof( layout ), format,
cur[0], client->target ? "Leave" : "Enter", cur[1],
cur[2], List_Count( &client->mvd->clients ),
cur[3], List_Count( &mvd_channel_list ), cur[4],
@@ -274,12 +274,9 @@ static void MVD_LayoutFollow( mvd_client_t *client ) {
char layout[MAX_STRING_CHARS];
size_t total;
- total = Q_snprintf( layout, sizeof( layout ),
+ total = Q_scnprintf( layout, sizeof( layout ),
"%s string \"[%s] Chasing %s\"",
mvd_chase_prefix->string, mvd->name, name );
- if( total >= sizeof( layout ) ) {
- return;
- }
// send the layout
MSG_WriteByte( svc_layout );
@@ -608,8 +605,9 @@ void MVD_BroadcastPrintf( mvd_t *mvd, int level, int mask, const char *fmt, ...
}
if( level == PRINT_CHAT && mvd_filter_version->integer ) {
- char *s = strstr( text, "!version" );
- if( s ) {
+ char *s;
+
+ while( ( s = strstr( text, "!version" ) ) != NULL ) {
s[6] = '0';
}
}
diff --git a/source/mvd_local.h b/source/mvd_local.h
index 3e30844..da578f3 100644
--- a/source/mvd_local.h
+++ b/source/mvd_local.h
@@ -165,7 +165,6 @@ extern cvar_t *mvd_shownet;
void MVD_Destroyf( mvd_t *mvd, const char *fmt, ... )
q_noreturn q_printf( 2, 3 );
-void MVD_Free( mvd_t *mvd );
void MVD_Shutdown( void );
mvd_t *MVD_SetChannel( int arg );
diff --git a/source/net_chan.c b/source/net_chan.c
index cbca6c9..e1be8cd 100644
--- a/source/net_chan.c
+++ b/source/net_chan.c
@@ -110,13 +110,13 @@ void Netchan_Init( void ) {
/*
===============
-Netchan_OutOfBandPrint
+Netchan_OutOfBand
Sends a text message in an out-of-band datagram
================
*/
-neterr_t Netchan_OutOfBandPrint( netsrc_t sock, const netadr_t *address,
- const char *format, ... )
+neterr_t Netchan_OutOfBand( netsrc_t sock, const netadr_t *address,
+ const char *format, ... )
{
va_list argptr;
char buffer[MAX_PACKETLEN_DEFAULT];
@@ -124,18 +124,19 @@ neterr_t Netchan_OutOfBandPrint( netsrc_t sock, const netadr_t *address,
// write the packet header
*( uint32_t * )buffer = 0xffffffff;
+ len = 4;
va_start( argptr, format );
- len = Q_vsnprintf( buffer + 4, sizeof( buffer ) - 4, format, argptr );
+ len += Q_vsnprintf( buffer + len, sizeof( buffer ) - len, format, argptr );
va_end( argptr );
- if( len >= sizeof( buffer ) - 4 ) {
+ if( len >= sizeof( buffer ) ) {
Com_WPrintf( "%s: overflow\n", __func__ );
return NET_ERROR;
}
// send the datagram
- return NET_SendPacket( sock, address, len + 4, buffer );
+ return NET_SendPacket( sock, address, len, buffer );
}
// ============================================================================
diff --git a/source/net_chan.h b/source/net_chan.h
index 0fb35f0..1950243 100644
--- a/source/net_chan.h
+++ b/source/net_chan.h
@@ -64,8 +64,8 @@ extern cvar_t *net_maxmsglen;
extern cvar_t *net_chantype;
void Netchan_Init( void );
-neterr_t Netchan_OutOfBandPrint( netsrc_t sock, const netadr_t *adr,
- const char *format, ... );
+neterr_t Netchan_OutOfBand( netsrc_t sock, const netadr_t *adr,
+ const char *format, ... ) q_printf( 3, 4 );
netchan_t *Netchan_Setup( netsrc_t sock, netchan_type_t type,
const netadr_t *adr, int qport, size_t maxpacketlen, int protocol );
void Netchan_Close( netchan_t *netchan );
diff --git a/source/net_common.c b/source/net_common.c
index 0067bfc..328c298 100644
--- a/source/net_common.c
+++ b/source/net_common.c
@@ -489,7 +489,9 @@ static neterr_t get_icmp_error( int s ) {
case EHOSTUNREACH:
case EHOSTDOWN:
case ECONNREFUSED:
+#ifdef ENONET
case ENONET:
+#endif
Com_DPrintf( "%s: %s from %s\n", __func__,
NET_ErrorString(), NET_AdrToString( &net_from ) );
return NET_ERROR;
@@ -1442,11 +1444,11 @@ qboolean NET_GetAddress( netsrc_t sock, netadr_t *adr ) {
}
static size_t NET_UpRate_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%"PRIz, net_rate_up );
+ return Q_scnprintf( buffer, size, "%"PRIz, net_rate_up );
}
static size_t NET_DnRate_m( char *buffer, size_t size ) {
- return Q_snprintf( buffer, size, "%"PRIz, net_rate_dn );
+ return Q_scnprintf( buffer, size, "%"PRIz, net_rate_dn );
}
static void net_udp_param_changed( cvar_t *self ) {
diff --git a/source/q_shared.c b/source/q_shared.c
index b97e987..7eebbff 100644
--- a/source/q_shared.c
+++ b/source/q_shared.c
@@ -1039,21 +1039,6 @@ size_t Q_UnescapeString( char *out, const char *in, size_t bufsize, escape_t fla
#endif
/*
-================
-Com_LocalTime
-================
-*/
-void Com_LocalTime( qtime_t *qtime ) {
- time_t clock;
- struct tm *localTime;
-
- time( &clock );
- localTime = localtime( &clock );
-
- *qtime = *localTime;
-}
-
-/*
============
va
@@ -1323,7 +1308,7 @@ Com_PageInMemory
*/
int paged_total;
-void Com_PageInMemory (void *buffer, int size)
+void Com_PageInMemory (void *buffer, size_t size)
{
int i;
@@ -1387,6 +1372,8 @@ int Q_strcasecmp( const char *s1, const char *s2 ) {
/*
===============
Q_strlcpy
+
+Returns length of the source string.
===============
*/
size_t Q_strlcpy( char *dst, const char *src, size_t size ) {
@@ -1404,6 +1391,8 @@ size_t Q_strlcpy( char *dst, const char *src, size_t size ) {
/*
===============
Q_strlcat
+
+Returns length of the source and destinations strings combined.
===============
*/
size_t Q_strlcat( char *dst, const char *src, size_t size ) {
@@ -1422,6 +1411,10 @@ size_t Q_strlcat( char *dst, const char *src, size_t size ) {
/*
===============
Q_concat
+
+Returns number of characters that would be written into the buffer,
+excluding trailing '\0'. If the returned value is equal to or greater than
+buffer size, resulting string is truncated.
===============
*/
size_t Q_concat( char *dest, size_t size, ... ) {
@@ -1451,13 +1444,20 @@ size_t Q_concat( char *dest, size_t size, ... ) {
===============
Q_vsnprintf
-Work around broken M$ C runtime semantics.
+Returns number of characters that would be written into the buffer,
+excluding trailing '\0'. If the returned value is equal to or greater than
+buffer size, resulting string is truncated.
===============
*/
size_t Q_vsnprintf( char *dest, size_t size, const char *fmt, va_list argptr ) {
int ret;
+ if( size > INT_MAX ) {
+ Com_Error( ERR_FATAL, "%s: bad buffer size", __func__ );
+ }
+
#ifdef _WIN32
+ // work around broken M$ C runtime semantics.
if( !size ) {
return 0;
}
@@ -1469,6 +1469,7 @@ size_t Q_vsnprintf( char *dest, size_t size, const char *fmt, va_list argptr ) {
ret = vsnprintf( dest, size, fmt, argptr );
#endif
+ // this shouldn't happen
if( ret < 0 ) {
if( size ) {
*dest = 0;
@@ -1476,12 +1477,37 @@ size_t Q_vsnprintf( char *dest, size_t size, const char *fmt, va_list argptr ) {
ret = 0;
}
- return ret;
+ return ( size_t )ret;
}
/*
===============
+Q_vscnprintf
+
+Returns number of characters actually written into the buffer,
+excluding trailing '\0'. If buffer size is 0, this function does nothing
+and returns 0.
+===============
+*/
+size_t Q_vscnprintf( char *dest, size_t size, const char *fmt, va_list argptr ) {
+ size_t ret;
+
+ if( !size ) {
+ return 0;
+ }
+
+ ret = Q_vsnprintf( dest, size, fmt, argptr );
+ return ret >= size ? size - 1 : ret;
+}
+
+
+/*
+===============
Q_snprintf
+
+Returns number of characters that would be written into the buffer,
+excluding trailing '\0'. If the returned value is equal to or greater than
+buffer size, resulting string is truncated.
===============
*/
size_t Q_snprintf( char *dest, size_t size, const char *fmt, ... ) {
@@ -1495,11 +1521,28 @@ size_t Q_snprintf( char *dest, size_t size, const char *fmt, ... ) {
return ret;
}
+/*
+===============
+Q_scnprintf
+
+Returns number of characters actually written into the buffer,
+excluding trailing '\0'. If buffer size is 0, this function does nothing
+and returns 0.
+===============
+*/
+size_t Q_scnprintf( char *dest, size_t size, const char *fmt, ... ) {
+ va_list argptr;
+ size_t ret;
+
+ va_start( argptr, fmt );
+ ret = Q_vscnprintf( dest, size, fmt, argptr );
+ va_end( argptr );
+
+ return ret;
+}
+
char *Q_strchrnul( const char *s, int c ) {
- while( *s ) {
- if( *s == c ) {
- return ( char * )s;
- }
+ while( *s && *s != c ) {
s++;
}
return ( char * )s;
diff --git a/source/q_shared.h b/source/q_shared.h
index b36b589..74d799f 100644
--- a/source/q_shared.h
+++ b/source/q_shared.h
@@ -296,9 +296,6 @@ vec_t VectorNormalize2 (vec3_t v, vec3_t out);
int Q_CeilPowerOfTwo( int value );
float Com_CalcFov( float fov_x, float width, float height );
-void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
-void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
-
void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
static inline float LerpAngle( float a2, float a1, float frac ) {
@@ -511,10 +508,13 @@ size_t Q_strlcpy( char *dst, const char *src, size_t size );
size_t Q_strlcat( char *dst, const char *src, size_t size );
size_t Q_concat( char *dest, size_t size, ... ) q_sentinel;
-size_t Q_snprintf( char *dest, size_t size, const char *fmt, ... ) q_printf( 3, 4 );
+
size_t Q_vsnprintf( char *dest, size_t size, const char *fmt, va_list argptr );
+size_t Q_vscnprintf( char *dest, size_t size, const char *fmt, va_list argptr );
+size_t Q_snprintf( char *dest, size_t size, const char *fmt, ... ) q_printf( 3, 4 );
+size_t Q_scnprintf( char *dest, size_t size, const char *fmt, ... ) q_printf( 3, 4 );
-void Com_PageInMemory (void *buffer, int size);
+void Com_PageInMemory (void *buffer, size_t size);
unsigned COM_ParseHex( const char *string );
qboolean COM_ParseColor( const char *s, color_t color );
@@ -555,23 +555,23 @@ static inline float FloatSwap( float f ) {
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define BigShort ShortSwap
-#define BigLong LongSwap
+#define BigShort ShortSwap
+#define BigLong LongSwap
#define BigFloat FloatSwap
-#define LittleShort( x ) (( uint16_t )(x))
-#define LittleLong( x ) (( uint32_t )(x))
-#define LittleFloat( x ) (( float )(x))
-#define MakeLong( b1, b2, b3, b4 ) (((b4)<<24)|((b3)<<16)|((b2)<<8)|(b1))
-#define MakeShort( b1, b2 ) (((b2)<<8)|(b1))
+#define LittleShort(x) ((uint16_t)(x))
+#define LittleLong(x) ((uint32_t)(x))
+#define LittleFloat(x) ((float)(x))
+#define MakeLong(b1,b2,b3,b4) (((b4)<<24)|((b3)<<16)|((b2)<<8)|(b1))
+#define MakeShort(b1,b2) (((b2)<<8)|(b1))
#elif __BYTE_ORDER == __BIG_ENDIAN
-#define BigShort (( uint16_t )(x))
-#define BigLong (( uint32_t )(x))
-#define BigFloat (( float )(x))
+#define BigShort ((uint16_t)(x))
+#define BigLong ((uint32_t)(x))
+#define BigFloat ((float)(x))
#define LittleShort ShortSwap
-#define LittleLong LongSwap
+#define LittleLong LongSwap
#define LittleFloat FloatSwap
-#define MakeLong( b1, b2, b3, b4 ) (((b1)<<24)|((b2)<<16)|((b3)<<8)|(b4))
-#define MakeShort( b1, b2 ) (((b1)<<8)|(b2))
+#define MakeLong(b1,b2,b3,b4) (((b1)<<24)|((b2)<<16)|((b3)<<8)|(b4))
+#define MakeShort(b1,b2) (((b1)<<8)|(b2))
#else
#error Unknown byte order
#endif
@@ -595,12 +595,6 @@ int Info_SubValidate( const char *s );
void Info_NextPair( const char **string, char *key, char *value );
void Info_Print( const char *infostring );
-//=============================================
-
-typedef struct tm qtime_t;
-
-void Com_LocalTime( qtime_t *time );
-
/*
==========================================================
diff --git a/source/sv_ccmds.c b/source/sv_ccmds.c
index 338538e..a4d5b37 100644
--- a/source/sv_ccmds.c
+++ b/source/sv_ccmds.c
@@ -218,11 +218,34 @@ For development work
==================
*/
static void SV_Map_f( void ) {
- if( Cmd_Argc() != 2 ) {
+ if( Cmd_Argc() < 2 ) {
Com_Printf( "Usage: %s <mapname>\n", Cmd_Argv( 0 ) );
return;
}
+ if( sv.state == ss_game && sv_allow_map->integer != 1 &&
+ Cvar_CountLatchedVars() == 0 && strcmp( Cmd_Argv( 2 ), "force" ) )
+ {
+ if( sv_allow_map->integer == 0 ) {
+ static qboolean warned;
+
+ Com_Printf(
+ "Using '%s' command will cause full server restart, "
+ "which is likely not what you want. Use 'gamemap' "
+ "command for changing maps.\n", Cmd_Argv( 0 ) );
+ if( !warned ) {
+ Com_Printf(
+ "(You can set 'sv_allow_map' to 1 "
+ "if you wish to disable this check.)\n" );
+ warned = qtrue;
+ }
+ return;
+ }
+
+ SV_Map( Cmd_Argv( 1 ), qfalse );
+ return;
+ }
+
SV_Map( Cmd_Argv( 1 ), qtrue );
}
@@ -248,7 +271,8 @@ static void SV_DumpEnts_f( void ) {
return;
}
- len = Q_concat( buffer, sizeof( buffer ), "maps/", Cmd_Argv( 1 ), ".ent", NULL );
+ len = Q_concat( buffer, sizeof( buffer ),
+ "maps/", Cmd_Argv( 1 ), ".ent", NULL );
if( len >= sizeof( buffer ) ) {
Com_EPrintf( "Oversize filename specified.\n" );
return;
@@ -292,16 +316,29 @@ void SV_Kick_f( void ) {
SV_DropClient( sv_client, "kicked" );
sv_client->lastmessage = svs.realtime; // min case there is a funny zombie
+ // optionally ban their IP address
+ if( !strcmp( Cmd_Argv( 0 ), "kickban" ) ) {
+ netadr_t *addr = &sv_client->netchan->remote_address;
+ if( addr->type == NA_IP ) {
+ addrmatch_t *match = Z_Malloc( sizeof( *match ) );
+ match->addr = BigLong( *( uint32_t * )addr->ip );
+ match->mask = 0xffffffffU;
+ match->hits = 0;
+ match->comment[0] = 0;
+ List_Append( &sv_banlist, &match->entry );
+ }
+ }
+
sv_client = NULL;
sv_player = NULL;
}
-static void SV_DumpClients( void ) {
+static void dump_clients( void ) {
client_t *client;
Com_Printf(
-"num score ping name lastmsg address rate proto\n"
-"--- ----- ---- ---------------- ------- --------------------- ----- -----\n" );
+"num score ping name lastmsg address rate pr fps\n"
+"--- ----- ---- ---------------- ------- --------------------- ----- -- ---\n" );
FOR_EACH_CLIENT( client ) {
Com_Printf( "%3i %5i ", client->number,
client->edict->client->ps.stats[STAT_FRAGS] );
@@ -330,24 +367,38 @@ static void SV_DumpClients( void ) {
&client->netchan->remote_address ) );
Com_Printf( "%5"PRIz" ", client->rate );
Com_Printf( "%2i ", client->protocol );
+ Com_Printf( "%3i ", client->fps );
Com_Printf( "\n" );
}
}
-static void SV_DumpVersions( void ) {
+static void dump_versions( void ) {
client_t *client;
Com_Printf(
"num name version\n"
"--- ---------------- -----------------------------------------\n" );
-
+
FOR_EACH_CLIENT( client ) {
Com_Printf( "%3i %-16.16s %-40.40s\n",
client->number, client->name,
- client->versionString ? client->versionString : "" );
+ client->versionString ? client->versionString : "-" );
}
}
+static void dump_downloads( void ) {
+ client_t *client;
+
+ Com_Printf(
+"num name download\n"
+"--- ---------------- -----------------------------------------\n" );
+
+ FOR_EACH_CLIENT( client ) {
+ Com_Printf( "%3i %-16.16s %-40.40s\n",
+ client->number, client->name,
+ client->downloadname ? client->downloadname : "-" );
+ }
+}
/*
================
@@ -368,9 +419,13 @@ static void SV_Status_f( void ) {
Com_Printf( "No UDP clients.\n" );
} else {
if( Cmd_Argc() > 1 ) {
- SV_DumpVersions();
+ if( *Cmd_Argv( 1 ) == 'd' ) {
+ dump_downloads();
+ } else {
+ dump_versions();
+ }
} else {
- SV_DumpClients();
+ dump_clients();
}
}
Com_Printf( "\n" );
@@ -418,7 +473,7 @@ SV_Heartbeat_f
==================
*/
static void SV_Heartbeat_f( void ) {
- svs.last_heartbeat = 0;
+ svs.last_heartbeat = svs.realtime - HEARTBEAT_SECONDS*1000;
}
@@ -460,16 +515,24 @@ static void SV_DumpUser_f( void ) {
if( !SV_SetPlayer() )
return;
- Com_Printf( "userinfo\n" );
+ Com_Printf( "\nuserinfo\n" );
Com_Printf( "--------\n" );
Info_Print( sv_client->userinfo );
- if( sv_client->versionString ) {
- Com_Printf( "version %s\n", sv_client->versionString );
- }
+
+ Com_Printf( "\nmiscinfo\n" );
+ Com_Printf( "--------\n" );
+ Com_Printf( "version %s\n",
+ sv_client->versionString ? sv_client->versionString : "-" );
+ Com_Printf( "protocol %d/%d\n",
+ sv_client->protocol, sv_client->version );
+ Com_Printf( "ping %d\n", sv_client->ping );
+ Com_Printf( "fps %d\n", sv_client->fps );
+#ifdef USE_PACKETDUP
+ Com_Printf( "packetdup %d\n", sv_client->numpackets - 1 );
+#endif
sv_client = NULL;
sv_player = NULL;
-
}
/*
@@ -627,8 +690,8 @@ static qboolean SV_ParseMask( const char *s, uint32_t *addr, uint32_t *mask ) {
return qfalse;
}
- *addr = *( uint32_t * )address.ip;
- *mask = 0xffffffffU >> ( 32 - bits ); // LE
+ *addr = BigLong( *( uint32_t * )address.ip );
+ *mask = ~( ( 1 << ( 32 - bits ) ) - 1 );
return qtrue;
}
@@ -639,7 +702,7 @@ void SV_AddMatch_f( list_t *list ) {
size_t len;
if( Cmd_Argc() < 2 ) {
- Com_Printf( "Usage: %s <address/mask>\n", Cmd_Argv( 0 ) );
+ Com_Printf( "Usage: %s <address[/mask]> [comment]\n", Cmd_Argv( 0 ) );
return;
}
@@ -662,6 +725,7 @@ void SV_AddMatch_f( list_t *list ) {
match = Z_Malloc( sizeof( *match ) + len );
match->addr = addr;
match->mask = mask;
+ match->hits = 0;
memcpy( match->comment, s, len + 1 );
List_Append( list, &match->entry );
}
@@ -673,7 +737,7 @@ void SV_DelMatch_f( list_t *list ) {
int i;
if( Cmd_Argc() < 2 ) {
- Com_Printf( "Usage: %s <address/mask|id|all>\n", Cmd_Argv( 0 ) );
+ Com_Printf( "Usage: %s <address[/mask]|id|all>\n", Cmd_Argv( 0 ) );
return;
}
@@ -737,19 +801,20 @@ void SV_ListMatches_f( list_t *list ) {
return;
}
- Com_Printf( "id address/mask comment\n"
- "-- ------------------ -------\n" );
+ Com_Printf( "id address/mask hits comment\n"
+ "-- ------------------ ---- -------\n" );
count = 1;
LIST_FOR_EACH( addrmatch_t, match, list, entry ) {
- *( uint32_t * )ip = match->addr;
+ *( uint32_t * )ip = BigLong( match->addr );
for( i = 0; i < 32; i++ ) {
- if( ( match->mask & ( 1 << i ) ) == 0 ) {
+ if( match->mask & ( 1 << i ) ) {
break;
}
}
Q_snprintf( addr, sizeof( addr ), "%d.%d.%d.%d/%d",
- ip[0], ip[1], ip[2], ip[3], i );
- Com_Printf( "%-2d %-18s %s\n", count, addr, match->comment );
+ ip[0], ip[1], ip[2], ip[3], 32 - i );
+ Com_Printf( "%-2d %-18s %-4u %s\n", count, addr,
+ match->hits, match->comment );
count++;
}
}
@@ -1029,6 +1094,7 @@ static void SV_ListFilterCmds_f( void ) {
static const cmdreg_t c_server[] = {
{ "heartbeat", SV_Heartbeat_f },
{ "kick", SV_Kick_f, SV_SetPlayer_c },
+ { "kickban", SV_Kick_f, SV_SetPlayer_c },
{ "status", SV_Status_f },
{ "serverinfo", SV_Serverinfo_f },
{ "dumpuser", SV_DumpUser_f, SV_SetPlayer_c },
diff --git a/source/sv_local.h b/source/sv_local.h
index 0ca4906..fc8f8ba 100644
--- a/source/sv_local.h
+++ b/source/sv_local.h
@@ -187,6 +187,8 @@ typedef struct client_s {
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;
@@ -210,6 +212,7 @@ typedef struct client_s {
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
@@ -290,6 +293,7 @@ typedef struct {
list_t entry;
uint32_t addr;
uint32_t mask;
+ unsigned hits;
char comment[1];
} addrmatch_t;
@@ -378,13 +382,13 @@ extern cvar_t *sv_calcpings_method;
extern cvar_t *sv_changemapcmd;
extern cvar_t *sv_strafejump_hack;
-extern cvar_t *sv_bodyque_hack;
#ifndef _WIN32
extern cvar_t *sv_oldgame_hack;
#endif
#if USE_PACKETDUP
extern cvar_t *sv_packetdup_hack;
#endif
+extern cvar_t *sv_allow_map;
extern cvar_t *sv_status_limit;
extern cvar_t *sv_status_show;
diff --git a/source/sv_main.c b/source/sv_main.c
index 021ba2c..305a951 100644
--- a/source/sv_main.c
+++ b/source/sv_main.c
@@ -37,21 +37,12 @@ cvar_t *sv_timeout; // seconds without any message
cvar_t *sv_zombietime; // seconds to sink messages after disconnect
cvar_t *sv_ghostime;
-cvar_t *rcon_password; // password for remote server commands
cvar_t *sv_password;
cvar_t *sv_reserved_password;
cvar_t *sv_force_reconnect;
cvar_t *sv_show_name_changes;
-cvar_t *allow_download;
-cvar_t *allow_download_players;
-cvar_t *allow_download_models;
-cvar_t *allow_download_sounds;
-cvar_t *allow_download_maps;
-cvar_t *allow_download_demos;
-cvar_t *allow_download_other;
-
cvar_t *sv_airaccelerate;
cvar_t *sv_qwmod; // atu QW Physics modificator
cvar_t *sv_novis;
@@ -74,13 +65,13 @@ cvar_t *sv_calcpings_method;
cvar_t *sv_changemapcmd;
cvar_t *sv_strafejump_hack;
-cvar_t *sv_bodyque_hack;
#ifndef _WIN32
cvar_t *sv_oldgame_hack;
#endif
#if USE_PACKETDUP
cvar_t *sv_packetdup_hack;
#endif
+cvar_t *sv_allow_map;
cvar_t *sv_iplimit;
cvar_t *sv_status_limit;
@@ -136,6 +127,10 @@ void SV_CleanClient( client_t *client ) {
Z_Free( client->download );
client->download = NULL;
}
+ if( client->downloadname ) {
+ Z_Free( client->downloadname );
+ client->downloadname = NULL;
+ }
if( client->versionString ) {
Z_Free( client->versionString );
@@ -259,11 +254,12 @@ void SV_RateInit( ratelimit_t *r, int limit, int period ) {
}
addrmatch_t *SV_MatchAddress( list_t *list, netadr_t *address ) {
- uint32_t addr = *( uint32_t * )address->ip;
+ uint32_t addr = BigLong( *( uint32_t * )address->ip );
addrmatch_t *match;
LIST_FOR_EACH( addrmatch_t, match, list, entry ) {
if( ( addr & match->mask ) == ( match->addr & match->mask ) ) {
+ match->hits++;
return match;
}
}
@@ -334,28 +330,6 @@ static size_t SV_StatusString( char *status ) {
return total;
}
-static void q_printf( 1, 2 ) SV_OobPrintf( const char *format, ... ) {
- va_list argptr;
- char buffer[MAX_PACKETLEN_DEFAULT];
- size_t len;
-
- // write the packet header
- memcpy( buffer, "\xff\xff\xff\xffprint\n", 10 );
-
- va_start( argptr, format );
- len = Q_vsnprintf( buffer + 10, sizeof( buffer ) - 10, format, argptr );
- va_end( argptr );
-
- if( len >= sizeof( buffer ) - 10 ) {
- Com_WPrintf( "%s: overflow\n", __func__ );
- return;
- }
-
- // send the datagram
- NET_SendPacket( NS_SERVER, &net_from, len + 10, buffer );
-}
-
-
/*
================
SVC_Status
@@ -381,11 +355,12 @@ static void SVC_Status( void ) {
// write the packet header
memcpy( buffer, "\xff\xff\xff\xffprint\n", 10 );
+ len = 10;
- len = SV_StatusString( buffer + 10 );
+ len += SV_StatusString( buffer + len );
// send the datagram
- NET_SendPacket( NS_SERVER, &net_from, len + 10, buffer );
+ NET_SendPacket( NS_SERVER, &net_from, len, buffer );
}
/*
@@ -422,7 +397,6 @@ static void SVC_Info( void ) {
size_t len;
int count;
int version;
- client_t *client;
if (sv_maxclients->integer == 1)
return; // ignore in single player
@@ -433,11 +407,7 @@ static void SVC_Info( void ) {
return;
}
- count = 0;
- FOR_EACH_CLIENT( client ) {
- if (client->state != cs_zombie)
- count++;
- }
+ count = SV_CountClients();
len = Q_snprintf (string, sizeof(string),
"\xff\xff\xff\xffinfo\n%16s %8s %2i/%2i\n",
@@ -505,10 +475,13 @@ static void SVC_GetChallenge( void ) {
}
// send it back
- Netchan_OutOfBandPrint( NS_SERVER, &net_from,
+ Netchan_OutOfBand( NS_SERVER, &net_from,
"challenge %u p=34,35,36", challenge );
}
+#define SV_OobPrintf(...) \
+ Netchan_OutOfBand( NS_SERVER, &net_from, "print\n" __VA_ARGS__ )
+
/*
==================
SVC_DirectConnect
@@ -919,7 +892,7 @@ static void SVC_DirectConnect( void ) {
}
// send the connect packet to the client
- Netchan_OutOfBandPrint( NS_SERVER, &net_from, "client_connect%s%s%s map=%s",
+ Netchan_OutOfBand( NS_SERVER, &net_from, "client_connect%s%s%s map=%s",
ncstring, acstring, dlstring, newcl->mapname );
List_Init( &newcl->msg_free );
@@ -1095,8 +1068,7 @@ static int ping_nop( client_t *cl ) {
}
static int ping_min( client_t *cl ) {
- int j;
- int count = 9999;
+ int j, count = 9999;
for( j = 0; j < LATENCY_COUNTS; j++ ) {
if( cl->frame_latency[j] > 0 ) {
@@ -1109,8 +1081,7 @@ static int ping_min( client_t *cl ) {
}
static int ping_avg( client_t *cl ) {
- int j;
- int total = 0, count = 0;
+ int j, total = 0, count = 0;
for( j = 0; j < LATENCY_COUNTS; j++ ) {
if( cl->frame_latency[j] > 0 ) {
@@ -1164,6 +1135,14 @@ static void SV_GiveMsec( void ) {
FOR_EACH_CLIENT( cl ) {
cl->commandMsec = 1800; // 1600 + some slop
}
+
+ if( sv.framenum & 63 )
+ return;
+
+ FOR_EACH_CLIENT( cl ) {
+ cl->fps = ( cl->numMoves * 10 ) >> 6;
+ cl->numMoves = 0;
+ }
}
@@ -1388,7 +1367,7 @@ static void SV_CheckTimeouts( void ) {
}
}
if( delta > drop_time || ( client->state == cs_assigned && delta > ghost_time ) ) {
- SV_DropClient( client, "timed out" );
+ SV_DropClient( client, "connection timed out" );
SV_RemoveClient( client ); // don't bother with zombie state
}
}
@@ -1484,16 +1463,17 @@ static void SV_MasterHeartbeat( void ) {
// write the packet header
memcpy( buffer, "\xff\xff\xff\xffheartbeat\n", 14 );
+ len = 14;
// send the same string that we would give for a status OOB command
- len = SV_StatusString( buffer + 14 );
+ len += SV_StatusString( buffer + len );
// send to group master
for( i = 0; i < MAX_MASTERS; i++ ) {
if( master_adr[i].port ) {
Com_DPrintf( "Sending heartbeat to %s\n",
NET_AdrToString( &master_adr[i] ) );
- NET_SendPacket( NS_SERVER, &master_adr[i], len + 14, buffer );
+ NET_SendPacket( NS_SERVER, &master_adr[i], len, buffer );
}
}
}
@@ -1844,18 +1824,9 @@ void SV_Init( void ) {
sv_force_reconnect = Cvar_Get ( "sv_force_reconnect", "", CVAR_LATCH );
sv_show_name_changes = Cvar_Get( "sv_show_name_changes", "0", 0 );
- allow_download = Cvar_Get( "allow_download", "1", CVAR_ARCHIVE );
- allow_download_players = Cvar_Get( "allow_download_players", "0", CVAR_ARCHIVE );
- allow_download_models = Cvar_Get( "allow_download_models", "1", CVAR_ARCHIVE );
- allow_download_sounds = Cvar_Get( "allow_download_sounds", "1", CVAR_ARCHIVE );
- allow_download_maps = Cvar_Get( "allow_download_maps", "1", CVAR_ARCHIVE );
- allow_download_demos = Cvar_Get( "allow_download_demos", "0", 0 );
- allow_download_other = Cvar_Get( "allow_download_other", "0", 0 );
-
sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
sv_qwmod = Cvar_Get( "sv_qwmod", "0", CVAR_LATCH ); //atu QWMod
sv_public = Cvar_Get( "public", "0", CVAR_LATCH );
- rcon_password = Cvar_Get( "rcon_password", "", CVAR_PRIVATE );
sv_password = Cvar_Get( "sv_password", "", CVAR_PRIVATE );
sv_reserved_password = Cvar_Get( "sv_reserved_password", "", CVAR_PRIVATE );
sv_locked = Cvar_Get( "sv_locked", "0", 0 );
@@ -1872,7 +1843,6 @@ void SV_Init( void ) {
sv_strafejump_hack = Cvar_Get( "sv_strafejump_hack", "1", CVAR_LATCH );
- sv_bodyque_hack = Cvar_Get( "sv_bodyque_hack", "0", 0 );
#ifndef _WIN32
sv_oldgame_hack = Cvar_Get( "sv_oldgame_hack", "0", CVAR_LATCH );
#endif
@@ -1880,6 +1850,8 @@ void SV_Init( void ) {
sv_packetdup_hack = Cvar_Get( "sv_packetdup_hack", "0", 0 );
#endif
+ sv_allow_map = Cvar_Get( "sv_allow_map", "0", 0 );
+
sv_iplimit = Cvar_Get( "sv_iplimit", "3", 0 );
sv_status_show = Cvar_Get( "sv_status_show", "2", 0 );
diff --git a/source/sv_null.c b/source/sv_null.c
deleted file mode 100644
index bcea168..0000000
--- a/source/sv_null.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "com_local.h"
-
-cvar_t *allow_download;
-cvar_t *allow_download_players;
-cvar_t *allow_download_models;
-cvar_t *allow_download_sounds;
-cvar_t *allow_download_maps;
-cvar_t *allow_download_demos;
-cvar_t *allow_download_other;
-
-cvar_t *rcon_password;
-
-void SV_Init( void ) {
- allow_download = Cvar_Get( "allow_download", "1", CVAR_ARCHIVE );
- allow_download_players = Cvar_Get( "allow_download_players", "0", CVAR_ARCHIVE );
- allow_download_models = Cvar_Get( "allow_download_models", "1", CVAR_ARCHIVE );
- allow_download_sounds = Cvar_Get( "allow_download_sounds", "1", CVAR_ARCHIVE );
- allow_download_maps = Cvar_Get( "allow_download_maps", "1", CVAR_ARCHIVE );
- allow_download_demos = Cvar_Get( "allow_download_demos", "0", 0 );
- allow_download_other = Cvar_Get( "allow_download_other", "0", 0 );
-
- rcon_password = Cvar_Get( "rcon_password", "", CVAR_PRIVATE );
-}
-
-void SV_Shutdown( const char *finalmsg, killtype_t type ) {
-}
-
-void SV_Frame( int msec ) {
-}
-
-void SV_ProcessEvents( void ) {
-}
-
diff --git a/source/sv_send.c b/source/sv_send.c
index 1310e3f..0994548 100644
--- a/source/sv_send.c
+++ b/source/sv_send.c
@@ -138,7 +138,7 @@ void SV_ClientPrintf( client_t *client, int level, const char *fmt, ... ) {
=================
SV_BroadcastPrintf
-Sends text to all active clients, including MVD clients.
+Sends text to all active clients.
NOT archived in MVD stream.
=================
*/
diff --git a/source/sv_user.c b/source/sv_user.c
index bda4813..dfd03fe 100644
--- a/source/sv_user.c
+++ b/source/sv_user.c
@@ -546,6 +546,8 @@ static void SV_NextDownload_f( void ) {
if( sv_client->downloadcount == sv_client->downloadsize ) {
Z_Free( sv_client->download );
sv_client->download = NULL;
+ Z_Free( sv_client->downloadname );
+ sv_client->downloadname = NULL;
}
SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR );
@@ -570,7 +572,6 @@ static void SV_BeginDownload_f( void ) {
int offset = 0;
cvar_t *allow;
int length;
- char *filename;
length = Q_ClearStr( name, Cmd_Argv( 1 ), sizeof( name ) );
Q_strlwr( name );
@@ -604,14 +605,22 @@ static void SV_BeginDownload_f( void ) {
if( strncmp( name, "players/", 8 ) == 0 ) {
allow = allow_download_players;
- } else if( strncmp( name, "models/", 7 ) == 0 ) {
+ } else if( strncmp( name, "models/", 7 ) == 0 ||
+ strncmp( name, "sprites/", 8 ) == 0 )
+ {
allow = allow_download_models;
} else if( strncmp( name, "sound/", 6 ) == 0 ) {
allow = allow_download_sounds;
} else if( strncmp( name, "maps/", 5 ) == 0 ) {
allow = allow_download_maps;
+ } else if( strncmp( name, "textures/", 9 ) == 0 ||
+ strncmp( name, "env/", 4 ) == 0 )
+ {
+ allow = allow_download_textures;
+ } else if( strncmp( name, "pics/", 5 ) == 0 ) {
+ allow = allow_download_pics;
} else {
- allow = allow_download_other;
+ allow = allow_download_others;
}
if( !allow->integer ) {
@@ -626,9 +635,7 @@ static void SV_BeginDownload_f( void ) {
sv_client->download = NULL;
}
- filename = name;
-
- downloadsize = FS_LoadFileEx( filename, NULL, 0, TAG_SERVER );
+ downloadsize = FS_LoadFileEx( name, NULL, 0, TAG_SERVER );
if( downloadsize == INVALID_LENGTH || downloadsize == 0
// special check for maps, if it came from a pak file, don't allow
@@ -661,9 +668,10 @@ static void SV_BeginDownload_f( void ) {
return;
}
- sv_client->downloadsize = FS_LoadFileEx( filename,
+ sv_client->downloadsize = FS_LoadFileEx( name,
( void ** )&sv_client->download, 0, TAG_SERVER );
sv_client->downloadcount = offset;
+ sv_client->downloadname = SV_CopyString( name );
Com_DPrintf( "Downloading %s to %s\n", name, sv_client->name );
@@ -689,9 +697,12 @@ static void SV_StopDownload_f( void ) {
MSG_WriteByte( percent );
SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR );
- Com_DPrintf( "Download for %s stopped by user request\n", sv_client->name );
+ Com_DPrintf( "Download of %s to %s stopped by user request\n",
+ sv_client->downloadname, sv_client->name );
Z_Free( sv_client->download );
sv_client->download = NULL;
+ Z_Free( sv_client->downloadname );
+ sv_client->downloadname = NULL;
}
//============================================================================
@@ -920,6 +931,7 @@ SV_ClientThink
*/
static inline void SV_ClientThink( usercmd_t *cmd ) {
sv_client->commandMsec -= cmd->msec;
+ sv_client->numMoves++;
if( sv_client->commandMsec < 0 && sv_enforcetime->integer ) {
#ifdef _DEBUG
diff --git a/source/sw_local.h b/source/sw_local.h
index 24b2548..3d17081 100644
--- a/source/sw_local.h
+++ b/source/sw_local.h
@@ -667,6 +667,9 @@ extern surfcache_t *sc_rover, *sc_base;
void R_RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
+void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
+void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
+
float R_DLightPoint (vec3_t p);
void R_NewMap (void);
diff --git a/wiki/doc.mdwn b/wiki/doc.mdwn
index 92a5c75..53e412e 100644
--- a/wiki/doc.mdwn
+++ b/wiki/doc.mdwn
@@ -2,5 +2,6 @@ Documentation for Q2PRO.
* [[Server_commands_and_cvars|server]].
* [[Client_commands_and_cvars|client]].
-* Building instructions for [[MinGW]].
-* [[Netcode]] details.
+* Building instructions for Win32 hosted [[MinGW]].
+* Some technical [[netcode]] details.
+* Online Q2PRO [configurator](http://skuller.ath.cx/q2pro/config.cgi).
diff --git a/wiki/doc/netcode.mdwn b/wiki/doc/netcode.mdwn
index c9feb7e..4a8acb1 100644
--- a/wiki/doc/netcode.mdwn
+++ b/wiki/doc/netcode.mdwn
@@ -25,17 +25,17 @@ Key features of Q2PRO protocol from technical perspective:
predicted position.
* Server is able to filter gibs/footsteps on per-client basis.
* Netchan level packet fragmentation support with possible
- asynchronous delivery (i.e. fragments are sent with less then 100ms
- granularity which depends on client `rate` setting). No more frame
+ asynchronous delivery (i.e. fragments are sent with less then 100 ms
+ granularity as soon as client `rate` limit allows). No more frame
overflows in mods with extremly high activity. Faster map load times
due to the higher game state compression ratio, as all configstrings
- and baselines are compressed in single block.
+ and baselines are compressed in a single pass.
* Per-key delta userinfo updates. E.g. if you often update your
FOV setting, only a few bytes will be transmitted instead of
the whole userinfo string.
-* Ability to dynamically update client entity number.
- Needed for in-eyes chasecam mode to work properly
- (requires support from game DLL, only used by MVD subsystem for now).
+* Ability to dynamically update client entity number. Needed for in-eyes
+ chasecam mode to work properly. This requires support from the game mod,
+ currently provided by the MVD subsystem and modern mods such as OpenTDM.
[r1q2]: http://r-1.ch/r1q2-protocol.txt
diff --git a/wiki/doc/q2pro.menu b/wiki/doc/q2pro.menu
index ddb4f36..baba96a 100644
--- a/wiki/doc/q2pro.menu
+++ b/wiki/doc/q2pro.menu
@@ -100,6 +100,8 @@ begin downloads
toggle "player models/skins" allow_download_players
toggle "models" allow_download_models
toggle "sounds" allow_download_sounds
+ toggle "textures" allow_download_textures
+ toggle "pics" allow_download_pics
end
begin gameflags
diff --git a/wiki/doc/server.mdwn b/wiki/doc/server.mdwn
index 104fe9f..8fb3940 100644
--- a/wiki/doc/server.mdwn
+++ b/wiki/doc/server.mdwn
@@ -190,18 +190,11 @@ Hacks
----------
- `set sv_oldgame_hack 0` (boolean)
-On Unix systems, enables ABI compatibility mode which allows loading of
+On UNIX-like systems, enables ABI compatibility mode which allows loading of
game libraries built using ancient GCC versions. If you happen to run closed
source game mod and your server crashes while loading a map, try enabling
this variable.
-- `set sv_bodyque_hack 0` (boolean)
-Attempts to prevent "flying bodies" effect introduced by some buggy
-mods. This hack assumes the mod allocates certain range of entity
-slots for "body queue" and disables client side interpolation of
-those entities. Use this hack with caution as it may not be compatible
-with all mods and causes slightly higher bandwidth usage.
-
- `set sv_strafejump_hack 1` (integer)
Enables FPS-independent strafe jumping mode for clients using R1Q2
and Q2PRO protocols. Values higher than 1 will force this mode for all
@@ -235,6 +228,10 @@ the whole ban list.
- `listbans`
Enumerates all registered address/mask pairs in the ban list.
+- `kickban <userid>`
+Kick the specified client and add his IP address to the
+ban list (with a default mask of 32).
+
- `addstuffcmd <connect|begin> <command> [...]`
Adds command to be automatically stuffed to every client as they initially
connect or each time they enter new map.
diff --git a/wiki/index.mdwn b/wiki/index.mdwn
index f7dcc2c..60cf245 100644
--- a/wiki/index.mdwn
+++ b/wiki/index.mdwn
@@ -15,7 +15,7 @@ Important news
-----------------
* __2008-Oct-30:__ Q2PRO server versions from [r307 and up][dl] now implement
improved MVD/GTV protocol capable of automatic connection recovery and
- feature special «suspension mode» for additional bandwidth savings in
+ feature special ‘suspension mode’ for additional bandwidth savings in
case there are no players/spectators on a channel.
[dl]: http://skuller.ath.cx/q2pro/nightly/
@@ -45,16 +45,16 @@ Feature highlights
* __Multi View Demo support.__ Server is capable of recording and playing
back demos in special MVD format, capturing views from each player in game.
During playback, spectators themselves choose which view they would like
- to watch. This is completely transparent and supported for _any_ Quake 2
- client.
+ to watch. This is completely transparent to and supported for _any_ Quake 2
+ client connected to a Q2PRO server.
* __Game TeleVision support.__ Server may act as game relay node, allowing
large amount of spectators watch game in real time without putting any
additional load on the game server itself. Furthermore, live game streaming
- is done with all benefits of MVD format. There is no need for «camera man»,
+ is done with all benefits of MVD format. There is no need for ‘camera man’,
unlike other GTV implementations.
-* __Frame rates separation.__ Client provides «true» networking, physics,
+* __Frame rates separation.__ Client provides ‘true’ networking, physics,
rendering and input polling frame rates separation. Unlike other Quake 2
clients, Q2PRO will not waste CPU cycles drawing frames never actually
seen on screen, but will poll for user input instead in order to minimize
@@ -62,10 +62,11 @@ Feature highlights
* __Improved security and stability.__ Developed with security in mind, Q2PRO
carefully handles all untrusted data, including data coming from the network
- as well as locally stored, downloadable files like game media.
+ as well as locally stored files like game media, which could be potentionally
+ downloaded from an untrusted location.
* __Support for multiple platforms.__ Client and server run natively on
- Windows as well as many Unix-like systems, where Q2PRO client uses highly
+ Win32 as well as many UNIX-like systems, where Q2PRO client uses highly
portable SDL library for graphical and sound output.
Navigation
@@ -74,5 +75,5 @@ Navigation
* [[download]]
* [[documentation|doc]]
* [[contact]]
-* [SF.net page](http://sourceforge.net/projects/q2pro/)
+* [project page at SF.net](http://sourceforge.net/projects/q2pro/)