replace items record with full end-of-game stats record
All checks were successful
record-daemon / Build, check and test (push) Successful in 2m5s

- record-daemon: remove items parsing module
- tauri-app: add items parsing from recorded end-of-game stats
This commit is contained in:
2026-03-26 18:47:19 +01:00
parent 506fc9827b
commit 0871703b11
8 changed files with 144 additions and 314 deletions

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { invoke } from "@tauri-apps/api/core";
import type { GameHistoryItem, GameResult, TimestampedEvent, ItemInfo } from "../types/timeline";
import type { GameHistoryItem, TimestampedEvent, ItemInfo, RawEndGameStats, EndGamePlayer } from "../types/timeline";
import {
getGameResult,
formatDuration,
@@ -49,21 +49,57 @@ function closeDetail() {
selectedGame.value = null;
}
// Helper to get items array for display (6 slots + trinket)
function getItemsArray(game: GameHistoryItem): (ItemInfo | null)[] {
const result: (ItemInfo | null)[] = [null, null, null, null, null, null, null];
if (game.final_items) {
// Fill main items (slots 0-5)
for (const item of game.final_items.items) {
if (item.slot >= 0 && item.slot <= 5) {
result[item.slot] = item;
// Helper to find local player from raw end game stats
function getLocalPlayer(stats: RawEndGameStats | null): EndGamePlayer | null {
if (!stats) return null;
// Try local_player field first
if (stats.local_player) {
return stats.local_player;
}
// Try teams
if (stats.teams) {
for (const team of stats.teams) {
if (team.players) {
for (const player of team.players) {
if (player.is_local_player) {
return player;
}
}
}
}
// Fill trinket (slot 6)
if (game.final_items.trinket) {
result[6] = game.final_items.trinket;
}
// Try legacy players array
if (stats.players && stats.players.length > 0) {
return stats.players[0];
}
return null;
}
// Helper to get items array for display (6 slots + trinket)
// Items are now stored as raw item IDs in raw_end_game_stats
function getItemsArray(game: GameHistoryItem): (ItemInfo | null)[] {
const result: (ItemInfo | null)[] = [null, null, null, null, null, null, null];
const localPlayer = getLocalPlayer(game.raw_end_game_stats);
if (localPlayer && localPlayer.items) {
// Items are stored as an array of item IDs (up to 7 items: 6 main + 1 trinket)
for (let i = 0; i < Math.min(localPlayer.items.length, 7); i++) {
const itemId = localPlayer.items[i];
if (itemId && itemId > 0) {
// Slot 6 is trinket, slots 0-5 are main items
result[i] = {
itemId: itemId,
name: null,
slot: i
};
}
}
}
return result;
}
@@ -217,9 +253,9 @@ onMounted(() => {
</div>
<div class="item-slot trinket">
<img
v-if="getItemsArray(game)[6] && getItemsArray(game)[6].itemId"
:src="getItemImageUrl(getItemsArray(game)[6].itemId)"
:alt="getItemsArray(game)[6].name || 'Trinket'"
v-if="getItemsArray(game)[6]?.itemId"
:src="getItemImageUrl(getItemsArray(game)[6]!.itemId)"
:alt="getItemsArray(game)[6]?.name || 'Trinket'"
class="item-image"
/>
<div v-else class="item-empty"></div>

View File

@@ -169,14 +169,83 @@ export interface Timeline {
runes: RunePage | null;
/** Summoner spells. */
summoner_spells: SummonerSpells | null;
/** Final item build at game end. */
final_items: ItemBuild | null;
/** Raw end-of-game stats JSON from the API. */
raw_end_game_stats: RawEndGameStats | null;
// All players in the game (puuid to summoner name mapping)
/** All players in the game. */
all_players: PlayerIdentityInfo[];
}
/**
* Raw end-of-game stats from the League Client API.
* This is the full response from the end-of-game stats endpoint.
*/
export interface RawEndGameStats {
/** Game ID. */
game_id?: number;
/** Game length in seconds. */
game_length?: number;
/** Match ID. */
match_id?: number;
/** Game result. */
game_result?: string;
/** Local player data. */
local_player?: EndGamePlayer;
/** Teams data. */
teams?: EndGameTeam[];
/** Players (legacy format). */
players?: EndGamePlayer[];
}
/**
* Player in end-of-game stats.
*/
export interface EndGamePlayer {
/** Whether this is the local player. */
is_local_player?: boolean;
/** Player stats. */
stats?: PlayerStats;
/** Items (array of item IDs). */
items?: number[];
}
/**
* Team in end-of-game stats.
*/
export interface EndGameTeam {
/** Whether this is the player's team. */
is_player_team?: boolean;
/** Whether this is the winning team. */
is_winning_team?: boolean;
/** Players on the team. */
players?: EndGamePlayer[];
}
/**
* Player stats in end-of-game.
*/
export interface PlayerStats {
/** Kills. */
CHAMPIONS_KILLED?: number;
/** Deaths. */
NUM_DEATHS?: number;
/** Assists. */
ASSISTS?: number;
/** Minions killed (CS). */
MINIONS_KILLED?: number;
/** Gold earned. */
GOLD_EARNED?: number;
/** Total damage dealt to champions. */
TOTAL_DAMAGE_DEALT_TO_CHAMPIONS?: number;
/** Total damage taken. */
TOTAL_DAMAGE_TAKEN?: number;
/** Vision score. */
VISION_SCORE?: number;
/** Win status (1 = win). */
WIN?: number;
}
/**
* Game history item for display in the UI.
* Alias for Timeline since the backend returns full timeline data.