Learn cvar and command names from the server for autocomplete
Send cvarlist and cmdlist on connect and merge the answer into the autocomplete candidates. Number the server menu from 0, keep suggesting sibling commands while the command name is typed, mask the password in the startup line, ignore venv/, fix README claims.
This commit is contained in:
@@ -22,6 +22,7 @@ from lib.parser import EventParser
|
||||
from lib.formatter import format_message, format_chat_message, format_powerup_message, strip_color_codes
|
||||
from lib.ui import UIManager, select_server
|
||||
from lib.settings import ConfigLoader
|
||||
from lib.namelist import NameCapture
|
||||
|
||||
# Pre-compiled regex patterns
|
||||
CVAR_RESPONSE_PATTERN = re.compile(r'"([^"]+)"\s+is:"([^"]*)"')
|
||||
@@ -131,7 +132,7 @@ def handle_stats_connection(message):
|
||||
password_str = match.group(2)
|
||||
password_str = strip_color_codes(password_str)
|
||||
stats_password = password_str.strip()
|
||||
logger.info(f'Got stats password: {stats_password}')
|
||||
logger.info('Got stats password')
|
||||
|
||||
return stats_port, stats_password
|
||||
|
||||
@@ -340,15 +341,17 @@ def main_loop(screen, args):
|
||||
|
||||
# Initialize components
|
||||
game_state = GameState()
|
||||
name_capture = NameCapture() # cvar/command names learned from the server for autocomplete
|
||||
ui = UIManager(screen, args.title, args.max_history,
|
||||
player_names_provider=lambda: game_state.player_tracker.get_player_names())
|
||||
player_names_provider=lambda: game_state.player_tracker.get_player_names(),
|
||||
learned_names_provider=lambda: name_capture.names)
|
||||
|
||||
# Setup logging to output window
|
||||
log_handler = ui.setup_logging()
|
||||
logger.addHandler(log_handler)
|
||||
|
||||
# Attach UI log handler to lib module loggers
|
||||
for lib_name in ('network', 'parser', 'state'):
|
||||
for lib_name in ('network', 'parser', 'state', 'namelist'):
|
||||
lib_logger = logging.getLogger(lib_name)
|
||||
if log_handler not in lib_logger.handlers:
|
||||
lib_logger.addHandler(log_handler)
|
||||
@@ -359,7 +362,8 @@ def main_loop(screen, args):
|
||||
ui.print_message(f"zmq python bindings {zmq.__version__}, libzmq version {zmq.zmq_version()}\n")
|
||||
|
||||
# Initialize network connections
|
||||
ui.print_message(f"Connecting with host={args.host} password={args.password}\n")
|
||||
password_display = '***' if args.password else '(none)'
|
||||
ui.print_message(f"Connecting with host={args.host} password={password_display}\n")
|
||||
rcon = RconConnection(args.host, args.password, args.identity)
|
||||
rcon.connect()
|
||||
|
||||
@@ -408,6 +412,7 @@ def main_loop(screen, args):
|
||||
ui.print_message("Requesting connection info...\n")
|
||||
rcon.send_command(b'zmq_stats_password')
|
||||
rcon.send_command(b'net_port')
|
||||
name_capture.request(rcon)
|
||||
elif monitor_event and monitor_event[0] == zmq.EVENT_DISCONNECTED:
|
||||
timestamp = time.strftime('%H:%M:%S')
|
||||
ui.print_message(f"^3[^7{timestamp}^3] ^8^1Disconnected from server - waiting for reconnect...^0^7\n")
|
||||
@@ -516,6 +521,12 @@ 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 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.
|
||||
if name_capture.handle(message):
|
||||
continue
|
||||
|
||||
# Try to parse as game event
|
||||
parsed_event = event_parser.parse_event(message)
|
||||
if parsed_event:
|
||||
|
||||
Reference in New Issue
Block a user