diff --git a/main.py b/main.py index bb78f6c..794075a 100644 --- a/main.py +++ b/main.py @@ -34,6 +34,9 @@ DISCONNECT_PATTERN = re.compile(r'^(.+?)\s+disconnected') KICK_PATTERN = re.compile(r'^(.+?)\s+was kicked') INACTIVITY_PATTERN = re.compile(r'^(.+?)\s+Dropped due to inactivity') RENAME_PATTERN = re.compile(r'^(.+?)\s+renamed to\s+(.+?)$') +STATUS_ROW_PATTERN = re.compile(r'^\s*\d+\s+\S.*\s\d{15,}\s*$', re.MULTILINE) +STATUS_SEP_PATTERN = re.compile(r'^--- -----', re.MULTILINE) +STATUS_MAP_PATTERN = re.compile(r'^map:\s+\S+\s*$', re.MULTILINE) # Configure logging logger = logging.getLogger('main') @@ -87,13 +90,6 @@ def parse_cvar_response(message, game_state, ui): Parse server cvar responses and update state Returns True if message should be suppressed from display """ - # Suppress command echo lines - if message.startswith('zmq RCON command') and 'from' in message: - suppress_cmds = ['status', 'roundlimit', 'qlx_serverBrandName', 'g_factoryTitle', - 'mapname', 'timelimit', 'fraglimit', 'capturelimit', 'sv_maxclients'] - if any(f': {cmd}' in message for cmd in suppress_cmds): - return True - # Parse cvar responses (format: "cvar_name" is:"value" default:...) cvar_match = CVAR_RESPONSE_PATTERN.search(message) if cvar_match: @@ -107,6 +103,27 @@ def parse_cvar_response(message, game_state, ui): return False +def is_own_command_echo(message, identity): + """True for echo lines of commands this client sent (the server echoes them to every RCON client)""" + return message.startswith(f'zmq RCON command from {identity}:') + + +def is_command_output(message): + """ + Detect console output produced by RCON commands: cvar dumps and status + tables. These are hidden; the 'zmq RCON command' echo lines still show + which client ran what. + """ + if CVAR_RESPONSE_PATTERN.search(message): + return True + if 'num score ping' in message: + return True + if (STATUS_ROW_PATTERN.search(message) or STATUS_SEP_PATTERN.search(message) + or STATUS_MAP_PATTERN.search(message)): + return True + return False + + def handle_stats_connection(message): """ Handle stats connection info extraction @@ -458,6 +475,10 @@ def main_loop(screen, args): if parse_player_events(message, game_state, ui): continue + # Hide echoes of our own commands; other clients' echoes stay visible + if is_own_command_echo(message, rcon.identity): + continue + if 'Game Initialization' in message: logger.info('Game initialization detected - refreshing server info') @@ -525,6 +546,11 @@ def main_loop(screen, args): ui.print_message(f"^1[^7{timestamp}^1] Error: Stats connection failed: {e}^7\n") logger.error(f'Stats connection failed: {e}') + # Hide output of RCON commands (cvar dumps, status tables) + if is_command_output(message): + logger.debug('Suppressed RCON command output') + continue + # Hide the cvarlist/cmdlist output while learning names from it. # Runs after the cvar handling above so the stats credentials and # server info responses are never swallowed.