From eac4f60acfc767321659dd62e3982463e77fa188 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Sun, 22 Jan 2023 21:39:22 +0100 Subject: [PATCH 1/6] Check name string for allowed characters --- .../elements/leaderboard/leaderboard_entry.rs | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/overlay/elements/leaderboard/leaderboard_entry.rs b/src/overlay/elements/leaderboard/leaderboard_entry.rs index d45cdc5..c809b44 100644 --- a/src/overlay/elements/leaderboard/leaderboard_entry.rs +++ b/src/overlay/elements/leaderboard/leaderboard_entry.rs @@ -108,7 +108,26 @@ impl LeaderBoardEntry { pub fn change_name(&mut self, name: String) -> Result<()> { self.name = name; - self.name_label.set_text(&self.name) + self.name_label.set_text(Self::check_string(&self.name)) + } + + fn check_string(s: &str) -> String { + std::str::from_utf8( + &s.as_bytes() + .iter() + .filter(|&&b| { + (b > 96 && b < 123) // small letters + || (b > 64 && b < 91) // big letters + || (b > 47 && b < 58) // numbers + || b == 45 // dash + || b == 95 // underscore + || b == 32 // whitespace + }) + .map(|&b| b) + .collect::>(), + ) + .unwrap() + .to_string() } pub fn snippet(&self) -> Arc { @@ -253,3 +272,28 @@ impl LeaderBoardEntry { self.place_updated = false; } } + +#[cfg(test)] +mod test { + + #[test] + fn test_string_replacement() { + let s_orig = "blaĆ¼"; + let s = super::LeaderBoardEntry::check_string(s_orig); + println!("{} {:?}", s_orig, s); + + for b in s.as_bytes() { + println!("{}", b) + } + + println!(); + + let s2_orig = "az AZ 09 # - _"; + let s2 = super::LeaderBoardEntry::check_string(s2_orig); + println!("{} {:?}", s2_orig, s2); + + for b in s2.as_bytes() { + println!("{}", *b); + } + } +} -- 2.45.2 From 3a463f2bec2b7c1680d6fba905590102de2ee9de Mon Sep 17 00:00:00 2001 From: hodasemi Date: Mon, 23 Jan 2023 07:21:52 +0100 Subject: [PATCH 2/6] Fix config loading --- .vscode/launch.json | 28 +++++++++++ src/lib.rs | 62 ++++++++++++++++++++----- src/overlay/elements/leaderboard/mod.rs | 2 +- src/overlay/mod.rs | 4 +- src/vk_layer/mod.rs | 28 ++--------- 5 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..98736cc --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug selected unit test", + "cargo": { + "args": [ + "test", + // "--no-run", + "test::${selectedText}" + ], + // "filter": { + // "name": "vk_layer_rs", + // "kind": "lib" + // } + }, + "cwd": "${workspaceFolder}", + "env": { + "RFACTOR_HUD_LOG": "1" + } + }, + ] +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 57198a2..74ac621 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub(crate) fn logging() -> bool { macro_rules! write_log { ($msg:expr) => { + println!("{}", $msg); if crate::logging() { crate::log($msg); } @@ -31,18 +32,25 @@ fn get_config(home: &str) -> OverlayConfig { let config_path = Path::new(&home).join(".config/rFactorHUD/config.json"); if config_path.exists() { - fs::read_to_string(&config_path) - .map(|s| { - serde_json::from_str(&s).unwrap_or({ - write_log!("failed to deserialize config file"); - OverlayConfig::new() - }) - }) - .unwrap_or({ - write_log!(format!("failed to open config file: {:?}", config_path)); + match fs::read_to_string(&config_path) { + Ok(s) => serde_json::from_str(&s).unwrap_or_else(|err| { + write_log!(format!( + "failed to deserialize config file from {} \n({:?})", + s, err + )); OverlayConfig::new() - }) + }), + Err(err) => { + write_log!(format!( + "failed to open config file: {:?} due to {:?}", + config_path, err + )); + OverlayConfig::new() + } + } } else { + write_log!("create parent dir structure"); + if let Err(err) = std::fs::create_dir_all(config_path.parent().unwrap()) { write_log!(format!("failed to create dirs for config file: {:?}", err)); } @@ -52,6 +60,8 @@ fn get_config(home: &str) -> OverlayConfig { match File::create(config_path) { Ok(mut file) => match serde_json::to_string_pretty(&config) { Ok(conf_str) => { + write_log!("create config file with default values"); + if let Err(err) = file.write_all(conf_str.as_bytes()) { write_log!(format!("failed to write to config file: {:?}", err)); } @@ -69,6 +79,31 @@ fn get_config(home: &str) -> OverlayConfig { } } +pub fn check_logging(home: &str) { + let log_enabled = match std::env::var("RFACTOR_HUD_LOG") { + Ok(var) => { + let i: u32 = var.parse().unwrap_or(0); + + i == 1 + } + Err(_) => false, + }; + + unsafe { LOG_ENABLED = log_enabled }; + + if logging() { + unsafe { + LOG_FILE = format!("{}/rf2_vk_hud.log", home); + } + + if let Err(_) = File::create(unsafe { &LOG_FILE }) {} + + write_log!(" =================================================================="); + write_log!(" ======================= New Negotiation =========================="); + write_log!(" =================================================================="); + } +} + pub fn log(msg: impl ToString) { assert!(logging()); @@ -83,11 +118,14 @@ pub fn log(msg: impl ToString) { #[cfg(test)] mod test { - use crate::get_config; + use crate::{check_logging, get_config}; #[test] fn config() { let home = std::env::var("HOME").unwrap(); - get_config(&home); + check_logging(&home); + let config = get_config(&home); + + println!("{:#?}", config); } } diff --git a/src/overlay/elements/leaderboard/mod.rs b/src/overlay/elements/leaderboard/mod.rs index e8d534b..c5c7bbc 100644 --- a/src/overlay/elements/leaderboard/mod.rs +++ b/src/overlay/elements/leaderboard/mod.rs @@ -22,7 +22,7 @@ use crate::write_log; use bg_generator::BackgroundGenerator; -#[derive(Default, Deserialize, Serialize, Clone, Copy)] +#[derive(Default, Deserialize, Serialize, Clone, Copy, Debug)] pub struct LeaderBoardConfig { first_board_color: [f32; 3], second_board_color: [f32; 3], diff --git a/src/overlay/mod.rs b/src/overlay/mod.rs index 9a69b52..392de04 100644 --- a/src/overlay/mod.rs +++ b/src/overlay/mod.rs @@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize}; pub trait UiOverlay: DataReceiver {} -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Debug)] pub struct UiSelectorConfig { pub enable_watermark: bool, @@ -45,7 +45,7 @@ impl UiSelectorConfig { } } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Debug)] pub struct OverlayConfig { pub ui_config: UiSelectorConfig, pub radar_config: RadarConfig, diff --git a/src/vk_layer/mod.rs b/src/vk_layer/mod.rs index 4240975..3338c50 100644 --- a/src/vk_layer/mod.rs +++ b/src/vk_layer/mod.rs @@ -2,47 +2,27 @@ mod enums; mod structs; mod vk_handles; +use crate::check_logging; use enums::*; use structs::*; use vk_handles::*; use vulkan_rs::prelude::*; -use std::{ffi::c_void, fs::File, mem, os::raw::c_char, ptr}; +use std::{ffi::c_void, mem, os::raw::c_char, ptr}; static mut ACQUIRE_NEXT_IMAGE: PFN_vkAcquireNextImageKHR = unsafe { mem::transmute(vkVoidFunction as *const c_void) }; -use crate::{get_config, logging, write_log, LOG_ENABLED, LOG_FILE, OVERLAY}; +use crate::{get_config, logging, write_log, OVERLAY}; #[no_mangle] #[allow(non_snake_case)] pub(crate) extern "C" fn vkNegotiateLoaderLayerInterfaceVersion( pVersionStruct: *mut VkNegotiateLayerInterface, ) -> VkResult { - let log_enabled = match std::env::var("RFACTOR_HUD_LOG") { - Ok(var) => { - let i: u32 = var.parse().unwrap_or(0); - - i == 1 - } - Err(_) => false, - }; - - unsafe { LOG_ENABLED = log_enabled }; - let home = std::env::var("HOME").unwrap(); - if logging() { - unsafe { - LOG_FILE = format!("{}/rf2_vk_hud.log", home); - } - - if let Err(_) = File::create(unsafe { &LOG_FILE }) {} - - write_log!(" =================================================================="); - write_log!(" ======================= New Negotiation =========================="); - write_log!(" =================================================================="); - } + check_logging(&home); unsafe { OVERLAY.set_config(get_config(&home)); -- 2.45.2 From ee75183765d2b1e1396b395cd7db16fbe56a5758 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Mon, 23 Jan 2023 09:14:53 +0100 Subject: [PATCH 3/6] Probable fix for time display --- .../elements/leaderboard/leaderboard_entry.rs | 92 +++++++++++-------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/src/overlay/elements/leaderboard/leaderboard_entry.rs b/src/overlay/elements/leaderboard/leaderboard_entry.rs index c809b44..e8fec60 100644 --- a/src/overlay/elements/leaderboard/leaderboard_entry.rs +++ b/src/overlay/elements/leaderboard/leaderboard_entry.rs @@ -164,40 +164,41 @@ impl LeaderBoardEntry { self.time_label.set_text("---") } - pub fn force_display_behind_leader(&mut self) -> Result<()> { - match self.behind { + fn split_minute(time: f64) -> (f64, f64) { + let full_minutes = (time / 60.0).floor(); + let remainder = time - (full_minutes * 60.0); + + (full_minutes, remainder) + } + + fn calculate_behind_leader(behind: BehindLeader) -> String { + match behind { BehindLeader::Time(time_behind) => { // check if we are leader if time_behind <= 0.0 { - self.time_label.set_text("---")?; + "---".to_string() } else { - let text = if time_behind > 60.0 { - let full_minutes = (self.best_lap / 60.0).floor(); - let remainder = self.best_lap - (full_minutes * 60.0); + if time_behind > 60.0 { + let (full_minutes, remainder) = Self::split_minute(time_behind); format!("+{:.0}:{:.0}", full_minutes, remainder) } else { format!("+{:.3}", time_behind) - }; - - self.time_label.set_text(text)?; + } } } BehindLeader::Laps(laps_behind) => { - self.time_label.set_text(format!("+{}", laps_behind))?; - } - BehindLeader::DNF => { - self.time_label.set_text("DNF")?; - } - BehindLeader::DSQ => { - self.time_label.set_text("DSQ")?; - } - BehindLeader::PITS => { - self.time_label.set_text("PIT")?; + format!("+{}", laps_behind) } + BehindLeader::DNF => "DNF".to_string(), + BehindLeader::DSQ => "DSQ".to_string(), + BehindLeader::PITS => "PIT".to_string(), } + } - Ok(()) + pub fn force_display_behind_leader(&self) -> Result<()> { + self.time_label + .set_text(Self::calculate_behind_leader(self.behind)) } pub fn update_time_behind_leader(&mut self, behind: BehindLeader) -> Result<()> { @@ -210,23 +211,23 @@ impl LeaderBoardEntry { Ok(()) } - pub fn force_display_best_lap(&mut self) -> Result<()> { - if self.best_lap <= 0.0 { - self.time_label.set_text("---")?; + fn calculuate_best_lap(best_lap: f64) -> String { + if best_lap <= 0.0 { + "---".to_string() } else { - let text = if self.best_lap > 60.0 { - let full_minutes = (self.best_lap / 60.0).floor(); - let remainder = self.best_lap - (full_minutes * 60.0); + if best_lap > 60.0 { + let (full_minutes, remainder) = Self::split_minute(best_lap); format!("{:.0}:{:.3}", full_minutes, remainder) } else { - format!("{:.3}", self.best_lap) - }; - - self.time_label.set_text(text)?; + format!("{:.3}", best_lap) + } } + } - Ok(()) + pub fn force_display_best_lap(&mut self) -> Result<()> { + self.time_label + .set_text(Self::calculuate_best_lap(self.best_lap)) } pub fn update_best_lap(&mut self, time: f64) -> Result<()> { @@ -239,19 +240,21 @@ impl LeaderBoardEntry { Ok(()) } - pub fn force_display_behind_next(&mut self) -> Result<()> { - let text = if self.time_behind_next <= 0.0 { + fn calculate_behind_next(behind_next: f64) -> String { + if behind_next <= 0.0 { "---".to_string() - } else if self.time_behind_next > 60.0 { - let full_minutes = (self.time_behind_next / 60.0).floor(); - let remainder = self.time_behind_next - (full_minutes * 60.0); + } else if behind_next > 60.0 { + let (full_minutes, remainder) = Self::split_minute(behind_next); - format!("+{:.0}:{:.3}", full_minutes, remainder) + format!("+{:.0}:{:.0}", full_minutes, remainder) } else { - format!("+{:.3}", self.time_behind_next) - }; + format!("+{:.3}", behind_next) + } + } - self.time_label.set_text(text) + pub fn force_display_behind_next(&mut self) -> Result<()> { + self.time_label + .set_text(Self::calculate_behind_next(self.time_behind_next)) } pub fn update_time_behind_next(&mut self, time: f64) -> Result<()> { @@ -275,6 +278,7 @@ impl LeaderBoardEntry { #[cfg(test)] mod test { + use super::{BehindLeader, LeaderBoardEntry}; #[test] fn test_string_replacement() { @@ -296,4 +300,12 @@ mod test { println!("{}", *b); } } + + #[test] + #[allow(unused)] + fn entry_display_tests() { + let behind_leader = LeaderBoardEntry::calculate_behind_leader(BehindLeader::Time(85.42)); + let behind_next = LeaderBoardEntry::calculate_behind_next(150.213423); + let best_lap = LeaderBoardEntry::calculuate_best_lap(97.23436); + } } -- 2.45.2 From 4238079409b54b26e01b763b8e735c92ac11cd4d Mon Sep 17 00:00:00 2001 From: hodasemi Date: Mon, 23 Jan 2023 18:34:04 +0100 Subject: [PATCH 4/6] Fit time into column --- src/overlay/elements/leaderboard/deltaboard_grid.xml | 2 +- src/overlay/elements/leaderboard/leaderboard_entry.xml | 8 ++++---- src/overlay/elements/leaderboard/leaderboard_grid.xml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/overlay/elements/leaderboard/deltaboard_grid.xml b/src/overlay/elements/leaderboard/deltaboard_grid.xml index 3cb0254..7934c2c 100644 --- a/src/overlay/elements/leaderboard/deltaboard_grid.xml +++ b/src/overlay/elements/leaderboard/deltaboard_grid.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/src/overlay/elements/leaderboard/leaderboard_entry.xml b/src/overlay/elements/leaderboard/leaderboard_entry.xml index 286ad0d..fd5493c 100644 --- a/src/overlay/elements/leaderboard/leaderboard_entry.xml +++ b/src/overlay/elements/leaderboard/leaderboard_entry.xml @@ -1,11 +1,11 @@ - + - + y_slot="0" x_size="9" text_color="black"> + \ No newline at end of file diff --git a/src/overlay/elements/leaderboard/leaderboard_grid.xml b/src/overlay/elements/leaderboard/leaderboard_grid.xml index 0c3b7a5..9eca1e9 100644 --- a/src/overlay/elements/leaderboard/leaderboard_grid.xml +++ b/src/overlay/elements/leaderboard/leaderboard_grid.xml @@ -1,6 +1,6 @@ - \ No newline at end of file -- 2.45.2 From f9112ea627445421a33408ebf756f90e0ed7d165 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Mon, 23 Jan 2023 19:41:51 +0100 Subject: [PATCH 5/6] Move resource files into their own dir --- font.png => resources/font.png | Bin {pkgbuild => resources/pkgbuild}/PKGBUILD | 2 +- {pkgbuild => resources/pkgbuild}/README.md | 0 .../rFactorOverlay.json | 0 src/overlay/mod.rs | 2 +- 5 files changed, 2 insertions(+), 2 deletions(-) rename font.png => resources/font.png (100%) rename {pkgbuild => resources/pkgbuild}/PKGBUILD (82%) rename {pkgbuild => resources/pkgbuild}/README.md (100%) rename rFactorOverlay.json => resources/rFactorOverlay.json (100%) diff --git a/font.png b/resources/font.png similarity index 100% rename from font.png rename to resources/font.png diff --git a/pkgbuild/PKGBUILD b/resources/pkgbuild/PKGBUILD similarity index 82% rename from pkgbuild/PKGBUILD rename to resources/pkgbuild/PKGBUILD index 890cef1..2b8f2f9 100644 --- a/pkgbuild/PKGBUILD +++ b/resources/pkgbuild/PKGBUILD @@ -25,5 +25,5 @@ package() { install -Dm755 ${_pkgbase}/target/release/libvk_layer_rs.so "${pkgdir}"/usr/lib/libvk_layer_rs.so # copy layer discovery info file - install -Dm644 ${_pkgbase}/rFactorOverlay.json "${pkgdir}"/usr/share/vulkan/implicit_layer.d/rFactorOverlay.json + install -Dm644 ${_pkgbase}/resources/rFactorOverlay.json "${pkgdir}"/usr/share/vulkan/implicit_layer.d/rFactorOverlay.json } diff --git a/pkgbuild/README.md b/resources/pkgbuild/README.md similarity index 100% rename from pkgbuild/README.md rename to resources/pkgbuild/README.md diff --git a/rFactorOverlay.json b/resources/rFactorOverlay.json similarity index 100% rename from rFactorOverlay.json rename to resources/rFactorOverlay.json diff --git a/src/overlay/mod.rs b/src/overlay/mod.rs index 392de04..e11e641 100644 --- a/src/overlay/mod.rs +++ b/src/overlay/mod.rs @@ -144,7 +144,7 @@ impl Overlay { // only font is used let mut create_info = GuiHandlerCreateInfo::default(); - create_info.font = Font::Bytes(include_bytes!("../../font.png")); + create_info.font = Font::Bytes(include_bytes!("../../resources/font.png")); // required to not crash create_info.resource_directory = AssetPath::from(""); -- 2.45.2 From 3c5aff8c4b554d7f821a0416e13d29d1a3034a22 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Mon, 23 Jan 2023 20:13:14 +0100 Subject: [PATCH 6/6] Update pkgbuild path in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3c1b4d..e3f2351 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ I would consider the following elements as working: # How to enable ### Archlinux based -Simply use the PKGBUILD from the pkgbuild directory ([How to use it](https://wiki.archlinux.org/title/Makepkg)) +Simply use the PKGBUILD from the resources/pkgbuild directory ([How to use it](https://wiki.archlinux.org/title/Makepkg)) ### Manual installation 1) Build this repository `cargo build --release` @@ -30,7 +30,7 @@ You need to have rFactor2 memory plugin shared file enabled ([rF2SharedMemoryMap ### Debugging -Add `RFACTOR_HUD_LOG=1` to the launch options of the game. Then a file log file will be created (`$HOME/rf2_vk_hud.log`). The logs may seem super random and they are super random, since I didn't have (or took) the time to unify my logging output. +Add `RFACTOR_HUD_LOG=1` to the launch options of the game. Then a file log file will be created (`$HOME/rf2_vk_hud.log`). The logs may seem super random and they are super random, since I didn't have (or took) the time to unify my logging output. I would not recommend to activate logging while playing a longer session, it can get quite big (about 15 minutes are roundabout 1 million lines). # Resources -- 2.45.2