Populate team rosters from a LIVESTATS team token and tag the damage list
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <[email protected]>
This commit is contained in:
+12
-3
@@ -149,16 +149,25 @@ class PlayerTracker:
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_livestats(self, clean_name, score, dealt, taken, ping):
|
||||
"""Update live score/damage/ping from a LIVESTATS console print (clean name)"""
|
||||
def update_livestats(self, clean_name, score, dealt, taken, ping, team=None):
|
||||
"""Update live score/damage/ping from a LIVESTATS console print (clean name).
|
||||
With a team token (extended livedamage format) the team is authoritative —
|
||||
it sorts tracked players and adds unknown ones to the roster, which is
|
||||
what populates teams correctly during warmup."""
|
||||
for player_name, player_data in self.server_info.players.items():
|
||||
if strip_color_codes(player_name) == clean_name:
|
||||
player_data['score'] = str(score)
|
||||
player_data['ping'] = str(ping)
|
||||
player_data['dealt'] = str(dealt)
|
||||
player_data['taken'] = str(taken)
|
||||
if team is not None:
|
||||
self.update_team(player_name, team)
|
||||
return True
|
||||
return False
|
||||
if team is None:
|
||||
return False
|
||||
self.add_player(clean_name, score=str(score), ping=str(ping))
|
||||
self.update_team(clean_name, team)
|
||||
return True
|
||||
|
||||
def remove_player(self, name):
|
||||
"""Remove player from tracking"""
|
||||
|
||||
@@ -18,9 +18,10 @@ import time
|
||||
from collections import deque
|
||||
|
||||
from .constants import (INFO_WINDOW_HEIGHT, INFO_WINDOW_Y, OUTPUT_WINDOW_Y, INPUT_WINDOW_HEIGHT,
|
||||
MIN_ROWS, MIN_COLS, OUTPUT_SCROLLBACK_LINES, TEAM_MODES, MAX_COMMAND_HISTORY)
|
||||
MIN_ROWS, MIN_COLS, OUTPUT_SCROLLBACK_LINES, TEAM_MODES, MAX_COMMAND_HISTORY,
|
||||
TEAM_COLORS)
|
||||
from .cvars import autocomplete, COMMAND_SIGNATURES, get_signature_with_highlight, get_argument_suggestions, COMMAND_ARGUMENTS
|
||||
from .formatter import strip_color_codes
|
||||
from .formatter import get_team_prefix, strip_color_codes
|
||||
|
||||
logger = logging.getLogger('ui')
|
||||
|
||||
@@ -431,9 +432,11 @@ def _draw_server_menu(screen, servers, names, selected):
|
||||
screen.refresh()
|
||||
|
||||
|
||||
def format_damage_summary(server_info):
|
||||
"""One-line damage summary (top 3 by damage dealt) from LIVESTATS counters;
|
||||
None when no damage data exists yet. Dealt/taken are stored as strings."""
|
||||
def format_damage_summary(server_info, player_tracker=None):
|
||||
"""One-line damage summary (top 3 by damage dealt) from LIVESTATS counters,
|
||||
tagged with the tracked team of each player (data-driven, so tags work
|
||||
during warmup too); None when no damage data exists yet. Dealt/taken are
|
||||
stored as strings."""
|
||||
entries = []
|
||||
for player_name, player_data in server_info.players.items():
|
||||
try:
|
||||
@@ -447,8 +450,13 @@ def format_damage_summary(server_info):
|
||||
if not entries:
|
||||
return None
|
||||
entries.sort(key=lambda x: x[1], reverse=True)
|
||||
summary = ' '.join(f"{name} {dealt}/{taken}" for name, dealt, taken in entries[:3])
|
||||
return f"^8^3DMG^7 {summary}\n"
|
||||
parts = []
|
||||
for name, dealt, taken in entries[:3]:
|
||||
prefix = ''
|
||||
if player_tracker is not None:
|
||||
prefix = TEAM_COLORS.get(player_tracker.get_team(name), '')
|
||||
parts.append(f"{prefix}{name} {dealt}/{taken}")
|
||||
return f"^8^3DMG^7 {' '.join(parts)}\n"
|
||||
|
||||
|
||||
class UIManager:
|
||||
@@ -893,7 +901,7 @@ class UIManager:
|
||||
print_colored(self.info_window, line, 0)
|
||||
|
||||
# Damage summary from LIVESTATS counters (top 3 by damage dealt)
|
||||
damage_line = format_damage_summary(server_info)
|
||||
damage_line = format_damage_summary(server_info, game_state.player_tracker)
|
||||
if damage_line:
|
||||
print_colored(self.info_window, damage_line, 0)
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ RENAME_PATTERN = re.compile(r'^(.+?)\s+renamed to\s+(.+?)$')
|
||||
STATUS_HEAD_PATTERN = re.compile(r'^\s*\d+\s+-?\d+\s+(bot|\d+)\s+\S', re.MULTILINE)
|
||||
STATUS_MAP_PATTERN = re.compile(r'^map:\s+\S+\s*$', re.MULTILINE)
|
||||
STEAMID_PATTERN = re.compile(r'\b\d{16,}\b')
|
||||
LIVESTATS_PATTERN = re.compile(r'^LIVESTATS\s+(.+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s*$')
|
||||
LIVESTATS_PATTERN = re.compile(
|
||||
r'^LIVESTATS\s+(.+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+([A-Za-z]+|\d))?\s*$')
|
||||
STATUS_ROW_PATTERN = re.compile(
|
||||
r'^\s*(\d+)\s+(-?\d+)\s+(\d+)\s+(.+?)\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+)(?:\s+(\d{15,}))?\s*$')
|
||||
ROSTER_CHAT_GUARD_PATTERN = re.compile(r'^.{1,40}:\s')
|
||||
@@ -179,7 +180,9 @@ def handle_livestats(message, game_state, ui, verbose=0):
|
||||
Consume every LIVESTATS heartbeat line (engine damage counters emitted
|
||||
every 10s by the livedamage plugin, plus its summary variants). Lines
|
||||
matching the full player shape update live score/damage/ping; names may
|
||||
contain spaces, so the counters anchor from the end. The raw lines
|
||||
contain spaces, so the counters anchor from the end. An optional trailing
|
||||
team token (extended livedamage format) is authoritative and populates
|
||||
the roster with correct teams — including during warmup. The raw lines
|
||||
display only at -v or higher verbosity; they are never treated as chat.
|
||||
"""
|
||||
clean = strip_color_codes(message).strip()
|
||||
@@ -187,8 +190,11 @@ def handle_livestats(message, game_state, ui, verbose=0):
|
||||
return False
|
||||
match = LIVESTATS_PATTERN.match(clean)
|
||||
if match:
|
||||
name, score, dealt, taken, ping = match.groups()
|
||||
game_state.player_tracker.update_livestats(name, int(score), int(dealt), int(taken), int(ping))
|
||||
name, score, dealt, taken, ping, team = match.groups()
|
||||
if team is not None and team.isdigit():
|
||||
team = int(team)
|
||||
game_state.player_tracker.update_livestats(
|
||||
name, int(score), int(dealt), int(taken), int(ping), team)
|
||||
ui.update_server_info(game_state)
|
||||
if verbose > 0:
|
||||
timestamp = time.strftime('%H:%M:%S')
|
||||
|
||||
Reference in New Issue
Block a user