Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quality of Life Improvements: Bomb Info + Misc #64

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
9 changes: 3 additions & 6 deletions controller/src/enhancements/aim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::Context;
use valthrun_kernel_interface::MouseState;

use super::Enhancement;
use crate::RenderContext;

pub struct AntiAimPunsh {
mouse_sensitivity: f32,
Expand Down Expand Up @@ -88,11 +89,7 @@ impl Enhancement for AntiAimPunsh {
Ok(())
}

fn render(
&self,
_settings: &crate::settings::AppSettings,
_ui: &imgui::Ui,
_view: &crate::view::ViewController,
) {
fn render(&self, _ctx: RenderContext) {
/* We have nothing to render */
}
}
298 changes: 228 additions & 70 deletions controller/src/enhancements/bomb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ use std::ffi::CStr;

use anyhow::Context;
use cs2::CEntityIdentityEx;
use cs2_schema_generated::cs2::client::C_PlantedC4;
use cs2_schema_generated::cs2::client::{
CCSPlayer_ItemServices,
C_CSGameRulesProxy,
C_CSPlayerPawn,
C_PlantedC4,
};
use imgui::Condition;
use mint::Vector4;
use obfstr::obfstr;

use super::Enhancement;
use crate::{
utils::ImguiUiEx,
RenderContext,
UpdateContext,
};

Expand Down Expand Up @@ -46,15 +53,29 @@ pub enum C4State {

/// Bomb has been defused
Defused,

/// Bomb has been dropped
Dropped,
}

pub struct BombInfo {
/// Number of Counter-Terrorists with kit
any_kit: bool,

/// Local Team Identifier
local_team: u8,

/// Current State of Bomb
bomb_state: Option<C4Info>,
}

impl BombInfo {
pub fn new() -> Self {
Self { bomb_state: None }
Self {
any_kit: false,
local_team: 0,
bomb_state: None,
}
}

fn read_state(&self, ctx: &UpdateContext) -> anyhow::Result<Option<C4Info>> {
Expand All @@ -66,6 +87,31 @@ impl BombInfo {
.lookup(&entity_identity.entity_class_info()?)
.context("class name")?;

// Check if bomb is dropped
if class_name
.map(|name| name == "C_CSGameRulesProxy")
.unwrap_or(false)
{
/* The bomb is dropped. */
let rules_proxy = entity_identity
.entity_ptr::<C_CSGameRulesProxy>()?
.reference_schema()
.context("rules proxy missing")?;

let game_rules = rules_proxy
.m_pGameRules()?
.reference_schema()
.context("game rules missing")?;
();

if game_rules.m_bBombDropped().unwrap_or_default() {
return Ok(Some(C4Info {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does ensure, that C_CSGameRulesProxy always comes before a potential C_PlantedC4 entity? I'm not sure if or under what circumstances but this may lead to unexpected results.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the bomb is dropped it can't be planted.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should I do?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You first have to loop trough all entities in order to find the C_CSGameRulesProxy entity.
If found & bomb is dropped, then return C4Info with the dropped state.

If not, try to find the bomb entity and get a state from that :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats what Im already doing tho? @WolverinDEV

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for entity_identity in entities.iter() {
            let class_name = ctx
                .class_name_cache
                .lookup(&entity_identity.entity_class_info()?)
                .context("class name")?;

            // Check if bomb is dropped
            if class_name
                .map(|name| name == "C_CSGameRulesProxy")
                .unwrap_or(false)
            {
                /* The bomb is dropped. */
                let rules_proxy = entity_identity
                    .entity_ptr::<C_CSGameRulesProxy>()?
                    .reference_schema()
                    .context("rules proxy missing")?;

                let game_rules = rules_proxy
                    .m_pGameRules()?
                    .reference_schema()
                    .context("game rules missing")?;
                ();

                if game_rules.m_bBombDropped().unwrap_or_default() {
                    return Ok(Some(C4Info {
                        bomb_site: 0,
                        state: C4State::Dropped,
                    }));
                }
            }
            
            .....

bomb_site: 0,
state: C4State::Dropped,
}));
}
}

if !class_name
.map(|name| name == "C_PlantedC4")
.unwrap_or(false)
Expand Down Expand Up @@ -148,29 +194,63 @@ impl BombInfo {
}
}

/// % of the screens height
const PLAYER_AVATAR_TOP_OFFSET: f32 = 0.004;

/// % of the screens height
const PLAYER_AVATAR_SIZE: f32 = 0.05;

impl Enhancement for BombInfo {
fn update(&mut self, ctx: &crate::UpdateContext) -> anyhow::Result<()> {
fn update(&mut self, ctx: &UpdateContext) -> anyhow::Result<()> {
if !ctx.settings.bomb_timer {
return Ok(());
}

for entity_identity in ctx.cs2_entities.all_identities() {
let entity_class = ctx
.class_name_cache
.lookup(&entity_identity.entity_class_info()?)?;

if !entity_class
.map(|name| *name == "C_CSPlayerPawn")
.unwrap_or(false)
{
/* entity is not a player pawn */
continue;
}

let player_pawn = entity_identity
.entity_ptr::<C_CSPlayerPawn>()?
.reference_schema()
.context("missing player pawn")?;

let player_has_defuser = player_pawn
.m_pItemServices()?
.cast::<CCSPlayer_ItemServices>()
.reference_schema()?
.m_bHasDefuser()?;

if player_pawn.m_iHealth().unwrap_or(0) != 0 && player_has_defuser {
self.any_kit = true;
break;
}
}

let local_controller = ctx
.cs2_entities
.get_local_player_controller()?
.try_reference_schema()
.with_context(|| obfstr!("failed to read local player controller").to_string())?;

let local_controller = match local_controller {
Some(controller) => controller,
None => {
/* We're currently not connected */
return Ok(());
}
};

self.local_team = local_controller.m_iPendingTeamNum()?;
self.bomb_state = self.read_state(ctx)?;
Ok(())
}

fn render(
&self,
settings: &crate::settings::AppSettings,
ui: &imgui::Ui,
_view: &crate::view::ViewController,
) {
if !settings.bomb_timer {
fn render(&self, ctx: RenderContext) {
if !ctx.settings.bomb_timer {
return;
}

Expand All @@ -179,63 +259,141 @@ impl Enhancement for BombInfo {
None => return,
};

let group = ui.begin_group();
let app_visible = ctx.app.settings_visible;
let show_bg_game = ctx.settings.bomb_timer_decor || app_visible;
let show_bg_menu = show_bg_game && app_visible;

ctx.ui
.window(obfstr!("Bomb Info"))
.size([250.0, 125.0], Condition::Appearing)
// Disable all window decorations.
.resizable(show_bg_menu)
.collapsible(show_bg_menu)
.title_bar(show_bg_menu)
.draw_background(show_bg_game)
.movable(app_visible)
.mouse_inputs(app_visible)
.build(|| {
// Common Colors
let white = [1.0, 1.0, 1.0, 1.0]; // White

let mut orange = [1.0, 0.61, 0.11, 1.0]; // Orange
let mut green = [0.11, 0.79, 0.26, 1.0]; // Green
let mut red = [0.79, 0.11, 0.11, 1.0]; // Red

// Reset Colors
if !ctx.settings.bomb_timer_color {
orange = white;
green = white;
red = white;
}

let line_count = match &bomb_info.state {
C4State::Active { .. } => 3,
C4State::Defused | C4State::Detonated => 2,
};
let text_height = ui.text_line_height_with_spacing() * line_count as f32;

/* align to be on the right side after the players */
let offset_x = ui.io().display_size[0] * 1730.0 / 2560.0;
let offset_y = ui.io().display_size[1] * PLAYER_AVATAR_TOP_OFFSET;
let offset_y = offset_y
+ 0_f32.max((ui.io().display_size[1] * PLAYER_AVATAR_SIZE - text_height) / 2.0);

ui.set_cursor_pos([offset_x, offset_y]);
ui.text(&format!(
"Bomb planted {}",
if bomb_info.bomb_site == 0 { "A" } else { "B" }
));

match &bomb_info.state {
C4State::Active {
time_detonation,
defuse,
} => {
ui.set_cursor_pos_x(offset_x);
ui.text(&format!("Time: {:.3}", time_detonation));
if let Some(defuse) = defuse.as_ref() {
let color = if defuse.time_remaining > *time_detonation {
[0.79, 0.11, 0.11, 1.0]
// Helper Function
fn helper_text_color(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is not needed. You can use:

let text_color = if self.local_team == 2 {
  color_t
} else {
  color_ct
};

and instead use ctx.ui.text_colored(text_color, "My lovely text")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still pending

ctx: &RenderContext,
player_team: &u8,
color_t: impl Into<Vector4<f32>>,
text_t: &str,
color_ct: impl Into<Vector4<f32>>,
text_ct: &str,
) {
if matches!(&player_team, 2) {
// Terrorists
ctx.ui.text_colored(color_t, text_t)
} else {
[0.11, 0.79, 0.26, 1.0]
};

ui.set_cursor_pos_x(offset_x);
ui.text_colored(
color,
&format!(
"Defused in {:.3} by {}",
defuse.time_remaining, defuse.player_name
),
// Counter-Terrorists
ctx.ui.text_colored(color_ct, text_ct)
}
}

if !matches!(&bomb_info.state, C4State::Dropped) {
RemainingToast marked this conversation as resolved.
Show resolved Hide resolved
let plant_str = &format!(
"Bomb planted {}",
if bomb_info.bomb_site == 0 { "A" } else { "B" }
);
} else {
ui.set_cursor_pos_x(offset_x);
ui.text("Not defusing");

helper_text_color(&ctx, &self.local_team, green, plant_str, red, plant_str);
}
}
C4State::Defused => {
ui.set_cursor_pos_x(offset_x);
ui.text("Bomb has been defused");
}
C4State::Detonated => {
ui.set_cursor_pos_x(offset_x);
ui.text("Bomb has been detonated");
}
}

group.end();
match &bomb_info.state {
C4State::Active {
time_detonation,
defuse,
} => {
let ten_seconds = *time_detonation < 10f32;
let five_seconds = *time_detonation < 5f32;
let is_terrorist = matches!(&self.local_team, 2);

let mut boom_color = white; // white by default

if *&self.any_kit {
if is_terrorist {
boom_color = red;
if ten_seconds {
boom_color = orange;
}
if five_seconds {
boom_color = green;
}
} else {
boom_color = green;
if ten_seconds {
boom_color = orange;
}
if five_seconds {
boom_color = red;
}
}
} else if ten_seconds {
boom_color = if is_terrorist { green } else { red };
}

ctx.ui
.text_colored(boom_color, &format!("Time: {:.3}", time_detonation));

if let Some(defuse) = defuse.as_ref() {
let defuse_str = &format!(
"Defused in {:.3} by {}",
defuse.time_remaining, defuse.player_name
);

if defuse.time_remaining > *time_detonation {
helper_text_color(
&ctx,
&self.local_team,
green,
defuse_str,
red,
defuse_str,
);
} else {
helper_text_color(
&ctx,
&self.local_team,
red,
defuse_str,
green,
defuse_str,
);
};
} else {
let text = "Not being defused";
helper_text_color(&ctx, &self.local_team, green, text, red, text);
}
}
C4State::Defused => {
let text = "Bomb has been defused";
helper_text_color(&ctx, &self.local_team, red, text, green, text);
}
C4State::Detonated => {
let text = "Bomb has been detonated";
helper_text_color(&ctx, &self.local_team, green, text, red, text);
}
C4State::Dropped => {
let text = "Bomb has been dropped";
helper_text_color(&ctx, &self.local_team, red, text, orange, text);
}
}
});
}
}
4 changes: 2 additions & 2 deletions controller/src/enhancements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub trait Enhancement {
Ok(false)
}

fn render(&self, settings: &AppSettings, ui: &imgui::Ui, view: &ViewController);
fn render(&self, ctx: RenderContext);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still: Please pass RenderContext as reference: &RenderContext

fn render_debug_window(&mut self, _settings: &mut AppSettings, _ui: &imgui::Ui) {}
}

Expand All @@ -30,6 +30,6 @@ mod aim;
pub use aim::*;

use crate::{
view::ViewController,
RenderContext,
UpdateContext,
};