From b21602276839bc19623744604e2162469088c178 Mon Sep 17 00:00:00 2001 From: Lol3rrr Date: Tue, 17 Sep 2024 17:35:02 +0200 Subject: [PATCH] Add basic analysis results, like scoreboard --- Cargo.lock | 10 +-- backend/src/analysis.rs | 87 ++++++++++++------- backend/src/lib.rs | 40 +++++++-- backend/src/models.rs | 21 +++++ backend/src/schema.rs | 23 +++++ .../2024-09-11-200628_demo_info/down.sql | 4 +- migrations/2024-09-11-200628_demo_info/up.sql | 19 +++- 7 files changed, 157 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3a20d1..f07fbfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,9 +307,9 @@ checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" [[package]] name = "cc" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +checksum = "45bcde016d64c21da4be18b655631e5ab6d3107607e71a73a9f53eb48aae23fb" dependencies = [ "shlex", ] @@ -504,7 +504,7 @@ dependencies = [ [[package]] name = "csdemo" version = "0.1.0" -source = "git+https://github.com/Lol3rrr/csdemo.git#4417b263a0c04ceb32e199e67dd790adf4645277" +source = "git+https://github.com/Lol3rrr/csdemo.git#c5237af33bc892437cf7b8658de34d7dad8947a0" dependencies = [ "bitter", "phf", @@ -3059,9 +3059,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ "indexmap", "serde", diff --git a/backend/src/analysis.rs b/backend/src/analysis.rs index 6b59030..c7cc15a 100644 --- a/backend/src/analysis.rs +++ b/backend/src/analysis.rs @@ -49,7 +49,22 @@ pub struct AnalysisInput { #[derive(Debug)] pub struct BaseInfo { pub map: String, - pub players: Vec<()>, + pub players: Vec<(BasePlayerInfo, BasePlayerStats)>, +} + +#[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, } #[tracing::instrument(skip(input))] @@ -66,7 +81,7 @@ pub fn analyse_base(input: AnalysisInput) -> BaseInfo { tracing::info!("Header: {:?}", header); - dbg!(&output.player_info); + let mut player_stats = std::collections::HashMap::with_capacity(output.player_info.len()); for event in output.events.iter() { match event { @@ -76,52 +91,58 @@ pub fn analyse_base(input: AnalysisInput) -> BaseInfo { csdemo::DemoEvent::RankReveal(reveal) => {} csdemo::DemoEvent::GameEvent(gevent) => { match gevent { + csdemo::game_event::GameEvent::BeginNewMatch(_) => { + player_stats.clear(); + } csdemo::game_event::GameEvent::PlayerTeam(pteam) => { - tracing::info!("{:?}", pteam); + // tracing::info!("{:?}", pteam); } csdemo::game_event::GameEvent::RoundOfficiallyEnded(r_end) => { - tracing::info!("{:?}", r_end); + // tracing::info!("{:?}", r_end); } csdemo::game_event::GameEvent::PlayerDeath(pdeath) => { - tracing::info!("{:?}", pdeath); + // tracing::info!("{:?}", pdeath); + + let player_died_id = pdeath.userid.unwrap(); + + let player_died = player_stats.entry(player_died_id).or_insert(BasePlayerStats { + kills: 0, + deaths: 0, + }); + player_died.deaths += 1; + + if let Some(attacker_id) = pdeath.attacker { + let attacker = player_stats.entry(attacker_id).or_insert(BasePlayerStats { + kills: 0, + deaths: 0, + }); + attacker.kills += 1; + + // tracing::trace!("{:?} killed {:?}", attacker_id, player_died_id); + } } other => {} }; } }; - - /* - match event.name.as_str() { - "team_info" => { - tracing::info!("Team Info: {:?}", event); - } - "player_spawn" => { - // tracing::info!("Player Spawn: {:?}", event); - } - "team_score" => { - tracing::info!("Team Score: {:?}", event); - } - "game_end" => { - tracing::info!("Game End: {:?}", event); - } - "match_end_conditions" => { - tracing::info!("Match End Conditions: {:?}", event); - } - "switch_team" => { - tracing::info!("Switch Team: {:?}", event); - } - "player_given_c4" => { - tracing::info!("Player Given C4: {:?}", event); - } - _ => {} - }; - */ } + let players: Vec<_> = player_stats.into_iter().filter_map(|(id, stats)| { + let player = output.player_info.get(&id)?; + + Some((BasePlayerInfo { + name: player.name.clone(), + steam_id: player.xuid.to_string(), + team: player.team, + color: player.color, + ingame_id: id.0, + }, stats)) + }).collect(); + let map = header.map_name().to_owned(); BaseInfo { map, - players: Vec::new(), + players, } } diff --git a/backend/src/lib.rs b/backend/src/lib.rs index 1dc8d31..04a3a19 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -114,23 +114,49 @@ pub async fn run_analysis( let mut db_con = crate::db_connection().await; - let store_info_query = diesel::dsl::insert_into(crate::schema::demo_info::dsl::demo_info) - .values(crate::models::DemoInfo { + let (player_info, player_stats): (Vec<_>, Vec<_>) = result.players.into_iter().map(|(info, stats)| { + (crate::models::DemoPlayer { + demo_id, + name: info.name, + steam_id: info.steam_id.clone(), + team: info.team as i16, + color: info.color as i16, + }, crate::models::DemoPlayerStats { + demo_id, + steam_id: info.steam_id, + deaths: stats.deaths as i16, + kills: stats.kills as i16, + }) + }).unzip(); + + let demo_info = crate::models::DemoInfo { demo_id, map: result.map, - }); + }; + + let store_demo_info_query = diesel::dsl::insert_into(crate::schema::demo_info::dsl::demo_info) + .values(&demo_info).on_conflict(crate::schema::demo_info::dsl::demo_id).do_update().set(crate::schema::demo_info::dsl::map.eq(diesel::upsert::excluded(crate::schema::demo_info::dsl::map))); + let store_demo_players_query = diesel::dsl::insert_into(crate::schema::demo_players::dsl::demo_players).values(player_info) + .on_conflict_do_nothing(); + let store_demo_player_stats_query = diesel::dsl::insert_into(crate::schema::demo_player_stats::dsl::demo_player_stats) + .values(player_stats) + .on_conflict((crate::schema::demo_player_stats::dsl::demo_id, crate::schema::demo_player_stats::dsl::steam_id)) + .do_update() + .set(( + crate::schema::demo_player_stats::dsl::deaths.eq(diesel::upsert::excluded(crate::schema::demo_player_stats::dsl::deaths)), + crate::schema::demo_player_stats::dsl::kills.eq(diesel::upsert::excluded(crate::schema::demo_player_stats::dsl::kills)), + )); let update_process_info = diesel::dsl::update(crate::schema::processing_status::dsl::processing_status) .set(crate::schema::processing_status::dsl::info.eq(1)) .filter(crate::schema::processing_status::dsl::demo_id.eq(demo_id)); - tracing::trace!(?store_info_query, "Store demo info query"); - tracing::trace!(?update_process_info, "Update processing info query"); - db_con .transaction::<'_, '_, '_, _, diesel::result::Error, _>(|conn| { Box::pin(async move { - store_info_query.execute(conn).await?; + store_demo_info_query.execute(conn).await?; + store_demo_players_query.execute(conn).await?; + store_demo_player_stats_query.execute(conn).await?; update_process_info.execute(conn).await?; Ok(()) }) diff --git a/backend/src/models.rs b/backend/src/models.rs index e8179fc..553841f 100644 --- a/backend/src/models.rs +++ b/backend/src/models.rs @@ -33,6 +33,27 @@ pub struct DemoInfo { pub map: String, } +#[derive(Queryable, Selectable, Insertable, Debug)] +#[diesel(table_name = crate::schema::demo_players)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct DemoPlayer { + pub demo_id: i64, + pub steam_id: String, + pub name: String, + pub team: i16, + pub color: i16, +} + +#[derive(Queryable, Selectable, Insertable, Debug)] +#[diesel(table_name = crate::schema::demo_player_stats)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct DemoPlayerStats { + pub demo_id: i64, + pub steam_id: String, + pub kills: i16, + pub deaths: i16, +} + #[derive(Queryable, Selectable, Insertable, Debug)] #[diesel(table_name = crate::schema::processing_status)] #[diesel(check_for_backend(diesel::pg::Pg))] diff --git a/backend/src/schema.rs b/backend/src/schema.rs index db7ae3a..2216239 100644 --- a/backend/src/schema.rs +++ b/backend/src/schema.rs @@ -15,6 +15,25 @@ diesel::table! { } } +diesel::table! { + demo_player_stats (demo_id, steam_id) { + demo_id -> Int8, + steam_id -> Text, + kills -> Int2, + deaths -> Int2, + } +} + +diesel::table! { + demo_players (demo_id, steam_id) { + demo_id -> Int8, + steam_id -> Text, + name -> Text, + team -> Int2, + color -> Int2, + } +} + diesel::table! { demos (demo_id) { steam_id -> Text, @@ -46,11 +65,15 @@ diesel::table! { diesel::joinable!(analysis_queue -> demos (demo_id)); diesel::joinable!(demo_info -> demos (demo_id)); +diesel::joinable!(demo_player_stats -> demo_info (demo_id)); +diesel::joinable!(demo_players -> demo_info (demo_id)); diesel::joinable!(processing_status -> demos (demo_id)); diesel::allow_tables_to_appear_in_same_query!( analysis_queue, demo_info, + demo_player_stats, + demo_players, demos, processing_status, sessions, diff --git a/migrations/2024-09-11-200628_demo_info/down.sql b/migrations/2024-09-11-200628_demo_info/down.sql index 3df2430..16986aa 100644 --- a/migrations/2024-09-11-200628_demo_info/down.sql +++ b/migrations/2024-09-11-200628_demo_info/down.sql @@ -1,3 +1,5 @@ -- This file should undo anything in `up.sql` DROP TABLE processing_status; -DROP TABLE demo_info +DROP TABLE demo_player_stats; +DROP TABLE demo_players; +DROP TABLE demo_info; diff --git a/migrations/2024-09-11-200628_demo_info/up.sql b/migrations/2024-09-11-200628_demo_info/up.sql index b867458..8040891 100644 --- a/migrations/2024-09-11-200628_demo_info/up.sql +++ b/migrations/2024-09-11-200628_demo_info/up.sql @@ -7,4 +7,21 @@ CREATE TABLE IF NOT EXISTS processing_status ( CREATE TABLE IF NOT EXISTS demo_info ( demo_id bigint PRIMARY KEY REFERENCES demos(demo_id), map TEXT NOT NULL -) +); + +CREATE TABLE IF NOT EXISTS demo_players ( + demo_id bigint REFERENCES demo_info(demo_id), + steam_id TEXT NOT NULL, + name TEXT NOT NULL, + team int2 NOT NULL, + color int2 NOT NULL, + PRIMARY KEY (demo_id, steam_id) +); + +CREATE TABLE IF NOT EXISTS demo_player_stats ( + demo_id bigint REFERENCES demo_info(demo_id), + steam_id TEXT NOT NULL, + kills int2 NOT NULL, + deaths int2 NOT NULL, + PRIMARY KEY (demo_id, steam_id) +);