diff --git a/record-daemon/src/lqp/api_types.rs b/record-daemon/src/lqp/api_types.rs index 63e00ed..b19dcac 100644 --- a/record-daemon/src/lqp/api_types.rs +++ b/record-daemon/src/lqp/api_types.rs @@ -209,151 +209,6 @@ pub struct ChampionSelectPlayer { pub skin_id: Option, } -// ============================================================================= -// Rune Pages API Responses -// ============================================================================= - -/// Response from `/lol-perks/v1/currentpage` -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RunePageResponse { - /// Rune page ID. - #[serde(default)] - pub id: Option, - - /// Rune page name. - #[serde(default)] - pub name: Option, - - /// Whether this is the current page. - #[serde(default)] - pub current: Option, - - /// Primary style ID. - #[serde(default)] - pub primary_style_id: Option, - - /// Secondary style ID. - #[serde(default)] - pub sub_style_id: Option, - - /// Selected perk IDs. - #[serde(default)] - pub selected_perk_ids: Option>, -} - -// ============================================================================= -// End of Game Stats API Responses -// ============================================================================= - -/// Response from `/lol-end-of-game/v1/eog-stats-block` -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct EndOfGameStatsResponse { - /// Game ID. - #[serde(default)] - pub game_id: Option, - - /// Game length in seconds. - #[serde(default)] - pub game_length: Option, - - /// Match ID. - #[serde(default)] - pub match_id: Option, - - /// Game result. - #[serde(default)] - pub game_result: Option, - - /// Local player data. - #[serde(default)] - pub local_player: Option, - - /// Teams data. - #[serde(default)] - pub teams: Option>, - - /// Players (legacy format). - #[serde(default)] - pub players: Option>, -} - -/// Player in end-of-game stats. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct EndOfGamePlayer { - /// Whether this is the local player. - #[serde(default)] - pub is_local_player: Option, - - /// Player stats. - #[serde(default)] - pub stats: Option, - - /// Items. - #[serde(default)] - pub items: Option>, -} - -/// Team in end-of-game stats. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct EndOfGameTeam { - /// Whether this is the player's team. - #[serde(default)] - pub is_player_team: Option, - - /// Whether this is the winning team. - #[serde(default)] - pub is_winning_team: Option, - - /// Players on the team. - #[serde(default)] - pub players: Option>, -} - -/// Player stats in end-of-game. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "UPPERCASE")] -pub struct PlayerStats { - /// Kills. - #[serde(default)] - pub champions_killed: Option, - - /// Deaths. - #[serde(default)] - pub num_deaths: Option, - - /// Assists. - #[serde(default)] - pub assists: Option, - - /// Minions killed (CS). - #[serde(default)] - pub minions_killed: Option, - - /// Gold earned. - #[serde(default)] - pub gold_earned: Option, - - /// Total damage dealt to champions. - #[serde(default)] - pub total_damage_dealt_to_champions: Option, - - /// Total damage taken. - #[serde(default)] - pub total_damage_taken: Option, - - /// Vision score. - #[serde(default)] - pub vision_score: Option, - - /// Win status (1 = win). - #[serde(default)] - pub win: Option, -} - // ============================================================================= // Live Client Data API Responses // ============================================================================= @@ -472,59 +327,6 @@ pub struct LiveClientItem { // Helper implementations // ============================================================================= -impl EndOfGameStatsResponse { - /// Get the local player from the response. - pub fn get_local_player(&self) -> Option<&EndOfGamePlayer> { - // First check local_player field - if let Some(ref player) = self.local_player { - return Some(player); - } - - // Then check teams - if let Some(ref teams) = self.teams { - for team in teams { - if let Some(ref players) = team.players { - for player in players { - if player.is_local_player == Some(true) { - return Some(player); - } - } - } - } - } - - // Finally check legacy players array - if let Some(ref players) = self.players { - return players.first(); - } - - None - } - - /// Check if the local player won. - pub fn is_victory(&self) -> bool { - // Check local player stats - if let Some(player) = self.get_local_player() { - if let Some(ref stats) = player.stats { - if stats.win == Some(1) { - return true; - } - } - } - - // Check teams - if let Some(ref teams) = self.teams { - for team in teams { - if team.is_player_team == Some(true) && team.is_winning_team == Some(true) { - return true; - } - } - } - - false - } -} - impl ChampionSelectResponse { /// Get the local player's champion selection. pub fn get_local_player_selection(&self) -> Option<&ChampionSelectPlayer> { @@ -552,80 +354,6 @@ impl ChampionSelectResponse { } } -// ============================================================================= -// Aggregated Data Containers -// ============================================================================= - -/// Container for pre-game data collected from multiple API calls. -/// Stores raw API responses directly for maximum flexibility. -#[derive(Debug, Clone, Default)] -pub struct PreGameData { - /// Session data (map, game mode, queue info). - pub session: Option, - /// Summoner data (puuid, name). - pub summoner: Option, - /// Champion select data (champion, skin, team). - pub champion_select: Option, - /// Rune page data. - pub rune_page: Option, -} - -impl PreGameData { - /// Get the summoner name from any available source. - pub fn summoner_name(&self) -> Option<&str> { - self.summoner - .as_ref() - .and_then(|s| s.display_name.as_deref()) - .or_else(|| self.summoner.as_ref().and_then(|s| s.name.as_deref())) - } - - /// Get the PUUID. - pub fn puuid(&self) -> Option<&str> { - self.summoner.as_ref()?.puuid.as_deref() - } - - /// Get the champion ID from champion select. - pub fn champion_id(&self) -> Option { - let cs = self.champion_select.as_ref()?; - let player = cs.get_local_player_selection()?; - player.champion_id - } - - /// Get the team ID from champion select. - pub fn team(&self) -> Option { - let cs = self.champion_select.as_ref()?; - let player = cs.get_local_player_selection()?; - player.team - } - - /// Get the skin ID from champion select. - pub fn skin_id(&self) -> Option { - let cs = self.champion_select.as_ref()?; - let player = cs.get_local_player_selection()?; - player.skin_id - } - - /// Get the map name from session. - pub fn map_name(&self) -> Option<&str> { - self.session.as_ref()?.map.as_deref() - } - - /// Get the game mode from session. - pub fn game_mode(&self) -> Option<&str> { - self.session.as_ref()?.game_mode.as_deref() - } - - /// Get the queue ID from session. - pub fn queue_id(&self) -> Option { - self.session.as_ref()?.queue_id - } - - /// Get the rune page name. - pub fn rune_page_name(&self) -> Option<&str> { - self.rune_page.as_ref()?.name.as_deref() - } -} - #[cfg(test)] mod tests { use super::*; @@ -638,13 +366,4 @@ mod tests { assert_eq!(summoner.puuid, Some("abc-123".to_string())); assert_eq!(summoner.display_name, Some("TestPlayer".to_string())); } - - #[test] - fn test_player_stats_deserialization() { - let json = r#"{"CHAMPIONS_KILLED": 10, "NUM_DEATHS": 3, "ASSISTS": 15}"#; - let stats: PlayerStats = serde_json::from_str(json).unwrap(); - assert_eq!(stats.champions_killed, Some(10)); - assert_eq!(stats.num_deaths, Some(3)); - assert_eq!(stats.assists, Some(15)); - } } diff --git a/record-daemon/src/lqp/client.rs b/record-daemon/src/lqp/client.rs index 83f7521..5454eb9 100644 --- a/record-daemon/src/lqp/client.rs +++ b/record-daemon/src/lqp/client.rs @@ -11,8 +11,8 @@ use tokio_tungstenite::{connect_async_tls_with_config, tungstenite::protocol::Me use tracing::{debug, error, info, trace, warn}; use super::api_types::{ - ActivePlayerResponse, ChampionSelectResponse, EndOfGameStatsResponse, GameflowSessionResponse, - PlayerListResponse, PreGameData, RunePageResponse, SummonerResponse, + ActivePlayerResponse, ChampionSelectResponse, GameflowSessionResponse, PlayerListResponse, + SummonerResponse, }; use super::auth::LockfileCredentials; use super::endpoints; @@ -394,11 +394,6 @@ impl LqpClient { self.request("GET", endpoints::CHAMPION_SELECT).await } - /// Get end-of-game stats (typed). - pub async fn get_game_stats_typed(&self) -> Result { - self.request_typed("GET", endpoints::GAME_STATS).await - } - /// Get end-of-game stats (raw JSON for backward compatibility). pub async fn get_game_stats(&self) -> Result { self.request("GET", endpoints::GAME_STATS).await @@ -409,11 +404,6 @@ impl LqpClient { self.request("GET", endpoints::CHAMPION_SUMMARY).await } - /// Get current rune page (typed). - pub async fn get_rune_page_typed(&self) -> Result { - self.request_typed("GET", endpoints::RUNE_PAGES).await - } - /// Get current rune page (raw JSON for backward compatibility). pub async fn get_rune_page(&self) -> Result { self.request("GET", endpoints::RUNE_PAGES).await @@ -497,49 +487,6 @@ impl LqpClient { pub async fn fetch_raw_end_game_stats(&self) -> Result { self.request("GET", endpoints::GAME_STATS).await } - - /// Fetch pre-game data (stores raw API responses directly). - pub async fn fetch_pregame_data(&self) -> Result { - let mut data = PreGameData::default(); - - // Fetch all API responses in parallel where possible - let (session, summoner, champ_select, rune_page) = tokio::join!( - self.get_session_typed(), - self.get_summoner_typed(), - self.get_champion_select_typed(), - self.get_rune_page_typed() - ); - - // Store session data - if let Ok(session) = session { - data.session = Some(session); - } - - // Store summoner data and update state - if let Ok(summoner) = summoner { - if let Some(ref puuid) = summoner.puuid { - self.state.write().await.local_puuid = Some(puuid.clone()); - } - data.summoner = Some(summoner); - } - - // Store champion select data - if let Ok(champ_select) = champ_select { - data.champion_select = Some(champ_select); - } - - // Store rune page data - if let Ok(rune_page) = rune_page { - data.rune_page = Some(rune_page); - } - - Ok(data) - } - - /// Fetch end-of-game stats (returns raw API response). - pub async fn fetch_game_end_stats(&self) -> Result { - self.get_game_stats_typed().await - } } impl Default for LqpClient { diff --git a/record-daemon/src/lqp/mod.rs b/record-daemon/src/lqp/mod.rs index d89bbd0..247bd46 100644 --- a/record-daemon/src/lqp/mod.rs +++ b/record-daemon/src/lqp/mod.rs @@ -13,9 +13,8 @@ mod tls; mod websocket; pub use api_types::{ - ActivePlayerResponse, ChampionSelectPlayer, ChampionSelectResponse, EndOfGamePlayer, - EndOfGameStatsResponse, EndOfGameTeam, GameData, GameflowSessionResponse, LiveClientItem, - LiveClientPlayer, PlayerListResponse, PlayerStats, PreGameData, QueueData, RunePageResponse, + ActivePlayerResponse, ChampionSelectPlayer, ChampionSelectResponse, GameData, + GameflowSessionResponse, LiveClientItem, LiveClientPlayer, PlayerListResponse, QueueData, SummonerResponse, SummonerSpellsData, TeamPlayer, Timers, }; pub use auth::{LockfileCredentials, LockfileWatcher}; diff --git a/record-daemon/src/main.rs b/record-daemon/src/main.rs index c547fed..3ee3b88 100644 --- a/record-daemon/src/main.rs +++ b/record-daemon/src/main.rs @@ -56,8 +56,6 @@ struct Daemon { event_mapper: Arc>, /// Current recording ID (if recording). current_recording_id: Arc>>, - /// Pre-game data (collected before game starts). - pregame_data: Arc>>, /// IPC server. ipc_server: Option, /// Shutdown signal. @@ -77,7 +75,6 @@ impl Daemon { timeline_store: Arc::new(RwLock::new(TimelineStore::new())), event_mapper: Arc::new(RwLock::new(EventMapper::new())), current_recording_id: Arc::new(RwLock::new(None)), - pregame_data: Arc::new(RwLock::new(None)), ipc_server: None, shutdown_tx, } @@ -232,78 +229,19 @@ impl Daemon { // Handle pre-game data collection match &event { GameEvent::PhaseChange(info) if info.phase == "ChampSelect" => { - info!("[EVENT_HANDLER] Champion select started, fetching pre-game data"); - match self.lqp_client.fetch_pregame_data().await { - Ok(data) => { - info!("[EVENT_HANDLER] Pre-game data fetched: {:?}", data); - *self.pregame_data.write() = Some(data); - } - Err(e) => { - warn!("[EVENT_HANDLER] Failed to fetch pre-game data: {}", e); - } - } + info!("[EVENT_HANDLER] Champion select started"); } GameEvent::ChampionPick(pick) if pick.is_local_player => { info!( "[EVENT_HANDLER] Local player picked champion: {}", pick.champion_name ); - // Champion pick info is now stored in champion_select response - // No need to manually update - refetch if needed } GameEvent::GameStart(info) => { info!( "[EVENT_HANDLER] Game started with metadata: queue={:?}, mode={:?}, map={:?}", info.queue_type, info.game_mode, info.map_name ); - - // Update pre-game data with game start info if needed - let mut pregame = self.pregame_data.write(); - - // Extract player-specific data from session using puuid - let (_champion_id, _team, summoner_name) = if let Some(ref session) = info.session { - // Get puuid from pregame data (fetched earlier) - let puuid = pregame.as_ref().and_then(|d| d.puuid()); - - if let Some(puuid) = puuid { - // Use the puuid to find the correct player's data - let champ_id = session.get_champion_id(puuid); - let team_id = session.get_team(puuid); - let summoner = session.get_summoner_name(puuid).map(|s| s.to_string()); - - info!("[EVENT_HANDLER] Found player data via puuid: champion_id={:?}, team={:?}, summoner={:?}", - champ_id, team_id, summoner); - - (champ_id, team_id, summoner) - } else { - // No puuid available, can't determine player - warn!("[EVENT_HANDLER] No puuid available, cannot determine player-specific data"); - (None, None, None) - } - } else { - (None, None, None) - }; - - // If we don't have pre-game data, create minimal from game start info - if pregame.is_none() { - use record_daemon::lqp::{GameflowSessionResponse, PreGameData}; - *pregame = Some(PreGameData { - session: Some(GameflowSessionResponse { - map: info.map_name.clone(), - game_mode: info.game_mode.clone(), - queue_id: info.queue_id.map(|id| id as u64), - ..Default::default() - }), - summoner: summoner_name.map(|name| { - use record_daemon::lqp::SummonerResponse; - SummonerResponse { - display_name: Some(name), - ..Default::default() - } - }), - ..Default::default() - }); - } } _ => {} } @@ -434,9 +372,6 @@ impl Daemon { // Don't propagate error - keep daemon running } - - // Clear pre-game data - *self.pregame_data.write() = None; } _ => {} }