Update
- Added AWP warning and sight-lines while scoped - Added Bomb timer Todo: cleanup
This commit is contained in:
parent
36013078ce
commit
d31c3f8ee5
42
src/comms.rs
42
src/comms.rs
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user