Initial work on the actual maps for the heatmap overview
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +1,2 @@
|
|||||||
testfiles/* filter=lfs diff=lfs merge=lfs -text
|
testfiles/* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
69
Cargo.lock
generated
69
Cargo.lock
generated
@@ -4,9 +4,9 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.24.1"
|
version = "0.24.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
|
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gimli",
|
"gimli",
|
||||||
]
|
]
|
||||||
@@ -289,7 +289,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"image",
|
"image",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"reqwest 0.12.7",
|
"reqwest 0.12.8",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"steam-openid",
|
"steam-openid",
|
||||||
@@ -411,9 +411,9 @@ checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.22"
|
version = "1.1.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
|
checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -465,9 +465,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.18"
|
version = "4.5.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
|
checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -475,9 +475,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.18"
|
version = "4.5.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
|
checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -666,7 +666,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "csdemo"
|
name = "csdemo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/Lol3rrr/csdemo.git#777248ab3c597b36103a9e0fa05e606134a1503c"
|
source = "git+https://github.com/Lol3rrr/csdemo.git#4671d0cbde48800dbb99cabba27ccb408df9fc3f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitter",
|
"bitter",
|
||||||
"phf",
|
"phf",
|
||||||
@@ -719,7 +719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"hashbrown",
|
"hashbrown 0.14.5",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
@@ -1113,9 +1113,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.31.0"
|
version = "0.31.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gloo-net"
|
name = "gloo-net"
|
||||||
@@ -1238,6 +1238,12 @@ version = "0.14.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -1332,9 +1338,9 @@ checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.9.4"
|
version = "1.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpdate"
|
name = "httpdate"
|
||||||
@@ -1509,12 +1515,12 @@ checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.5.0"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1542,9 +1548,9 @@ checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.10.0"
|
version = "2.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
|
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
@@ -2114,9 +2120,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.36.4"
|
version = "0.36.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
|
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -2819,9 +2825,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.7"
|
version = "0.12.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
|
checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -2844,7 +2850,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustls-pemfile 2.1.3",
|
"rustls-pemfile 2.2.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
@@ -2947,11 +2953,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pemfile"
|
name = "rustls-pemfile"
|
||||||
version = "2.1.3"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
|
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3927,9 +3932,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
@@ -3948,9 +3953,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-properties"
|
name = "unicode-properties"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524"
|
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
|
|||||||
@@ -4,19 +4,27 @@ pub struct Config {
|
|||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct HeatMap {
|
pub struct HeatMap {
|
||||||
|
#[serde(default)]
|
||||||
|
min_x: usize,
|
||||||
|
#[serde(default)]
|
||||||
|
min_y: usize,
|
||||||
max_x: usize,
|
max_x: usize,
|
||||||
max_y: usize,
|
max_y: usize,
|
||||||
max_value: usize,
|
max_value: usize,
|
||||||
rows: Vec<Vec<usize>>,
|
rows: Vec<Vec<usize>>,
|
||||||
|
block_size: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeatMap {
|
impl HeatMap {
|
||||||
fn new() -> Self {
|
fn new(block_size: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
min_x: 0,
|
||||||
|
min_y: 0,
|
||||||
max_x: 0,
|
max_x: 0,
|
||||||
max_y: 0,
|
max_y: 0,
|
||||||
max_value: 0,
|
max_value: 0,
|
||||||
rows: Vec::new(),
|
rows: Vec::new(),
|
||||||
|
block_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +141,8 @@ fn get_entityid(props: &[csdemo::parser::entities::EntityProp]) -> Option<i32> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const MAX_COORD: f32 = (1 << 14) as f32;
|
||||||
|
|
||||||
fn process_tick(
|
fn process_tick(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
tick_state: &csdemo::parser::EntityTickStates,
|
tick_state: &csdemo::parser::EntityTickStates,
|
||||||
@@ -146,7 +156,7 @@ fn process_tick(
|
|||||||
for entity_state in tick_state
|
for entity_state in tick_state
|
||||||
.states
|
.states
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|s| s.class == "CCSPlayerPawn")
|
.filter(|s| s.class.as_ref() == "CCSPlayerPawn")
|
||||||
{
|
{
|
||||||
if let Some(pawn_id) = get_entityid(&entity_state.props) {
|
if let Some(pawn_id) = get_entityid(&entity_state.props) {
|
||||||
let user_id = pawn_ids.get(&pawn_id).cloned().unwrap();
|
let user_id = pawn_ids.get(&pawn_id).cloned().unwrap();
|
||||||
@@ -192,8 +202,6 @@ fn process_tick(
|
|||||||
assert!(y_coord >= 0.0);
|
assert!(y_coord >= 0.0);
|
||||||
assert!(z_coord >= 0.0);
|
assert!(z_coord >= 0.0);
|
||||||
|
|
||||||
const MAX_COORD: f32 = (1 << 14) as f32;
|
|
||||||
|
|
||||||
let x_cell_coord = ((x_cell as f32 * (1 << 9) as f32)) as f32;
|
let x_cell_coord = ((x_cell as f32 * (1 << 9) as f32)) as f32;
|
||||||
let y_cell_coord = ((y_cell as f32 * (1 << 9) as f32)) as f32;
|
let y_cell_coord = ((y_cell as f32 * (1 << 9) as f32)) as f32;
|
||||||
let z_cell_coord = ((z_cell as f32 * (1 << 9) as f32)) as f32;
|
let z_cell_coord = ((z_cell as f32 * (1 << 9) as f32)) as f32;
|
||||||
@@ -235,7 +243,7 @@ fn process_tick(
|
|||||||
|
|
||||||
// tracing::trace!("Coord (X, Y, Z): {:?} -> {:?}", (x_coord, y_coord, z_coord), (x_cell, y_cell));
|
// tracing::trace!("Coord (X, Y, Z): {:?} -> {:?}", (x_coord, y_coord, z_coord), (x_cell, y_cell));
|
||||||
|
|
||||||
let heatmap = heatmaps.entry(user_id.clone()).or_insert(HeatMap::new());
|
let heatmap = heatmaps.entry(user_id.clone()).or_insert(HeatMap::new(config.cell_size));
|
||||||
heatmap.increment(x_cell, y_cell);
|
heatmap.increment(x_cell, y_cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,13 +264,20 @@ impl core::fmt::Display for HeatMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HeatMap {
|
impl HeatMap {
|
||||||
|
pub fn coords(&self) -> ((f32, f32), (f32, f32)) {
|
||||||
|
(
|
||||||
|
(self.min_x as f32 * self.block_size - MAX_COORD, self.max_x as f32 * self.block_size - MAX_COORD),
|
||||||
|
(self.min_y as f32 * self.block_size - MAX_COORD, self.max_y as f32 * self.block_size - MAX_COORD)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_image(&self) -> image::RgbImage {
|
pub fn as_image(&self) -> image::RgbImage {
|
||||||
use colors_transform::Color;
|
use colors_transform::Color;
|
||||||
|
|
||||||
let mut buffer = image::RgbImage::new(self.max_x as u32 + 1, self.max_y as u32 + 1);
|
let mut buffer = image::RgbImage::new((self.max_x - self.min_x) as u32 + 1, (self.max_y - self.min_y) as u32 + 1);
|
||||||
|
|
||||||
for (y, row) in self.rows.iter().rev().enumerate() {
|
for (y, row) in self.rows.iter().rev().enumerate() {
|
||||||
for (x, cell) in row.iter().copied().chain(core::iter::repeat(0)).enumerate().take(self.max_x) {
|
for (x, cell) in row.iter().copied().chain(core::iter::repeat(0)).enumerate().take((self.max_x - self.min_x)) {
|
||||||
let scaled = (1.0/(1.0 + (cell as f32))) * 240.0;
|
let scaled = (1.0/(1.0 + (cell as f32))) * 240.0;
|
||||||
let raw_rgb = colors_transform::Hsl::from(scaled, 100.0, 50.0).to_rgb();
|
let raw_rgb = colors_transform::Hsl::from(scaled, 100.0, 50.0).to_rgb();
|
||||||
|
|
||||||
@@ -273,17 +288,101 @@ impl HeatMap {
|
|||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shrink(&mut self) {
|
pub fn fit(&mut self, xs: core::ops::Range<f32>, ys: core::ops::Range<f32>) {
|
||||||
let min_x = self.rows.iter().filter_map(|row| row.iter().enumerate().filter(|(_, v)| **v != 0).map(|(i, _)| i).next()).min().unwrap_or(0);
|
let min_x = (xs.start / self.block_size - self.min_x as f32) as usize;
|
||||||
let min_y = self.rows.iter().enumerate().filter(|(y, row)| row.iter().any(|v| *v != 0)).map(|(i, _)| i).min().unwrap_or(0);
|
let min_y = (ys.start / self.block_size - self.min_y as f32) as usize;
|
||||||
|
|
||||||
let _ = self.rows.drain(0..min_y);
|
let _ = self.rows.drain(0..min_y);
|
||||||
for row in self.rows.iter_mut() {
|
for row in self.rows.iter_mut() {
|
||||||
let _ = row.drain(0..min_x);
|
let _ = row.drain(0..min_x.min(row.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let x_steps = ((xs.end - xs.start) / self.block_size) as usize;
|
||||||
|
let y_steps = ((ys.end - ys.start) / self.block_size) as usize;
|
||||||
|
|
||||||
self.max_y = self.rows.len();
|
for row in self.rows.iter_mut() {
|
||||||
self.max_x = self.rows.iter().map(|r| r.len()).max().unwrap_or(0);
|
row.resize(x_steps, 0);
|
||||||
|
}
|
||||||
|
self.rows.resize_with(y_steps, || vec![0; x_steps]);
|
||||||
|
|
||||||
|
self.min_y += (0..min_y).len();
|
||||||
|
self.min_x += (0..min_x).len();
|
||||||
|
|
||||||
|
self.max_y = self.min_y + self.rows.len();
|
||||||
|
self.max_x = self.min_x + self.rows.iter().map(|r| r.len()).max().unwrap_or(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fit_no_cutoff() {
|
||||||
|
let mut input = HeatMap::new(2.0);
|
||||||
|
|
||||||
|
input.increment(3, 3);
|
||||||
|
input.increment(2, 2);
|
||||||
|
|
||||||
|
assert_eq!(input.min_x, 0);
|
||||||
|
assert_eq!(input.min_y, 0);
|
||||||
|
assert_eq!(input.max_x, 3);
|
||||||
|
assert_eq!(input.max_y, 3);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
&vec![
|
||||||
|
vec![],
|
||||||
|
vec![],
|
||||||
|
vec![0, 0, 1],
|
||||||
|
vec![0, 0, 0, 1]
|
||||||
|
],
|
||||||
|
&input.rows
|
||||||
|
);
|
||||||
|
|
||||||
|
input.fit(2.0..10.0, 2.0..10.0);
|
||||||
|
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
&vec![
|
||||||
|
vec![0, 0, 0, 0],
|
||||||
|
vec![0, 1, 0, 0],
|
||||||
|
vec![0, 0, 1, 0],
|
||||||
|
vec![0, 0, 0, 0],
|
||||||
|
],
|
||||||
|
&input.rows
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fit_cutoff() {
|
||||||
|
let mut input = HeatMap::new(2.0);
|
||||||
|
|
||||||
|
input.increment(3, 3);
|
||||||
|
input.increment(2, 2);
|
||||||
|
|
||||||
|
assert_eq!(input.min_x, 0);
|
||||||
|
assert_eq!(input.min_y, 0);
|
||||||
|
assert_eq!(input.max_x, 3);
|
||||||
|
assert_eq!(input.max_y, 3);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
&vec![
|
||||||
|
vec![],
|
||||||
|
vec![],
|
||||||
|
vec![0, 0, 1],
|
||||||
|
vec![0, 0, 0, 1]
|
||||||
|
],
|
||||||
|
&input.rows
|
||||||
|
);
|
||||||
|
|
||||||
|
input.fit(6.0..10.0, 6.0..10.0);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
&vec![
|
||||||
|
vec![1, 0],
|
||||||
|
vec![0, 0]
|
||||||
|
],
|
||||||
|
&input.rows
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ fn heatmap_nuke() {
|
|||||||
let config = heatmap::Config { cell_size: 5.0 };
|
let config = heatmap::Config { cell_size: 5.0 };
|
||||||
let result = heatmap::parse(&config, &input_bytes).unwrap();
|
let result = heatmap::parse(&config, &input_bytes).unwrap();
|
||||||
|
|
||||||
assert_eq!(result.player_heatmaps.len(), result.player_info.len());
|
assert_eq!(result.player_heatmaps.len(), 11);
|
||||||
|
assert_eq!(result.entity_to_player.len(), 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -72,7 +72,13 @@ async fn upload(
|
|||||||
|
|
||||||
tracing::info!("Upload for Session: {:?}", steam_id);
|
tracing::info!("Upload for Session: {:?}", steam_id);
|
||||||
|
|
||||||
let file_content = crate::get_demo_from_upload("demo", form).await.unwrap();
|
let file_content = match crate::get_demo_from_upload("demo", form).await {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
|
tracing::error!("Getting File content from request");
|
||||||
|
return Err((axum::http::StatusCode::BAD_REQUEST, "Failed to get file-content from upload"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let user_folder = std::path::Path::new(&state.upload_folder).join(format!("{}/", steam_id));
|
let user_folder = std::path::Path::new(&state.upload_folder).join(format!("{}/", steam_id));
|
||||||
if !tokio::fs::try_exists(&user_folder).await.unwrap_or(false) {
|
if !tokio::fs::try_exists(&user_folder).await.unwrap_or(false) {
|
||||||
@@ -260,13 +266,28 @@ async fn heatmap(
|
|||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Querying DB: {:?}", e);
|
tracing::error!("Querying DB: {:?}", e);
|
||||||
return Err(axum::http::StatusCode::INTERNAL_SERVER_ERROR);;
|
return Err(axum::http::StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// These are currently the values for de_inferno
|
||||||
|
// The corresponding values for each map can be found using the Source2 Viewer and opening the
|
||||||
|
// files in 'game/csgo/pak01_dir.vpk' and then 'resource/overviews/{map}.txt'
|
||||||
|
let pos_x: f32 = 2087.0;
|
||||||
|
let pos_y: f32 = 3870.0;
|
||||||
|
let scale: f32 = 4.9;
|
||||||
|
|
||||||
|
let x = |map_coord: f32| {
|
||||||
|
(map_coord * scale) - pos_x + analysis::heatmap::MAX_COORD
|
||||||
|
};
|
||||||
|
let y = |map_coord: f32| {
|
||||||
|
-(map_coord * scale) + pos_y + analysis::heatmap::MAX_COORD
|
||||||
|
};
|
||||||
|
|
||||||
let data: Vec<common::demo_analysis::PlayerHeatmap> = result.into_iter().map(|(player, heatmap)| {
|
let data: Vec<common::demo_analysis::PlayerHeatmap> = result.into_iter().map(|(player, heatmap)| {
|
||||||
let mut heatmap: analysis::heatmap::HeatMap = serde_json::from_str(&heatmap.data).unwrap();
|
let mut heatmap: analysis::heatmap::HeatMap = serde_json::from_str(&heatmap.data).unwrap();
|
||||||
heatmap.shrink();
|
heatmap.fit(x(0.0)..x(1024.0), y(1024.0)..y(0.0));
|
||||||
let h_image = heatmap.as_image();
|
let h_image = heatmap.as_image();
|
||||||
|
|
||||||
let mut buffer = std::io::Cursor::new(Vec::new());
|
let mut buffer = std::io::Cursor::new(Vec::new());
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ pub async fn run_api(
|
|||||||
"/api/",
|
"/api/",
|
||||||
crate::api::router(crate::api::RouterConfig {
|
crate::api::router(crate::api::RouterConfig {
|
||||||
steam_api_key: steam_api_key.into(),
|
steam_api_key: steam_api_key.into(),
|
||||||
steam_callback_base_url: "http://localhost:3000".into(),
|
|
||||||
// steam_callback_base_url: "http://localhost:3000".into(),
|
// steam_callback_base_url: "http://localhost:3000".into(),
|
||||||
|
steam_callback_base_url: "http://192.168.0.156:3000".into(),
|
||||||
steam_callback_path: "/api/steam/callback".into(),
|
steam_callback_path: "/api/steam/callback".into(),
|
||||||
upload_dir: upload_folder.clone(),
|
upload_dir: upload_folder.clone(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" href="/main.css">
|
<link rel="stylesheet" href="/main.css">
|
||||||
|
|
||||||
|
<link data-trunk rel="copy-dir" href="static/"/>
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body></body>
|
||||||
|
|||||||
@@ -3,11 +3,17 @@ use leptos_router::{Outlet, A};
|
|||||||
|
|
||||||
pub mod heatmap;
|
pub mod heatmap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct CurrentDemoName(ReadSignal<String>);
|
||||||
|
|
||||||
#[leptos::component]
|
#[leptos::component]
|
||||||
pub fn demo() -> impl leptos::IntoView {
|
pub fn demo() -> impl leptos::IntoView {
|
||||||
let params = leptos_router::use_params_map();
|
let params = leptos_router::use_params_map();
|
||||||
let id = move || params.with(|params| params.get("id").cloned().unwrap_or_default());
|
let id = move || params.with(|params| params.get("id").cloned().unwrap_or_default());
|
||||||
|
|
||||||
|
let (rx, map_tx) = create_signal(String::new());
|
||||||
|
provide_context(CurrentDemoName(rx.clone()));
|
||||||
|
|
||||||
let demo_info = create_resource(
|
let demo_info = create_resource(
|
||||||
|| (),
|
|| (),
|
||||||
move |_| async move {
|
move |_| async move {
|
||||||
@@ -15,7 +21,11 @@ pub fn demo() -> impl leptos::IntoView {
|
|||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
res.json::<common::DemoInfo>().await.unwrap()
|
let value = res.json::<common::DemoInfo>().await.unwrap();
|
||||||
|
|
||||||
|
map_tx.set(value.map.clone());
|
||||||
|
|
||||||
|
value
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use leptos::*;
|
use leptos::*;
|
||||||
|
|
||||||
|
use super::CurrentDemoName;
|
||||||
|
|
||||||
#[leptos::component]
|
#[leptos::component]
|
||||||
pub fn heatmaps() -> impl leptos::IntoView {
|
pub fn heatmaps() -> impl leptos::IntoView {
|
||||||
let heatmaps_resource =
|
let heatmaps_resource =
|
||||||
@@ -40,12 +42,22 @@ fn heatmap_view(heatmaps: Vec<common::demo_analysis::PlayerHeatmap>) -> impl lep
|
|||||||
|
|
||||||
let h1 = heatmaps.clone();
|
let h1 = heatmaps.clone();
|
||||||
|
|
||||||
|
let map = use_context::<CurrentDemoName>().unwrap();
|
||||||
|
|
||||||
let style = stylers::style! {
|
let style = stylers::style! {
|
||||||
"Heatmap-View",
|
"Heatmap-View",
|
||||||
img {
|
.heatmap_image {
|
||||||
width: 75vw;
|
width: 1024px;
|
||||||
height: 75vw;
|
height: 1024px;
|
||||||
display: block;
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.heatmap_image > * {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heatmap_image > .heatmap {
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,7 +84,11 @@ fn heatmap_view(heatmaps: Vec<common::demo_analysis::PlayerHeatmap>) -> impl lep
|
|||||||
move || {
|
move || {
|
||||||
match value.get() {
|
match value.get() {
|
||||||
Some(heatmap) => view! {
|
Some(heatmap) => view! {
|
||||||
<img class="heatmap_img" src=format!("data:image/png;base64,{}", heatmap.png_data) />
|
class=style,
|
||||||
|
<div class="heatmap_image">
|
||||||
|
<img class="radar" src=format!("/static/minimaps/{}.png", map.0.get()) />
|
||||||
|
<img class="heatmap" width=1024 height=1024 src=format!("data:image/png;base64,{}", heatmap.png_data) />
|
||||||
|
</div>
|
||||||
}.into_any(),
|
}.into_any(),
|
||||||
None => view! { <p>ERROR</p> }.into_any(),
|
None => view! { <p>ERROR</p> }.into_any(),
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
frontend/static/minimaps/de_ancient.png
LFS
Executable file
BIN
frontend/static/minimaps/de_ancient.png
LFS
Executable file
Binary file not shown.
BIN
frontend/static/minimaps/de_anubis.png
LFS
Executable file
BIN
frontend/static/minimaps/de_anubis.png
LFS
Executable file
Binary file not shown.
BIN
frontend/static/minimaps/de_dust2.png
LFS
Executable file
BIN
frontend/static/minimaps/de_dust2.png
LFS
Executable file
Binary file not shown.
BIN
frontend/static/minimaps/de_inferno.png
LFS
Executable file
BIN
frontend/static/minimaps/de_inferno.png
LFS
Executable file
Binary file not shown.
BIN
frontend/static/minimaps/de_mirage.png
LFS
Executable file
BIN
frontend/static/minimaps/de_mirage.png
LFS
Executable file
Binary file not shown.
BIN
frontend/static/minimaps/de_overpass.png
LFS
Executable file
BIN
frontend/static/minimaps/de_overpass.png
LFS
Executable file
Binary file not shown.
Reference in New Issue
Block a user