- Added AWP warning and sight-lines while scoped
- Added Bomb timer
Todo: cleanup
This commit is contained in:
Janek 2024-01-09 23:06:32 +01:00
parent 36013078ce
commit d31c3f8ee5
5 changed files with 242 additions and 13 deletions
src
comms.rs
dma
context
mod.rs
threaddata
webradar

@ -10,12 +10,18 @@ pub struct PlayerData {
player_type: PlayerType,
#[serde(rename = "hasBomb")]
has_bomb: bool
has_bomb: bool,
#[serde(rename = "hasAwp")]
has_awp: bool,
#[serde(rename = "isScoped")]
is_scoped: bool
}
impl PlayerData {
pub fn new(pos: Vec3, yaw: f32, player_type: PlayerType, has_bomb: bool) -> PlayerData {
PlayerData { pos, yaw, player_type, has_bomb }
pub fn new(pos: Vec3, yaw: f32, player_type: PlayerType, has_bomb: bool, has_awp: bool, is_scoped: bool) -> PlayerData {
PlayerData { pos, yaw, player_type, has_bomb, has_awp, is_scoped }
}
}
@ -44,6 +50,24 @@ pub struct RadarData {
freq: usize,
ingame: bool,
#[serde(rename = "bombPlanted")]
bomb_planted: bool,
#[serde(rename = "bombExploded")]
bomb_exploded: bool,
#[serde(rename = "bombBeingDefused")]
bomb_being_defused: bool,
#[serde(rename = "bombCanDefuse")]
bomb_can_defuse: bool,
#[serde(rename = "bombDefuseLength")]
bomb_defuse_length: f32,
#[serde(rename = "bombDefuseTimeleft")]
bomb_defuse_timeleft: f32,
#[serde(rename = "mapName")]
map_name: String,
@ -55,8 +79,8 @@ pub struct RadarData {
}
impl RadarData {
pub fn new(ingame: bool, map_name: String, player_data: Vec<EntityData>, freq: usize) -> RadarData {
RadarData { ingame, map_name, player_data, freq }
pub fn new(ingame: bool, map_name: String, player_data: Vec<EntityData>, freq: usize, bomb_planted: bool, bomb_cannot_defuse: bool, bomb_defuse_timeleft: f32, bomb_exploded: bool, bomb_being_defused: bool, bomb_defuse_length: f32) -> RadarData {
RadarData { ingame, map_name, player_data, freq, bomb_planted, bomb_can_defuse: bomb_cannot_defuse, bomb_defuse_timeleft, bomb_exploded, bomb_being_defused, bomb_defuse_length }
}
/// Returns empty RadarData, it's also the same data that gets sent to clients when not ingame
@ -65,7 +89,13 @@ impl RadarData {
ingame: false,
map_name: String::new(),
player_data: Vec::new(),
freq
freq,
bomb_planted: false,
bomb_can_defuse: false,
bomb_defuse_timeleft: 0.0,
bomb_exploded: false,
bomb_being_defused: false,
bomb_defuse_length: 0.0
}
}
}

@ -91,6 +91,8 @@ impl DmaCtx {
let mut yaw = 0f32;
let mut health = 0u32;
let mut team = 0i32;
let mut clipping_weapon = 0u64;
let mut is_scoped = 0u8;
{
let mut batcher = MemoryViewBatcher::new(&mut self.process);
@ -98,15 +100,29 @@ impl DmaCtx {
batcher.read_into(pawn + cs2dumper::client::C_CSPlayerPawnBase::m_angEyeAngles + 4, &mut yaw);
batcher.read_into(pawn + cs2dumper::client::C_BaseEntity::m_iHealth, &mut health);
batcher.read_into(controller + cs2dumper::client::C_BaseEntity::m_iTeamNum, &mut team);
batcher.read_into(pawn + cs2dumper::client::C_CSPlayerPawnBase::m_pClippingWeapon, &mut clipping_weapon);
batcher.read_into(pawn + cs2dumper::client::C_CSPlayerPawnBase::m_bIsScoped, &mut is_scoped);
}
let team = TeamID::from_i32(team);
let has_awp = {
let clipping_weapon: Address = clipping_weapon.into();
let items_def_idx_addr = clipping_weapon + cs2dumper::client::C_EconEntity::m_AttributeManager
+ cs2dumper::client::C_AttributeContainer::m_Item + cs2dumper::client::C_EconItemView::m_iItemDefinitionIndex;
let items_def_idx: i16 = self.process.read(items_def_idx_addr)?;
items_def_idx == 9
};
Ok(BatchedPlayerData {
pos,
yaw,
team,
health
health,
has_awp,
is_scoped: is_scoped != 0
})
}
@ -174,9 +190,12 @@ impl DmaCtx {
}
#[derive(Debug)]
pub struct BatchedPlayerData {
pub pos: Vec3,
pub yaw: f32,
pub team: Option<TeamID>,
pub health: u32,
pub has_awp: bool,
pub is_scoped: bool,
}

@ -54,6 +54,33 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
data.recheck_bomb_holder = true;
}
let bomb_defuse_timeleft: f32 = {
if data.bomb_planted && !data.bomb_exploded && !data.bomb_defused {
if let Some(bomb_stamp) = data.bomb_planted_stamp {
data.bomb_plant_timer - bomb_stamp.elapsed().as_secs_f32()
} else {
0.0
}
} else {
0.0
}
};
let bomb_can_defuse: bool = {
if data.bomb_planted && !data.bomb_exploded && !data.bomb_defused {
if let (Some(bomb_stamp), Some(defuse_stamp)) = (data.bomb_planted_stamp, data.bomb_defuse_stamp) {
let time_left = data.bomb_plant_timer - bomb_stamp.elapsed().as_secs_f32();
let defuse_left = data.bomb_defuse_length - defuse_stamp.elapsed().as_secs_f32();
time_left - defuse_left > 0.0
} else {
false
}
} else {
false
}
};
last_bomb_dropped = data.bomb_dropped;
last_bomb_planted = data.bomb_planted;
@ -109,7 +136,9 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
local_data.pos,
local_data.yaw,
PlayerType::Local,
has_bomb
has_bomb,
local_data.has_awp,
local_data.is_scoped
)
)
);
@ -156,7 +185,9 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
player_data.pos,
player_data.yaw,
player_type,
has_bomb
has_bomb,
player_data.has_awp,
player_data.is_scoped
)
)
);
@ -167,7 +198,13 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
true,
data.map.clone(),
entity_data,
freq
freq,
data.bomb_planted,
bomb_can_defuse,
bomb_defuse_timeleft,
data.bomb_exploded,
data.bomb_being_defused,
data.bomb_defuse_length
);
} else {
let mut radar = radar_data.write().await;

@ -1,5 +1,6 @@
use itertools::Itertools;
use memflow::{mem::MemoryView, types::Address};
use tokio::time::Instant;
use super::{context::DmaCtx, cs2dumper};
@ -24,6 +25,13 @@ pub struct CsData {
pub tick_count: i32,
pub bomb_dropped: bool,
pub bomb_planted: bool,
pub bomb_planted_stamp: Option<Instant>,
pub bomb_plant_timer: f32,
pub bomb_being_defused: bool,
pub bomb_defuse_stamp: Option<Instant>,
pub bomb_defuse_length: f32,
pub bomb_exploded: bool,
pub bomb_defused: bool,
pub highest_index: i32,
pub map: String
}
@ -129,6 +137,9 @@ impl CsData {
let mut bomb_dropped = 0u8;
let mut bomb_planted = 0u8;
let mut map_ptr = 0u64;
let mut bomb_being_defused = 0u8;
let mut bomb_exploded = 0u8;
let mut bomb_defused = 0u8;
{
// Globals
@ -159,11 +170,52 @@ impl CsData {
batcher.read_into(map_addr, &mut map_ptr);
}
{
let mut batcher = ctx.process.batcher();
if self.bomb_planted {
batcher.read_into(self.bomb + cs2dumper::client::C_PlantedC4::m_flTimerLength , &mut self.bomb_plant_timer);
batcher.read_into(self.bomb + cs2dumper::client::C_PlantedC4::m_bBombDefused, &mut bomb_defused);
batcher.read_into(self.bomb + cs2dumper::client::C_PlantedC4::m_flDefuseLength, &mut self.bomb_defuse_length);
batcher.read_into(self.bomb + cs2dumper::client::C_PlantedC4::m_bHasExploded, &mut bomb_exploded);
batcher.read_into(self.bomb + cs2dumper::client::C_PlantedC4::m_bBeingDefused, &mut bomb_being_defused);
drop(batcher);
if self.bomb_planted_stamp.is_none() && !self.bomb.is_null() {
self.bomb_planted_stamp = Some(Instant::now());
}
if self.bomb_being_defused {
if self.bomb_defuse_stamp.is_none() {
self.bomb_defuse_stamp = Some(Instant::now())
}
} else {
if self.bomb_defuse_stamp.is_some() {
self.bomb_defuse_stamp = None;
}
}
} else {
if self.bomb_planted_stamp.is_some() {
self.bomb_planted_stamp = None;
}
if self.bomb_defuse_stamp.is_some() {
self.bomb_defuse_stamp = None;
}
}
}
let map_string = ctx.process.read_char_string_n(map_ptr.into(), 32).unwrap_or(String::from("<empty>"));
self.map = map_string;
self.bomb_dropped = bomb_dropped != 0;
self.bomb_planted = bomb_planted != 0;
self.bomb_exploded = bomb_exploded != 0;
self.bomb_being_defused = bomb_being_defused != 0;
self.bomb_defused = bomb_defused != 0;
}
pub fn update_pointers(&mut self, ctx: &mut DmaCtx) {

@ -14,6 +14,7 @@ canvas = null
ctx = null
// radarflow specific
radarData = null
freq = 0
image = null
map = null
@ -170,11 +171,63 @@ function render() {
fillStyle,
data.Player.isDormant,
data.Player.hasBomb,
data.Player.yaw
data.Player.yaw,
data.Player.hasAwp,
data.Player.playerType,
data.Player.isScoped
)
}
});
}
if (radarData != null) {
if (radarData.bombPlanted && !radarData.bombExploded && radarData.bombDefuseTimeleft >= 0) {
let maxWidth = 1024-128-128;
let timeleft = radarData.bombDefuseTimeleft;
//let canDefuse = (timeleft - radarData.bombDefuseLength) > 0
// Base bar
ctx.fillStyle = "black"
ctx.fillRect(128, 16, maxWidth, 16)
// Bomb timer
if (radarData.bombBeingDefused) {
if (radarData.bombCanDefuse) {
ctx.fillStyle = teamColor
} else {
ctx.fillStyle = enemyColor
}
} else {
ctx.fillStyle = bombColor
}
ctx.fillRect(130, 18, (maxWidth-2) * (timeleft / 40), 12)
ctx.font = "24px Arial";
ctx.textAlign = "center"
ctx.textBaseline = "middle"
ctx.fillStyle = textColor
ctx.fillText(`${timeleft.toFixed(1)}s`, 1024/2, 28+24);
// Defuse time lines
ctx.strokeStyle = "black"
ctx.lineWidth = 2
// Kit defuse
ctx.beginPath()
ctx.moveTo(128 + (maxWidth * (5 / 40)), 16)
ctx.lineTo(128 + (maxWidth * (5 / 40)), 32)
ctx.stroke()
// Normal defuse
ctx.beginPath()
ctx.moveTo(130 + (maxWidth-2) * (10 / 40), 16)
ctx.lineTo(130 + (maxWidth-2) * (10 / 40), 32)
ctx.stroke()
}
}
} else {
if (websocket != null) {
ctx.font = "100px Arial";
@ -247,7 +300,7 @@ function drawBomb(pos, planted) {
}
}
function drawEntity(pos, fillStyle, dormant, hasBomb, yaw) {
function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, isScoped) {
if (map == null)
return
@ -272,12 +325,34 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw) {
ctx.fillText("?", pos.x, pos.y);
} else {
if (hasAwp) {
ctx.beginPath();
ctx.arc(pos.x, pos.y, circleRadius, 0, 2 * Math.PI);
ctx.fillStyle = "orange";
ctx.fill();
circleRadius -= 2;
}
// Draw circle
ctx.beginPath();
ctx.arc(pos.x, pos.y, circleRadius, 0, 2 * Math.PI);
ctx.fillStyle = fillStyle;
ctx.fill();
if (hasAwp && false) {
let style = "yellow"
if (playerType == "Enemy") {
style = "orange"
}
ctx.beginPath();
ctx.arc(pos.x, pos.y, circleRadius / 1.5, 0, 2 * Math.PI);
ctx.fillStyle = style;
ctx.fill();
}
if (hasBomb) {
ctx.beginPath();
ctx.arc(pos.x, pos.y, circleRadius / 2, 0, 2 * Math.PI);
@ -319,6 +394,22 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw) {
ctx.fillStyle = 'white'
ctx.fill();
if (isScoped) {
const lineOfSightX = arrowHeadX + 1024 * Math.cos(yaw * (Math.PI / 180))
const lineOfSightY = arrowHeadY - 1024 * Math.sin(yaw * (Math.PI / 180))
ctx.beginPath();
ctx.moveTo(arrowHeadX, arrowHeadY);
ctx.lineTo(lineOfSightX, lineOfSightY);
if (playerType == "Enemy")
ctx.strokeStyle = enemyColor
else
ctx.strokeStyle = teamColor
ctx.strokeWidth = 1;
ctx.stroke();
}
}
}
@ -367,7 +458,7 @@ function connect() {
console.log("[radarflow] Server had an unknown error")
} else {
let data = JSON.parse(event.data);
radarData = data;
freq = data.freq;
if (data.ingame == false) {