diff --git a/lib/constants.py b/lib/constants.py index 4abec15..28ab9d0 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -18,6 +18,7 @@ POLL_TIMEOUT = 100 # Timing constants QUIT_CONFIRM_TIMEOUT = 3.0 # Seconds to confirm quit (Ctrl-C twice) RESPAWN_DELAY = 3.0 # Seconds before players respawn after death +STATUS_OUTPUT_WINDOW = 3.0 # Seconds a 'status' command echo hides its chunked table output STATS_CONNECTION_DELAY = 0.5 # Initial stats connection delay # UI dimensions diff --git a/main.py b/main.py index 9ce7d1b..5417f71 100644 --- a/main.py +++ b/main.py @@ -15,7 +15,7 @@ import signal import sys import os -from lib.constants import VERSION, DEFAULT_HOST, POLL_TIMEOUT, QUIT_CONFIRM_TIMEOUT, RESPAWN_DELAY, MAX_COMMAND_HISTORY +from lib.constants import VERSION, DEFAULT_HOST, POLL_TIMEOUT, QUIT_CONFIRM_TIMEOUT, RESPAWN_DELAY, MAX_COMMAND_HISTORY, STATUS_OUTPUT_WINDOW from lib.state import GameState from lib.network import RconConnection, StatsConnection from lib.parser import EventParser @@ -134,6 +134,28 @@ def is_command_output(message): return False +def is_status_chunk(message): + """ + Detect one chunk of 'status' command output. The server streams the table + as many small messages (row heads, '0 16384', the steamid, the address), + so per-chunk shape checks are loose; they only apply inside the + suppression window opened by the command echo. + """ + clean = strip_color_codes(message) + stripped = clean.strip() + if not stripped or stripped[:1] in ('{', '['): + return False + if 'num score ping' in clean or '--- -----' in clean: + return True + if stripped.startswith('map:'): + return True + if STATUS_HEAD_PATTERN.search(clean): + return True + if re.match(r'^[\d.:-]+(\s+[\w.:-]+)*\s*$', stripped): + return True + return False + + def handle_stats_connection(message): """ Handle stats connection info extraction @@ -403,6 +425,7 @@ def main_loop(screen, args): stats_port = None stats_password = None stats_check_counter = 0 + status_suppress_until = 0.0 # Timer refresh tracking (update UI once per second) last_ui_update = 0 @@ -487,10 +510,23 @@ def main_loop(screen, args): if parse_player_events(message, game_state, ui): continue - # Command echoes only show at -v or higher verbosity - if is_command_echo(message) and args.verbose == 0: - logger.debug('Suppressed RCON command echo') - continue + # Command echoes only show at -v or higher verbosity; a + # status echo opens a window that hides its chunked output + if is_command_echo(message): + if message.rstrip().endswith(': status'): + status_suppress_until = time.time() + STATUS_OUTPUT_WINDOW + if args.verbose == 0: + logger.debug('Suppressed RCON command echo') + continue + + # Hide status table chunks following a 'status' command + if status_suppress_until: + if time.time() < status_suppress_until: + if is_status_chunk(message): + logger.debug('Suppressed status output chunk') + continue + else: + status_suppress_until = 0.0 if 'Game Initialization' in message: logger.info('Game initialization detected - refreshing server info')