From 259c996ebe14cdb52e4a47149ce6c33dbeffa4d3 Mon Sep 17 00:00:00 2001 From: /dev/humancontroller Date: Sat, 15 Apr 2017 00:16:35 +0200 Subject: implement Schachtmeister v2 --- src/game/g_admin.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/game/g_admin.h | 14 ++++ src/game/g_local.h | 3 + src/game/g_main.c | 8 +++ src/game/g_svcmds.c | 28 ++++++++ 5 files changed, 243 insertions(+), 2 deletions(-) diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 99a08e5..05fcd2b 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -72,6 +72,11 @@ g_admin_cmd_t g_admin_cmds[ ] = "" }, + {"sm", G_admin_sm, "schachtmeister", + "Schachtmeister", + "..." + }, + {"ban", G_admin_ban, "ban", "ban a player by IP and GUID with an optional expiration time and reason." " time is specified as numbers followed by units 'w' (weeks), 'd' " @@ -1852,11 +1857,49 @@ void G_admin_namelog_cleanup( ) for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) { + if( g_admin_namelog[ i ]->smj.comment ) + G_Free( g_admin_namelog[ i ]->smj.comment ); G_Free( g_admin_namelog[ i ] ); g_admin_namelog[ i ] = NULL; } } +static void dispatchSchachtmeisterIPAQuery( const char *ipa ) +{ + trap_SendConsoleCommand( EXEC_APPEND, va( "smq ipa \"%s\"\n", ipa ) ); +} + +static void schachtmeisterProcess( g_admin_namelog_t *namelog ) +{ + schachtmeisterJudgement_t *j = &namelog->smj; + + if( !j->ratingTime || level.time - j->ratingTime >= 600000 ) + { + if( j->queryTime ) + return; + + j->queryTime = level.time; + goto dispatch; + } + + if( !j->queryTime || level.time - j->queryTime >= 60000 ) + return; + + if( j->dispatchTime && level.time - j->dispatchTime < 5000 ) + return; + + dispatch: + j->dispatchTime = level.time; + dispatchSchachtmeisterIPAQuery( namelog->ip ); +} + +void G_admin_schachtmeisterFrame( void ) +{ + int i; + for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) + schachtmeisterProcess( g_admin_namelog[ i ] ); +} + void G_admin_namelog_update( gclient_t *client, qboolean disconnect ) { int i, j; @@ -1981,6 +2024,7 @@ void G_admin_namelog_update( gclient_t *client, qboolean disconnect ) Q_strncpyz( namelog->name[ 0 ], client->pers.netname, sizeof( namelog->name[ 0 ] ) ); namelog->slot = ( disconnect ) ? -1 : clientNum; + schachtmeisterProcess( namelog ); g_admin_namelog[ i ] = namelog; } @@ -3022,6 +3066,69 @@ qboolean G_admin_setdevmode( gentity_t *ent, int skiparg ) return qtrue; } +qboolean G_admin_sm( gentity_t *ent, int skiparg ) +{ + const char *s; + char feature[ 16 ]; + + if( G_SayArgc() < 2 + skiparg ) + { + usage: + ADMP( "^3!sm: ^7usage: !sm ipa \n" ); + return qfalse; + } + + s = G_SayConcatArgs( 1 + skiparg ); + if( strchr( s, '\n' ) || strchr( s, '\r' ) ) + { + ADMP( "^3!sm: ^7invalid character\n" ); + return qfalse; + } + + G_SayArgv( 1 + skiparg, feature, sizeof( feature ) ); + + if( !Q_stricmp( feature, "ipa" ) ) + { + char ipa[ 32 ]; + int parts[ 4 ]; + + if( G_SayArgc() > 3 + skiparg ) + { + ADMP( "^3!sm: ^7excessive arguments\n" ); + goto usage; + } + G_SayArgv( 2 + skiparg, ipa, sizeof( ipa ) ); + + // have a well-formed IPv4 address, because Schachtmeister silently drops all invalid requests + + if( sscanf( ipa, "%i.%i.%i.%i", &parts[0], &parts[1], &parts[2], &parts[3] ) != 4 + || parts[0] < 0 || parts[0] > 255 + || parts[1] < 0 || parts[1] > 255 + || parts[2] < 0 || parts[2] > 255 + || parts[3] < 0 || parts[3] > 255 ) + { + ADMP( "^3!sm: ^7invalid IP address\n" ); + return qfalse; + } + + snprintf( ipa, sizeof( ipa ), "%i.%i.%i.%i", parts[0], parts[1], parts[2], parts[3] ); + + if( rand() % 2 /* FIXME cache hit */ ) + { + const char *answer = "interesting"; + ADMP( va( "^3!sm: ^7IP address %s is: %s\n", ipa, answer ) ); + return qtrue; + } + + ADMP( "^3!sm: ^7hmm...\n" ); + trap_SendConsoleCommand( EXEC_APPEND, va( "smq ipa \"%s\"\n", ipa ) ); + } + else + goto usage; + + return qtrue; +} + qboolean G_admin_kick( gentity_t *ent, int skiparg ) { int pids[ MAX_CLIENTS ]; @@ -3309,6 +3416,35 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg ) return qtrue; } +void G_admin_IPA_judgement( const char *ipa, int rating, const char *comment ) +{ + int i; + for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) + { + if( !strcmp( g_admin_namelog[ i ]->ip, ipa ) ) + { + schachtmeisterJudgement_t *j = &g_admin_namelog[ i ]->smj; + + j->ratingTime = level.time; + j->queryTime = 0; + j->dispatchTime = 0; + + j->rating = rating; + + if( j->comment ) + G_Free( j->comment ); + + if( comment ) + { + j->comment = G_Alloc( strlen( comment ) + 1 ); + strcpy( j->comment, comment ); + } + else + j->comment = NULL; + } + } +} + qboolean G_admin_adjustban( gentity_t *ent, int skiparg ) { int bnum; @@ -6753,6 +6889,56 @@ qboolean G_admin_nextmap( gentity_t *ent, int skiparg ) return qtrue; } +const char *displaySchachtmeisterJudgement( const schachtmeisterJudgement_t *j ) +{ + char pc, ps; + static char display[ MAX_STRING_CHARS ]; + + if( j->queryTime ) + { + if( level.time - j->queryTime >= 60000 ) + pc = '0', ps = 'X'; // dead, apparently + else if( level.time - j->queryTime >= 10000 ) + pc = '4', ps = 'z'; // asleep, apparently + else + pc = '5', ps = ','; // wait + } + else + pc = '7', ps = ' '; // stfu, compiler + + if( j->ratingTime ) + { + char rc, rs; + + if( j->rating >= g_schachtmeisterClearThreshold.integer ) + rc = '2', rs = 'o'; + else if( j->rating <= g_schachtmeisterAutobahnThreshold.integer ) + rc = '1', rs = '!'; + else + rc = '3', rs = '?'; + + if( j->queryTime ) + Com_sprintf( display, sizeof( display ), "^%c%c^%c%c ^%c% 4i", rc, rs, pc, ps, rc, j->rating ); + else + Com_sprintf( display, sizeof( display ), "^%c%c % 4i", rc, rs, j->rating ); + + if( j->comment ) + { + int l = strlen( display ); + Com_sprintf( display + l, sizeof( display ) - l, " (%s)", j->comment ); + } + } + else + { + if( j->queryTime ) + Com_sprintf( display, sizeof( display ), " ^%c%c", pc, ps ); + else // shouldn't happen + display[ 0 ] = '\0'; + } + + return display; +} + qboolean G_admin_namelog( gentity_t *ent, int skiparg ) { int i, j; @@ -6793,10 +6979,11 @@ qboolean G_admin_namelog( gentity_t *ent, int skiparg ) guid_stub[ j ] = '\0'; if( g_admin_namelog[ i ]->slot > -1 ) ADMBP( "^3" ); - ADMBP( va( "%-2s (*%s) %15s^7", + ADMBP( va( "%-2s (*%s) %15s %s^7", (g_admin_namelog[ i ]->slot > -1 ) ? va( "%d", g_admin_namelog[ i ]->slot ) : "-", - guid_stub, g_admin_namelog[ i ]->ip ) ); + guid_stub, g_admin_namelog[ i ]->ip, + displaySchachtmeisterJudgement( &g_admin_namelog[ i ]->smj ) ) ); for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES && g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ ) { @@ -10027,3 +10214,4 @@ qboolean G_admin_give(gentity_t *ent, int skiparg) return qtrue; } + diff --git a/src/game/g_admin.h b/src/game/g_admin.h index 93458b6..b6ed952 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -168,6 +168,15 @@ typedef struct g_admin_command } g_admin_command_t; +typedef struct +{ + int ratingTime; + int queryTime; + int dispatchTime; + int rating; + char *comment; +} schachtmeisterJudgement_t; + typedef struct g_admin_namelog { char name[ MAX_ADMIN_NAMELOG_NAMES ][MAX_NAME_LENGTH ]; @@ -181,6 +190,7 @@ typedef struct g_admin_namelog int denyHumanWeapons; int denyAlienClasses; int specExpires; + schachtmeisterJudgement_t smj; } g_admin_namelog_t; @@ -255,6 +265,7 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg ); qboolean G_admin_permission( gentity_t *ent, const char *flag ); qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len ); void G_admin_namelog_update( gclient_t *ent, qboolean disconnect ); +void G_admin_IPA_judgement( const char *ipa, int rating, const char *comment ); void G_admin_maplog_result( char *flag ); int G_admin_level( gentity_t *ent ); void G_admin_set_adminname( gentity_t *ent ); @@ -269,6 +280,7 @@ void G_admin_chat_update( gentity_t *ent, int chan ); qboolean G_admin_time( gentity_t *ent, int skiparg ); qboolean G_admin_setlevel( gentity_t *ent, int skiparg ); qboolean G_admin_setdevmode( gentity_t *ent, int skiparg ); +qboolean G_admin_sm( gentity_t *ent, int skiparg ); qboolean G_admin_kick( gentity_t *ent, int skiparg ); qboolean G_admin_adjustban( gentity_t *ent, int skiparg ); qboolean G_admin_subnetban( gentity_t *ent, int skiparg ); @@ -361,4 +373,6 @@ void G_admin_namelog_cleanup( void ); void G_admin_report_check( int clientNum ); +void G_admin_schachtmeisterFrame( void ); + #endif /* ifndef _G_ADMIN_H */ diff --git a/src/game/g_local.h b/src/game/g_local.h index 6e077bd..550803a 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -1540,6 +1540,9 @@ extern vmCvar_t g_maxUnregReports; extern vmCvar_t g_reportWelcomeComment; +extern vmCvar_t g_schachtmeisterClearThreshold; +extern vmCvar_t g_schachtmeisterAutobahnThreshold; + extern vmCvar_t g_scrimMode; extern vmCvar_t g_revertCooldownTime; diff --git a/src/game/g_main.c b/src/game/g_main.c index 5cfc383..5fe4307 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -280,6 +280,9 @@ vmCvar_t g_maxUnregReports; vmCvar_t g_reportWelcomeComment; +vmCvar_t g_schachtmeisterClearThreshold; +vmCvar_t g_schachtmeisterAutobahnThreshold; + vmCvar_t g_scrimMode; vmCvar_t g_revertCooldownTime; @@ -545,6 +548,9 @@ static cvarTable_t gameCvarTable[ ] = { &g_scrimMode, "g_scrimMode", "0", CVAR_ARCHIVE, 0, qfalse }, + { &g_schachtmeisterClearThreshold, "g_schachtmeisterClearThreshold", "0", CVAR_ARCHIVE, 0, qfalse }, + { &g_schachtmeisterAutobahnThreshold, "g_schachtmeisterAutobahnThreshold", "-50", CVAR_ARCHIVE, 0, qfalse }, + { &g_revertCooldownTime, "g_revertCooldownTime", "30", CVAR_ARCHIVE, 0, qfalse } }; @@ -3488,6 +3494,8 @@ void G_RunFrame( int levelTime ) CheckTeamVote( PTE_HUMANS ); CheckTeamVote( PTE_ALIENS ); + G_admin_schachtmeisterFrame(); + // for tracking changes CheckCvars( ); diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index 8b7b575..c4ce182 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -704,6 +704,34 @@ qboolean ConsoleCommand( void ) return qtrue; } + if( !Q_stricmp( cmd, "smr" ) ) + { + if( trap_Argc() >= 2 ) + { + char arg[ 32 ]; + trap_Argv( 1, arg, sizeof( arg ) ); + + if( !Q_stricmp( arg, "ipa" ) && trap_Argc() >= 4 ) + { + int rating; + const char *comment = NULL; + + trap_Argv( 3, arg, sizeof( arg ) ); + rating = atoi( arg ); + if( trap_Argc() >= 5 ) + comment = ConcatArgs( 4 ); + trap_Argv( 2, arg, sizeof( arg ) ); + + G_admin_IPA_judgement( arg, rating, comment ); + + return qtrue; + } + } + + G_Printf( "unrecognized Schachtmeister response: %s\n", ConcatArgs( 1 ) ); + return qtrue; + } + // see if this is a a admin command if( G_admin_cmd_check( NULL, qfalse ) ) return qtrue; -- cgit