diff --git a/Cargo.lock b/Cargo.lock index 4e2e84a..c3b0abd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,7 +224,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "itoa", "matchit", @@ -663,7 +663,7 @@ dependencies = [ [[package]] name = "csdemo" version = "0.1.0" -source = "git+https://github.com/Lol3rrr/csdemo.git#7dfa4fa57ac25e17c3abe5ad7d7621e003786eca" +source = "git+https://github.com/Lol3rrr/csdemo.git#195d2fbc15e7cf3795995519b696239233f5f9b8" dependencies = [ "bitter", "phf", @@ -1328,9 +1328,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -1352,9 +1352,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1378,7 +1378,7 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "rustls", "rustls-pki-types", @@ -1395,7 +1395,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.31", "native-tls", "tokio", "tokio-native-tls", @@ -1412,7 +1412,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", @@ -2459,18 +2459,18 @@ dependencies = [ [[package]] name = "profiling" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", "syn", @@ -2798,7 +2798,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-tls", "ipnet", "js-sys", @@ -2838,7 +2838,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-rustls", "hyper-util", "ipnet", @@ -2970,9 +2970,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -2987,9 +2987,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" diff --git a/analysis/src/endofgame.rs b/analysis/src/endofgame.rs index fb5f70f..3088ff6 100644 --- a/analysis/src/endofgame.rs +++ b/analysis/src/endofgame.rs @@ -1,16 +1,14 @@ -use std::collections::HashMap; - #[derive(Debug, PartialEq)] pub struct EndOfGame { pub map: String, pub players: Vec<(PlayerInfo, PlayerStats)>, - pub teams: HashMap, + pub teams: std::collections::HashMap, } #[derive(Debug, PartialEq)] pub struct TeamInfo { - pub name: String, - pub score: usize, + pub end_score: usize, + pub start_side: String, } #[derive(Debug, PartialEq)] @@ -44,6 +42,7 @@ pub fn parse(buf: &[u8]) -> Result { let header = &output.header; let mut player_stats = std::collections::HashMap::<_, PlayerStats>::new(); + let mut pawn_to_player = std::collections::HashMap::::new(); let mut track = false; let mut player_life = std::collections::HashMap::<_, u8>::new(); @@ -59,7 +58,13 @@ pub fn parse(buf: &[u8]) -> Result { track = true; } csdemo::game_event::GameEvent::PlayerSpawn(pspawn) => { - player_life.insert(pspawn.userid.unwrap(), 100); + let userid = pspawn.userid.unwrap(); + + player_life.insert(userid.clone(), 100); + + if let Some(pawn) = pspawn.userid_pawn.as_ref().map(|p| match p { csdemo::RawValue::I32(v) => Some(csdemo::structured::pawnid::PawnID::from(*v)), _ => None }).flatten() { + pawn_to_player.insert(pawn, userid); + } } csdemo::game_event::GameEvent::WinPanelMatch(_) => { track = false; @@ -85,55 +90,42 @@ pub fn parse(buf: &[u8]) -> Result { }; } - let mut teams = HashMap::new(); - let mut entity_to_team = HashMap::new(); - let mut entity_to_name = HashMap::<_, String>::new(); + let mut teams = std::collections::HashMap::::new(); + + let mut entity_to_team = std::collections::HashMap::new(); for tick_state in output.entity_states.ticks { for state in tick_state.states { - if state.class.as_ref() != "CCSTeam" { + let team = match csdemo::structured::ccsteam::CCSTeam::try_from(&state) { + Ok(t) => t, + Err(_) => continue, + }; + + let pawns = team.player_pawns(); + let player_ids = pawns.into_iter().filter_map(|pawn| pawn_to_player.get(&pawn)).collect::>(); + if player_ids.is_empty() { + if let Some(team_number) = entity_to_team.get(&team.entity_id()) { + if let Some(score) = team.score() { + if let Some(team_entry) = teams.get_mut(team_number) { + team_entry.end_score = score as usize; + } + } + } + continue; } - let team = match state - .get_prop("CCSTeam.m_iTeamNum") - .map(|p| p.value.as_u32()) - .flatten() - { - Some(team) => { - entity_to_team.insert(state.id, team.clone()); - team + let team_number = player_ids.iter().filter_map(|p| output.player_info.get(*p).map(|p| p.team)).next().unwrap(); + + entity_to_team.insert(team.entity_id(), team_number); + + let team_entry = teams.entry(team_number).or_insert_with(|| { + TeamInfo { + end_score: 0, + start_side: team.team_name().map(|t| t.to_owned()).unwrap_or(String::new()), } - None => match entity_to_team.get(&state.id) { - Some(t) => t.clone(), - None => continue, - }, - }; - - let name = match entity_to_name.get(&state.id) { - Some(n) => n.to_owned(), - None => match state - .get_prop("CCSTeam.m_szTeamname") - .map(|p| match &p.value { - csdemo::parser::Variant::String(v) => Some(v.to_owned()), - _ => None, - }) - .flatten() - { - Some(n) => { - entity_to_name.insert(state.id, n.clone()); - n - } - None => continue, - }, - }; - - if let Some(score) = state - .get_prop("CCSTeam.m_iScore") - .map(|p| p.value.as_i32()) - .flatten() - .map(|v| v as usize) - { - teams.insert(team, TeamInfo { name, score }); + }); + if let Some(score) = team.score() { + team_entry.end_score = score as usize; } } } diff --git a/analysis/tests/endofgame.rs b/analysis/tests/endofgame.rs index b68e4dc..32e19e5 100644 --- a/analysis/tests/endofgame.rs +++ b/analysis/tests/endofgame.rs @@ -11,24 +11,7 @@ fn endofgame_nuke() { let expected = endofgame::EndOfGame { map: "de_nuke".to_owned(), - teams: [ - ( - 3, - endofgame::TeamInfo { - name: "CT".to_owned(), - score: 8, - }, - ), - ( - 2, - endofgame::TeamInfo { - name: "TERRORIST".to_owned(), - score: 13, - }, - ), - ] - .into_iter() - .collect(), + teams: [].into_iter().collect(), players: vec![ ( endofgame::PlayerInfo { diff --git a/backend/src/analysis.rs b/backend/src/analysis.rs index e00dff4..4c38120 100644 --- a/backend/src/analysis.rs +++ b/backend/src/analysis.rs @@ -102,33 +102,3 @@ pub struct AnalysisInput { pub demoid: String, pub path: PathBuf, } - -#[derive(Debug)] -pub struct BaseInfo { - pub map: String, - pub players: Vec<(BasePlayerInfo, BasePlayerStats)>, - pub teams: Vec<(u32, BaseTeamInfo)> -} - -#[derive(Debug)] -pub struct BaseTeamInfo { - pub score: usize, - pub name: String, -} - -#[derive(Debug)] -pub struct BasePlayerInfo { - pub name: String, - pub steam_id: String, - pub team: i32, - pub color: i32, - pub ingame_id: i32, -} - -#[derive(Debug)] -pub struct BasePlayerStats { - pub kills: usize, - pub deaths: usize, - pub damage: usize, - pub assists: usize, -} diff --git a/backend/src/analysis/base.rs b/backend/src/analysis/base.rs index 34b8842..e71396c 100644 --- a/backend/src/analysis/base.rs +++ b/backend/src/analysis/base.rs @@ -1,5 +1,35 @@ use super::*; +#[derive(Debug)] +struct BaseInfo { + pub map: String, + pub players: Vec<(BasePlayerInfo, BasePlayerStats)>, + pub teams: std::collections::HashMap, +} + +#[derive(Debug)] +struct BaseTeamInfo { + pub start_side: String, + pub end_score: usize, +} + +#[derive(Debug)] +struct BasePlayerInfo { + pub name: String, + pub steam_id: String, + pub team: i32, + pub color: i32, + pub ingame_id: i32, +} + +#[derive(Debug)] +struct BasePlayerStats { + pub kills: usize, + pub deaths: usize, + pub damage: usize, + pub assists: usize, +} + pub struct BaseAnalysis {} impl BaseAnalysis { @@ -36,6 +66,12 @@ impl Analysis for BaseAnalysis { let base_result = BaseInfo { map: result.map, + teams: result.teams.into_iter().map(|(numb, team)| { + (numb, BaseTeamInfo { + end_score: team.end_score, + start_side: team.start_side, + }) + }).collect(), players: result .players .into_iter() @@ -57,12 +93,6 @@ impl Analysis for BaseAnalysis { ) }) .collect(), - teams: result.teams.into_iter().map(|(numb, val)| { - (numb, BaseTeamInfo { - name: val.name, - score: val.score, - }) - }).collect(), }; let (player_info, player_stats): (Vec<_>, Vec<_>) = base_result @@ -89,20 +119,20 @@ impl Analysis for BaseAnalysis { }) .unzip(); + let teams = base_result.teams.into_iter().map(|(numb, team)| { + crate::models::DemoTeam { + demo_id: input.demoid.clone(), + team: numb as i16, + end_score: team.end_score as i16, + start_name: team.start_side, + } + }).collect::>(); + let demo_info = crate::models::DemoInfo { demo_id: input.demoid.clone(), map: base_result.map, }; - let demo_teams: Vec = base_result.teams.into_iter().map(|(numb, info)| { - crate::models::DemoTeam { - demo_id: input.demoid.clone(), - team: numb as i16, - end_score: info.score as i16, - start_name: info.name, - } - }).collect(); - Ok(Box::new(move |connection| { let store_demo_info_query = diesel::dsl::insert_into(crate::schema::demo_info::dsl::demo_info) @@ -143,19 +173,26 @@ impl Analysis for BaseAnalysis { )), )); - let store_demo_teams = diesel::dsl::insert_into(crate::schema::demo_teams::dsl::demo_teams) - .values(demo_teams).on_conflict((crate::schema::demo_teams::dsl::demo_id, crate::schema::demo_teams::dsl::team)) - .do_update() - .set(( - crate::schema::demo_teams::dsl::start_name.eq(diesel::upsert::excluded(crate::schema::demo_teams::dsl::start_name)), - crate::schema::demo_teams::dsl::end_score.eq(diesel::upsert::excluded(crate::schema::demo_teams::dsl::end_score)), + let store_teams = diesel::dsl::insert_into(crate::schema::demo_teams::dsl::demo_teams) + .values(teams) + .on_conflict(( + crate::schema::demo_teams::dsl::demo_id, + crate::schema::demo_teams::dsl::team, + )) + .do_update().set(( + crate::schema::demo_teams::dsl::start_name.eq(diesel::upsert::excluded( + crate::schema::demo_teams::dsl::start_name, + )), + crate::schema::demo_teams::dsl::end_score.eq(diesel::upsert::excluded( + crate::schema::demo_teams::dsl::end_score, + )), )); Box::pin(async move { store_demo_info_query.execute(connection).await?; store_demo_players_query.execute(connection).await?; store_demo_player_stats_query.execute(connection).await?; - store_demo_teams.execute(connection).await?; + store_teams.execute(connection).await?; Ok(()) }) diff --git a/backend/src/api/demos.rs b/backend/src/api/demos.rs index 2e8dcbd..134ff03 100644 --- a/backend/src/api/demos.rs +++ b/backend/src/api/demos.rs @@ -264,18 +264,11 @@ async fn scoreboard( return Err(axum::http::StatusCode::INTERNAL_SERVER_ERROR); } - let team1_number: i16 = response.last().map(|(p, _)| p.team).unwrap(); - - let mut team1 = Vec::new(); - let mut team2 = Vec::new(); + let mut teams = std::collections::BTreeMap::new(); for (player, stats) in response { - let team_vec = if player.team == team1_number { - &mut team1 - } else { - &mut team2 - }; + let team = teams.entry(player.team as u32).or_insert(Vec::new()); - team_vec.push(common::demo_analysis::ScoreBoardPlayer { + team.push(common::demo_analysis::ScoreBoardPlayer { name: player.name, kills: stats.kills as usize, deaths: stats.deaths as usize, @@ -285,8 +278,7 @@ async fn scoreboard( } Ok(axum::Json(common::demo_analysis::ScoreBoard { - team1, - team2, + teams: teams.into_iter().collect::>() })) } @@ -373,17 +365,20 @@ async fn heatmap( async fn perround( session: UserSession, Path(demo_id): Path, -) -> Result>, axum::http::StatusCode> { +) -> Result, axum::http::StatusCode> { let rounds_query = crate::schema::demo_round::dsl::demo_round .filter(crate::schema::demo_round::dsl::demo_id.eq(demo_id.clone())); let round_players_query = crate::schema::demo_players::dsl::demo_players - .filter(crate::schema::demo_players::dsl::demo_id.eq(demo_id)); + .filter(crate::schema::demo_players::dsl::demo_id.eq(demo_id.clone())); + let demo_teams = crate::schema::demo_teams::dsl::demo_teams + .filter(crate::schema::demo_teams::dsl::demo_id.eq(demo_id)); let mut db_con = crate::db_connection().await; let raw_rounds: Vec = rounds_query.load(&mut db_con).await.unwrap(); let players: Vec = round_players_query.load(&mut db_con).await.unwrap(); + let raw_teams: Vec = demo_teams.load(&mut db_con).await.unwrap(); let mut result = Vec::with_capacity(raw_rounds.len()); for raw_round in raw_rounds.into_iter() { @@ -450,7 +445,17 @@ async fn perround( result.push(common::demo_analysis::DemoRound { reason, events }); } - Ok(axum::Json(result)) + let teams = raw_teams.into_iter().map(|dteam| { + common::demo_analysis::PerRoundTeam { + name: dteam.start_name, + number: dteam.team as u32, + } + }).collect(); + + Ok(axum::Json(common::demo_analysis::PerRoundResult { + rounds: result, + teams, + })) } // The corresponding values for each map can be found using the Source2 Viewer and opening the diff --git a/backend/src/models.rs b/backend/src/models.rs index 940ec6b..6d074a6 100644 --- a/backend/src/models.rs +++ b/backend/src/models.rs @@ -42,6 +42,16 @@ pub struct DemoInfo { pub map: String, } +#[derive(Queryable, Selectable, Insertable, Debug)] +#[diesel(table_name = crate::schema::demo_teams)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct DemoTeam { + pub demo_id: String, + pub team: i16, + pub end_score: i16, + pub start_name: String, +} + #[derive(Queryable, Selectable, Insertable, Debug)] #[diesel(table_name = crate::schema::demo_players)] #[diesel(check_for_backend(diesel::pg::Pg))] @@ -65,16 +75,6 @@ pub struct DemoPlayerStats { pub assists: i16, } -#[derive(Queryable, Selectable, Insertable, Debug)] -#[diesel(table_name = crate::schema::demo_teams)] -#[diesel(check_for_backend(diesel::pg::Pg))] -pub struct DemoTeam { - pub demo_id: String, - pub team: i16, - pub end_score: i16, - pub start_name: String, -} - #[derive(Queryable, Selectable, Insertable, Debug)] #[diesel(table_name = crate::schema::processing_status)] #[diesel(check_for_backend(diesel::pg::Pg))] diff --git a/common/src/demo_analysis.rs b/common/src/demo_analysis.rs new file mode 100644 index 0000000..b5e01b8 --- /dev/null +++ b/common/src/demo_analysis.rs @@ -0,0 +1,73 @@ +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub struct ScoreBoard { + pub teams: Vec<(u32, Vec)> + } + + #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub struct ScoreBoardPlayer { + pub name: String, + pub kills: usize, + pub deaths: usize, + pub damage: usize, + pub assists: usize, + } + + #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub struct PlayerHeatmap { + pub name: String, + pub team: String, + pub png_data: String, + } + + #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub struct PerRoundResult { + pub teams: Vec, + pub rounds: Vec, + } + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct PerRoundTeam { + pub name: String, + pub number: u32, +} + + #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub struct DemoRound { + pub reason: RoundWinReason, + pub events: Vec + } + + #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub enum RoundWinReason { + StillInProgress, + BombExploded, + VipEscaped, + VipKilled, + TSaved, + CtStoppedEscape, + RoundEndReasonTerroristsStopped, + BombDefused, + TKilled, + CTKilled, + Draw, + HostageRescued, + TimeRanOut, + RoundEndReasonHostagesNotRescued, + TerroristsNotEscaped, + VipNotEscaped, + GameStart, + TSurrender, + CTSurrender, + TPlanted, + CTReachedHostage, + } + + #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub enum RoundEvent { + BombPlanted, + BombDefused, + Killed { + attacker: String, + died: String, + }, + } diff --git a/common/src/lib.rs b/common/src/lib.rs index cab97d3..90729ac 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -18,67 +18,4 @@ pub struct DemoInfo { pub map: String, } -pub mod demo_analysis { - #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - pub struct ScoreBoard { - pub team1: Vec, - pub team2: Vec, - } - - #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - pub struct ScoreBoardPlayer { - pub name: String, - pub kills: usize, - pub deaths: usize, - pub damage: usize, - pub assists: usize, - } - - #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - pub struct PlayerHeatmap { - pub name: String, - pub team: String, - pub png_data: String, - } - - #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - pub struct DemoRound { - pub reason: RoundWinReason, - pub events: Vec - } - - #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - pub enum RoundWinReason { - StillInProgress, - BombExploded, - VipEscaped, - VipKilled, - TSaved, - CtStoppedEscape, - RoundEndReasonTerroristsStopped, - BombDefused, - TKilled, - CTKilled, - Draw, - HostageRescued, - TimeRanOut, - RoundEndReasonHostagesNotRescued, - TerroristsNotEscaped, - VipNotEscaped, - GameStart, - TSurrender, - CTSurrender, - TPlanted, - CTReachedHostage, - } - - #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - pub enum RoundEvent { - BombPlanted, - BombDefused, - Killed { - attacker: String, - died: String, - }, - } -} +pub mod demo_analysis; diff --git a/frontend/src/demo/perround.rs b/frontend/src/demo/perround.rs index 6a7e0c5..2cca48f 100644 --- a/frontend/src/demo/perround.rs +++ b/frontend/src/demo/perround.rs @@ -1,26 +1,14 @@ use leptos::*; -fn to_roman(mut number: u32) -> char { - if number < 12 { - char::from_u32(8544 + number).unwrap() - } else if number < 24 { - char::from_u32(8544 + (number - 12)).unwrap() - } else if number < 27 { - char::from_u32(8544 + (number - 24)).unwrap() - } else { - char::from_u32(8544 + (number - 27)).unwrap() - } -} - fn to_coloumn(idx: usize) -> usize { if idx < 12 { - 1 + idx + 2 + idx } else if idx < 24 { - 1 + idx + 1 + 2 + idx + 1 } else if idx < 27 { - 1 + idx + 2 + 2 + idx + 2 } else { - 1 + idx + 3 + 2 + idx + 3 } } @@ -35,18 +23,18 @@ pub fn per_round() -> impl leptos::IntoView { .send() .await .unwrap(); - res.json::>() + res.json::() .await .unwrap() }); - + let style = stylers::style! { "PerRound", .round_overview { display: inline-grid; width: 90vw; - grid-template-columns: repeat(12, 1fr) 5px repeat(12, 1fr) 5px repeat(3, 1fr) 5px repeat(3, 1fr); + grid-template-columns: auto repeat(12, 1fr) 5px repeat(12, 1fr) 5px repeat(3, 1fr) 5px repeat(3, 1fr); grid-template-rows: repeat(3, auto); } @@ -84,7 +72,7 @@ pub fn per_round() -> impl leptos::IntoView { let events_list = move || { let round_index = round(); - let current_round = perround_resource.get().map(|rs| rs.get(round_index).cloned()).flatten(); + let current_round = perround_resource.get().map(|rs| rs.rounds.get(round_index).cloned()).flatten(); match current_round { Some(round) => { @@ -106,7 +94,7 @@ pub fn per_round() -> impl leptos::IntoView { set_round.set(r); }; - let round = perround_resource.get().map(|rs| rs.get(r).cloned()).flatten(); + let round = perround_resource.get().map(|rs| rs.rounds.get(r).cloned()).flatten(); let reason = round.map(|r| r.reason); let (ct_won, t_won) = match &reason { @@ -159,11 +147,27 @@ pub fn per_round() -> impl leptos::IntoView { }).collect::>() }; + let team_names = move || { + let perround_teams = match perround_resource.get().map(|p| p.teams) { + Some(t) => t, + None => return view! {}.into_view(), + }; + + let upper = perround_teams.iter().find(|t| t.name == "CT").map(|t| t.number).unwrap_or(0); + let lower = perround_teams.iter().find(|t| t.name == "TERRORIST").map(|t| t.number).unwrap_or(0); + + view! { + Team { upper } + Team { lower } + }.into_view() + }; + view! { class=style,

Per Round

+ { team_names } { round_overview }
diff --git a/frontend/src/demo/scoreboard.rs b/frontend/src/demo/scoreboard.rs index f40b472..0143711 100644 --- a/frontend/src/demo/scoreboard.rs +++ b/frontend/src/demo/scoreboard.rs @@ -20,14 +20,24 @@ pub fn scoreboard() -> impl leptos::IntoView { let (ordering, set_ordering) = create_signal::(orderings::DAMAGE); + let scoreboards = move || { + scoreboard_resource + .get() + .into_iter() + .flat_map(|v| v.teams.into_iter()) + .map(|(team, players)| view! { + + }) + .collect::>() + }; + view! {

Scoreboard

Loading Scoreboard data

} > - - + { scoreboards }
} } @@ -79,7 +89,7 @@ mod orderings { } #[leptos::component] -fn team_scoreboard(info: Resource, team_name: String, part: fn(common::demo_analysis::ScoreBoard) -> Vec) -> impl IntoView { +fn team_scoreboard(value: Vec, team_name: String) -> impl IntoView { let (ordering, set_ordering) = create_signal::(orderings::DAMAGE); let style = stylers::style! { @@ -119,8 +129,7 @@ fn team_scoreboard(info: Resource { move || { - let value = info.get().map(|v| part(v)); - let mut players: Vec<_> = value.into_iter().flat_map(|v| v).collect(); + let mut players: Vec<_> = value.clone().into_iter().collect(); let sorting = ordering.get(); players.sort_unstable_by(|p1, p2| (sorting.sort_fn)(p1, p2));