diff --git a/init-db.sql b/init-db.sql index 7b2327a..5bc6239 100644 --- a/init-db.sql +++ b/init-db.sql @@ -32,6 +32,17 @@ CREATE TABLE IF NOT EXISTS scoreboard_state ( UNIQUE(team_id, service_name) ); +-- Team scores table - track total and flag points over time +CREATE TABLE IF NOT EXISTS team_scores ( + id SERIAL PRIMARY KEY, + team_id INTEGER NOT NULL, + team_name VARCHAR(255) NOT NULL, + total_score FLOAT DEFAULT 0, + flag_points FLOAT DEFAULT 0, + round INTEGER NOT NULL, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + -- Attacks tracking table for scoreboard injector CREATE TABLE IF NOT EXISTS attacks ( id SERIAL PRIMARY KEY, @@ -84,6 +95,8 @@ ON CONFLICT (key) DO NOTHING; -- Create indexes for performance CREATE INDEX IF NOT EXISTS idx_scoreboard_state_team_service ON scoreboard_state(team_id, service_name); +CREATE INDEX IF NOT EXISTS idx_team_scores_round ON team_scores(round); +CREATE INDEX IF NOT EXISTS idx_team_scores_team_id ON team_scores(team_id); CREATE INDEX IF NOT EXISTS idx_attacks_timestamp ON attacks(timestamp); CREATE INDEX IF NOT EXISTS idx_attacks_our_attack ON attacks(is_our_attack); CREATE INDEX IF NOT EXISTS idx_attacks_attack_to_us ON attacks(is_attack_to_us); diff --git a/scoreboard_injector/main.py b/scoreboard_injector/main.py index 42edea4..4baa4f0 100644 --- a/scoreboard_injector/main.py +++ b/scoreboard_injector/main.py @@ -189,8 +189,9 @@ async def socketio_listener(): """Listen to ForcAD scoreboard using Socket.IO""" sio = socketio.AsyncClient(logger=False, engineio_logger=False) - # Cache for task names + # Cache for task and team names task_names = {} + team_names = {} @sio.event(namespace='/game_events') async def update_scoreboard(data): @@ -200,11 +201,20 @@ async def socketio_listener(): round_num = event_data.get('round', 0) round_start = event_data.get('round_start', 0) team_tasks = event_data.get('team_tasks', []) + teams_data = event_data.get('teams', []) print(f"📊 Round {round_num} - Processing {len(team_tasks)} team updates") conn = await db_pool.acquire() try: + # Store team scores + for team in teams_data: + team_id = team.get('id') + await conn.execute(""" + INSERT INTO team_scores (team_id, team_name, total_score, flag_points, round, timestamp) + VALUES ($1, $2, $3, $4, $5, NOW()) + """, team_id, team_names.get(team_id, f'Team {team_id}'), + team.get('score', 0), team.get('flag_points', 0), round_num) for team_task in team_tasks: team_id = team_task.get('team_id') task_id = team_task.get('task_id') @@ -294,6 +304,10 @@ async def socketio_listener(): for task in tasks: task_names[task.get('id')] = task.get('name') + # Cache team names + for team in teams: + team_names[team.get('id')] = team.get('name') + team_names_str = ', '.join([f"{t.get('name')} (ID:{t.get('id')})" for t in teams]) task_names_str = ', '.join([t.get('name') for t in tasks]) print(f" Teams: {team_names_str}") @@ -390,25 +404,42 @@ async def get_stats(): @app.get("/attacks", dependencies=[Depends(verify_token)]) async def get_attacks(limit: int = 100, our_attacks: Optional[bool] = None, attacks_to_us: Optional[bool] = None): - """Get recent attacks""" + """Get recent attacks with team names""" conn = await get_db() try: - query = "SELECT * FROM attacks WHERE 1=1" + query = """ + SELECT + a.*, + ts_attacker.team_name as attacker_team_name, + ts_victim.team_name as victim_team_name + FROM attacks a + LEFT JOIN ( + SELECT DISTINCT ON (team_id) team_id, team_name + FROM team_scores + ORDER BY team_id, timestamp DESC + ) ts_attacker ON a.attacker_team_id = ts_attacker.team_id + LEFT JOIN ( + SELECT DISTINCT ON (team_id) team_id, team_name + FROM team_scores + ORDER BY team_id, timestamp DESC + ) ts_victim ON a.victim_team_id = ts_victim.team_id + WHERE 1=1 + """ params = [] param_count = 0 if our_attacks is not None: param_count += 1 - query += f" AND is_our_attack = ${param_count}" + query += f" AND a.is_our_attack = ${param_count}" params.append(our_attacks) if attacks_to_us is not None: param_count += 1 - query += f" AND is_attack_to_us = ${param_count}" + query += f" AND a.is_attack_to_us = ${param_count}" params.append(attacks_to_us) param_count += 1 - query += f" ORDER BY timestamp DESC LIMIT ${param_count}" + query += f" ORDER BY a.timestamp DESC LIMIT ${param_count}" params.append(limit) rows = await conn.fetch(query, *params) diff --git a/web/templates/attacks.html b/web/templates/attacks.html index b0fd324..7ebb565 100644 --- a/web/templates/attacks.html +++ b/web/templates/attacks.html @@ -65,7 +65,7 @@ Attacker Victim Service - Points + Flags Type @@ -126,13 +126,16 @@ typeLabel = 'Against Us'; } + const attackerName = attack.attacker_team_id ? (attack.attacker_team_name || `Team ${attack.attacker_team_id}`) : 'Unknown'; + const victimName = attack.victim_team_id ? (attack.victim_team_name || `Team ${attack.victim_team_id}`) : 'Unknown'; + html += ` ${new Date(attack.timestamp).toLocaleString()} - Team ${attack.attacker_team_id} - Team ${attack.victim_team_id} + ${attackerName} + ${victimName} ${attack.service_name} - ${attack.points ? attack.points.toFixed(2) : '-'} + ${attack.points ? Math.round(attack.points) : '-'} ${typeLabel} `;