Merge pull request #54 from superyu1337/development
Merge 'development' into 'main'
This commit is contained in:
commit
02c3ac8dde
995
Cargo.lock
generated
995
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
37
Cargo.toml
37
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "radarflow"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
authors = ["Janek S <development@superyu.xyz"]
|
||||
edition = "2021"
|
||||
|
||||
@ -8,38 +8,39 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# memory
|
||||
memflow = "0.2.1"
|
||||
memflow = "0.2.3"
|
||||
memflow-native = { git = "https://github.com/memflow/memflow-native" }
|
||||
dataview = "1.0.1"
|
||||
|
||||
# logging
|
||||
log = "0.4.21"
|
||||
simple_logger = "4.3.3"
|
||||
log = "0.4.22"
|
||||
simple_logger = "5.0.0"
|
||||
|
||||
# error handling
|
||||
anyhow = "1.0.81"
|
||||
anyhow = "1.0.93"
|
||||
|
||||
# derive stuff
|
||||
enum-primitive-derive = "0.3.0"
|
||||
num-traits = "0.2.18"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.115"
|
||||
clap = { version = "4.5.4", features = ["derive", "string"] }
|
||||
num-traits = "0.2.19"
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde_json = "1.0.133"
|
||||
clap = { version = "4.5.21", features = ["derive", "string"] }
|
||||
|
||||
# tokio
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
|
||||
# networking
|
||||
axum = { version = "0.7.5", features = ["ws"] }
|
||||
tower-http = { version = "0.5.2", features = ["fs"] }
|
||||
tower = "0.4.13"
|
||||
local-ip-address = "0.6.1"
|
||||
axum = { version = "0.7.9", features = ["ws"] }
|
||||
tower-http = { version = "0.6.2", features = ["fs"] }
|
||||
tower = "0.5.1"
|
||||
local-ip-address = "0.6.3"
|
||||
|
||||
# other
|
||||
itertools = "0.12.1"
|
||||
itertools = "0.13.0"
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
reqwest = { version = "0.12.2", features = ["blocking"] }
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.115"
|
||||
vergen = { version = "8.3.1", features = ["build", "cargo", "git", "gitcl", "rustc", "si"] }
|
||||
reqwest = { version = "0.12.9", features = ["blocking"] }
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde_json = "1.0.133"
|
||||
vergen-gitcl = { version = "1.0.0", features = ["build", "cargo", "rustc",] }
|
||||
|
20
build.rs
20
build.rs
@ -1,7 +1,7 @@
|
||||
use std::error::Error;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vergen::EmitBuilder;
|
||||
use vergen_gitcl::{Emitter, GitclBuilder};
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
struct InfoJson {
|
||||
@ -36,29 +36,27 @@ fn build_number() -> Result<(), Box<dyn Error>> {
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
download(
|
||||
"https://raw.githubusercontent.com/a2x/cs2-dumper/main/output/client.dll.rs",
|
||||
"https://raw.githubusercontent.com/a2x/cs2-dumper/refs/heads/main/output/client_dll.rs",
|
||||
"./src/dma/cs2dumper/client_mod.rs"
|
||||
).expect("Failed to download build file \"client.dll.rs\"");
|
||||
|
||||
download(
|
||||
"https://raw.githubusercontent.com/a2x/cs2-dumper/main/output/offsets.rs",
|
||||
"https://raw.githubusercontent.com/a2x/cs2-dumper/refs/heads/main/output/offsets.rs",
|
||||
"./src/dma/cs2dumper/offsets_mod.rs"
|
||||
).expect("Failed to download build file \"offsets.rs\"");
|
||||
|
||||
download(
|
||||
"https://raw.githubusercontent.com/a2x/cs2-dumper/main/output/engine2.dll.rs",
|
||||
"https://raw.githubusercontent.com/a2x/cs2-dumper/refs/heads/main/output/engine2_dll.rs",
|
||||
"./src/dma/cs2dumper/engine2_mod.rs"
|
||||
).expect("Failed to download build file \"engine2.dll.rs\"");
|
||||
|
||||
build_number()?;
|
||||
|
||||
EmitBuilder::builder()
|
||||
.git_sha(true)
|
||||
.git_commit_date()
|
||||
.cargo_debug()
|
||||
.cargo_target_triple()
|
||||
.rustc_semver()
|
||||
.rustc_llvm_version()
|
||||
let gitcl = GitclBuilder::all_git()?;
|
||||
|
||||
|
||||
Emitter::new()
|
||||
.add_instructions(&gitcl)?
|
||||
.emit()?;
|
||||
|
||||
Ok(())
|
||||
|
10
src/cli.rs
10
src/cli.rs
@ -40,10 +40,16 @@ fn version() -> String {
|
||||
let commit_date = option_env!("VERGEN_GIT_COMMIT_DATE").unwrap_or("unknown");
|
||||
let avail_cons = {
|
||||
let inventory = Inventory::scan();
|
||||
inventory.available_connectors().join(", ")
|
||||
let mut avail = inventory.available_connectors();
|
||||
avail.push("native".into());
|
||||
avail.join(", ")
|
||||
};
|
||||
|
||||
format!(" {pkg_ver} (rev {git_hash})\nCommit Date: {commit_date}\nAvailable Connectors: {avail_cons}")
|
||||
format!(
|
||||
"{pkg_ver} (rev {git_hash})\n\
|
||||
Commit Date: {commit_date}\n\
|
||||
Available Connectors: {avail_cons}\n"
|
||||
)
|
||||
}
|
||||
|
||||
fn port_in_range(s: &str) -> Result<u16, String> {
|
||||
|
@ -3,7 +3,8 @@ pub enum Connector {
|
||||
#[default]
|
||||
Qemu,
|
||||
Kvm,
|
||||
Pcileech
|
||||
Pcileech,
|
||||
Native
|
||||
}
|
||||
|
||||
impl ToString for Connector {
|
||||
@ -12,6 +13,7 @@ impl ToString for Connector {
|
||||
Connector::Qemu => String::from("qemu"),
|
||||
Connector::Kvm => String::from("kvm"),
|
||||
Connector::Pcileech => String::from("pcileech"),
|
||||
Connector::Native => String::from("native"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use num_traits::FromPrimitive;
|
||||
|
||||
use crate::{structs::Vec3, enums::TeamID};
|
||||
|
||||
use super::cs2dumper;
|
||||
use super::{cs2dumper, threaddata::CsData};
|
||||
|
||||
pub struct DmaCtx {
|
||||
pub process: IntoProcessInstanceArcBox<'static>,
|
||||
@ -46,11 +46,13 @@ impl DmaCtx {
|
||||
.args(connector_args)
|
||||
.os("win32")
|
||||
.build()?
|
||||
} else {
|
||||
} else if connector != Connector::Native {
|
||||
inventory.builder()
|
||||
.connector(&connector.to_string())
|
||||
.os("win32")
|
||||
.build()?
|
||||
.connector(&connector.to_string())
|
||||
.os("win32")
|
||||
.build()?
|
||||
} else {
|
||||
memflow_native::create_os(&Default::default(), Default::default())?
|
||||
}
|
||||
};
|
||||
|
||||
@ -103,7 +105,7 @@ impl DmaCtx {
|
||||
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);
|
||||
batcher.read_into(pawn + cs2dumper::client::C_CSPlayerPawn::m_bIsScoped, &mut is_scoped);
|
||||
}
|
||||
|
||||
let team = TeamID::from_i32(team);
|
||||
@ -144,41 +146,101 @@ impl DmaCtx {
|
||||
Ok(is_controller)
|
||||
}
|
||||
|
||||
// Todo: Optimize this function: find another way to do this
|
||||
pub fn has_c4(&mut self, pawn: Address, entity_list: Address) -> anyhow::Result<bool> {
|
||||
let mut has_c4 = false;
|
||||
let wep_services = self.process.read_addr64(pawn + cs2dumper::client::C_BasePlayerPawn::m_pWeaponServices)?;
|
||||
let wep_count: i32 = self.process.read(wep_services + cs2dumper::client::CPlayer_WeaponServices::m_hMyWeapons)?;
|
||||
let wep_base = self.process.read_addr64(wep_services + cs2dumper::client::CPlayer_WeaponServices::m_hMyWeapons + 0x8)?;
|
||||
pub fn get_c4_holder(&mut self, pawns: Vec<Address>, entity_list: Address, csdata: &CsData) -> Option<Address> {
|
||||
|
||||
for wep_idx in 0..wep_count {
|
||||
let handle: i32 = self.process.read(wep_base + wep_idx * 0x4)?;
|
||||
if handle == -1 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let list_entry = self.process.read_addr64(entity_list + 0x8 * ((handle & 0x7FFF) >> 9) + 16)?;
|
||||
if let Some(wep_ptr) = {
|
||||
if list_entry.is_null() || !list_entry.is_valid() {
|
||||
None
|
||||
} else {
|
||||
let ptr = self.process.read_addr64(list_entry + 120 * (handle & 0x1FF))?;
|
||||
Some(ptr)
|
||||
}
|
||||
} {
|
||||
let wep_data = self.process.read_addr64(wep_ptr + cs2dumper::client::C_BaseEntity::m_nSubclassID + 0x8)?;
|
||||
let id: i32 = self.process.read(wep_data + cs2dumper::client::CCSWeaponBaseVData::m_WeaponType)?;
|
||||
|
||||
if id == 7 {
|
||||
has_c4 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if csdata.bomb_dropped || csdata.bomb_planted {
|
||||
return None;
|
||||
}
|
||||
|
||||
Ok(has_c4)
|
||||
}
|
||||
// (pawn, wep_services, wep_count, wep_base)
|
||||
let mut data_vec: Vec<(Address, u64, i32, u64)> = pawns
|
||||
.into_iter()
|
||||
.map(|pawn| (pawn, 0u64, 0i32, 0u64))
|
||||
.collect();
|
||||
|
||||
// Get wep_services
|
||||
let mut batcher = self.process.batcher();
|
||||
data_vec.iter_mut().for_each(|(pawn, wep_services, _, _)| {
|
||||
batcher.read_into(*pawn + cs2dumper::client::C_BasePlayerPawn::m_pWeaponServices, wep_services);
|
||||
});
|
||||
drop(batcher);
|
||||
|
||||
// Get wep_count and wep_base
|
||||
let mut batcher = self.process.batcher();
|
||||
data_vec.iter_mut().for_each(|(_, wep_services, wep_count, wep_base)| {
|
||||
batcher.read_into((*wep_services + cs2dumper::client::CPlayer_WeaponServices::m_hMyWeapons as u64).into(), wep_count);
|
||||
batcher.read_into((*wep_services + cs2dumper::client::CPlayer_WeaponServices::m_hMyWeapons as u64 + 0x8).into() , wep_base);
|
||||
});
|
||||
drop(batcher);
|
||||
|
||||
// Rebuild data vec
|
||||
// Vec<(pawn, wep_base, Vec<(buff, buff2)>)>
|
||||
let mut data_vec: Vec<(Address, u64, Vec<(u64, i32)>)> = data_vec
|
||||
.into_iter()
|
||||
.map(|(pawn, _, wep_count, wep_base)| {
|
||||
let weps = (0..wep_count).into_iter().map(|idx| (0u64, idx)).collect();
|
||||
(pawn, wep_base, weps)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Get handle
|
||||
let mut batcher = self.process.batcher();
|
||||
data_vec.iter_mut().for_each(|(_, wep_base, wep_data_vec)| {
|
||||
wep_data_vec.iter_mut().for_each(|(_, idx)| {
|
||||
let b: Address = (*wep_base).into();
|
||||
batcher.read_into(b + * idx * 0x4, idx);
|
||||
});
|
||||
});
|
||||
drop(batcher);
|
||||
|
||||
// Get list entry
|
||||
let mut batcher = self.process.batcher();
|
||||
data_vec.iter_mut().for_each(|(_, _, wep_data_vec)| {
|
||||
wep_data_vec.iter_mut().for_each(|(list_entry, handle)| {
|
||||
batcher.read_into(entity_list + 0x8 * ((*handle & 0x7FFF) >> 9) + 16, list_entry);
|
||||
});
|
||||
});
|
||||
drop(batcher);
|
||||
|
||||
// Get wep ptr
|
||||
let mut batcher = self.process.batcher();
|
||||
data_vec.iter_mut().for_each(|(_, _, wep_data_vec)| {
|
||||
wep_data_vec.iter_mut().for_each(|(list_entry, handle)| {
|
||||
let le: Address = (*list_entry).into();
|
||||
batcher.read_into(le + 120 * (*handle & 0x1FF), list_entry);
|
||||
});
|
||||
});
|
||||
drop(batcher);
|
||||
|
||||
// Get wep data
|
||||
let mut batcher = self.process.batcher();
|
||||
data_vec.iter_mut().for_each(|(_, _, wep_data_vec)| {
|
||||
wep_data_vec.iter_mut().for_each(|(wep_ptr, _)| {
|
||||
let b: Address = (*wep_ptr).into();
|
||||
batcher.read_into(b + cs2dumper::client::C_BaseEntity::m_nSubclassID + 0x8, wep_ptr);
|
||||
});
|
||||
});
|
||||
drop(batcher);
|
||||
|
||||
// Get wep id
|
||||
let mut batcher = self.process.batcher();
|
||||
data_vec.iter_mut().for_each(|(_, _, wep_data_vec)| {
|
||||
wep_data_vec.iter_mut().for_each(|(wep_data, id)| {
|
||||
let b: Address = (*wep_data).into();
|
||||
batcher.read_into(b + cs2dumper::client::CCSWeaponBaseVData::m_WeaponType, id);
|
||||
});
|
||||
});
|
||||
drop(batcher);
|
||||
|
||||
let holder = data_vec.into_iter().find(|(_, _, wep_data_vec)| {
|
||||
wep_data_vec.iter().find(|(_, id)| { *id == 7 }).is_some()
|
||||
});
|
||||
|
||||
match holder {
|
||||
Some((addr, _, _)) => Some(addr),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::{thread, time::{Duration, Instant}};
|
||||
|
||||
use memflow::{os::Process, types::Address, mem::MemoryView};
|
||||
use memflow::{mem::MemoryView, os::Process, types::Address};
|
||||
|
||||
use crate::{enums::{TeamID, PlayerType}, comms::{EntityData, PlayerData, RadarData, ArcRwlockRadarData, BombData}};
|
||||
use crate::{enums::PlayerType, comms::{EntityData, PlayerData, RadarData, ArcRwlockRadarData, BombData}};
|
||||
|
||||
use self::{context::DmaCtx, threaddata::CsData};
|
||||
|
||||
@ -19,6 +19,8 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
|
||||
// For read timing
|
||||
let mut last_bomb_dropped = false;
|
||||
let mut last_bomb_planted = false;
|
||||
let mut last_freeze_period = false;
|
||||
let mut last_round_start_count = 0u8;
|
||||
let mut last_tick_count = 0;
|
||||
let mut last_big_read = Instant::now();
|
||||
|
||||
@ -50,10 +52,37 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
|
||||
data.update_bomb(&mut ctx);
|
||||
}
|
||||
|
||||
if !data.bomb_dropped && last_bomb_dropped && !data.bomb_planted {
|
||||
if data.bomb_dropped != last_bomb_dropped || data.bomb_planted != last_bomb_planted {
|
||||
log::debug!("Bomb holder recheck due to bomb status");
|
||||
data.recheck_bomb_holder = true;
|
||||
}
|
||||
|
||||
if last_freeze_period != data.freeze_period {
|
||||
log::debug!("Bomb holder recheck due to freeze time");
|
||||
data.recheck_bomb_holder = true;
|
||||
}
|
||||
|
||||
if last_round_start_count != data.round_start_count {
|
||||
log::debug!("Bomb holder recheck due to round start");
|
||||
data.recheck_bomb_holder = true;
|
||||
}
|
||||
|
||||
last_freeze_period = data.freeze_period;
|
||||
last_round_start_count = data.round_start_count;
|
||||
|
||||
if data.recheck_bomb_holder {
|
||||
let mut pawns: Vec<Address> = data.players
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(_, pawn)| pawn)
|
||||
.collect();
|
||||
|
||||
pawns.push(data.local_pawn.into());
|
||||
|
||||
data.bomb_holder = ctx.get_c4_holder(pawns, data.entity_list.into(), &data);
|
||||
data.recheck_bomb_holder = false;
|
||||
}
|
||||
|
||||
let bomb_defuse_timeleft: f32 = {
|
||||
if data.bomb_planted && !data.bomb_exploded && !data.bomb_defused {
|
||||
if let Some(bomb_stamp) = data.bomb_planted_stamp {
|
||||
@ -123,23 +152,9 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
|
||||
).unwrap();
|
||||
|
||||
if local_data.health > 0 {
|
||||
let has_bomb = {
|
||||
if data.bomb_planted || data.bomb_dropped {
|
||||
false
|
||||
} else if data.recheck_bomb_holder {
|
||||
if local_data.team == Some(TeamID::T) && !data.bomb_dropped && !data.bomb_planted {
|
||||
let is_holder = ctx.has_c4(
|
||||
data.local_pawn.into(), data.entity_list.into()
|
||||
).unwrap_or(false);
|
||||
|
||||
if is_holder {
|
||||
data.bomb_holder = data.local.into();
|
||||
data.recheck_bomb_holder = false;
|
||||
}
|
||||
|
||||
is_holder
|
||||
} else { false }
|
||||
} else { Address::from(data.local) == data.bomb_holder }
|
||||
let has_bomb = match data.bomb_holder {
|
||||
Some(bh) => data.local_pawn == bh.to_umem(),
|
||||
None => false,
|
||||
};
|
||||
|
||||
entity_data.push(
|
||||
@ -164,21 +179,9 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
|
||||
continue;
|
||||
}
|
||||
|
||||
let has_bomb = {
|
||||
if data.bomb_planted {
|
||||
false
|
||||
} else if data.recheck_bomb_holder {
|
||||
if player_data.team == Some(TeamID::T) && !data.bomb_dropped && !data.bomb_planted {
|
||||
let is_holder = ctx.has_c4(*pawn, data.entity_list.into()).unwrap_or(false);
|
||||
|
||||
if is_holder {
|
||||
data.bomb_holder = *controller;
|
||||
data.recheck_bomb_holder = false;
|
||||
}
|
||||
|
||||
is_holder
|
||||
} else { false }
|
||||
} else { *controller == data.bomb_holder }
|
||||
let has_bomb = match data.bomb_holder {
|
||||
Some(bh) => *pawn == bh,
|
||||
None => false,
|
||||
};
|
||||
|
||||
let player_type = {
|
||||
|
@ -9,7 +9,7 @@ pub struct CsData {
|
||||
// Entities
|
||||
pub players: Vec<(Address, Address)>,
|
||||
pub bomb: Address,
|
||||
pub bomb_holder: Address,
|
||||
pub bomb_holder: Option<Address>,
|
||||
pub recheck_bomb_holder: bool,
|
||||
|
||||
// Pointers
|
||||
@ -21,8 +21,14 @@ pub struct CsData {
|
||||
// Common
|
||||
pub local: u64,
|
||||
pub local_pawn: u64,
|
||||
pub is_dead: bool,
|
||||
// pub is_dead: bool, // TODO: Why is this here?
|
||||
pub tick_count: i32,
|
||||
pub freeze_period: bool,
|
||||
pub round_start_count: u8,
|
||||
pub highest_index: i32,
|
||||
pub map: String,
|
||||
|
||||
// Bomb
|
||||
pub bomb_dropped: bool,
|
||||
pub bomb_planted: bool,
|
||||
pub bomb_planted_stamp: Option<Instant>,
|
||||
@ -32,8 +38,6 @@ pub struct CsData {
|
||||
pub bomb_defuse_length: f32,
|
||||
pub bomb_exploded: bool,
|
||||
pub bomb_defused: bool,
|
||||
pub highest_index: i32,
|
||||
pub map: String
|
||||
}
|
||||
|
||||
|
||||
@ -161,7 +165,7 @@ impl CsData {
|
||||
let mut bomb_being_defused = 0u8;
|
||||
let mut bomb_exploded = 0u8;
|
||||
let mut bomb_defused = 0u8;
|
||||
|
||||
let mut freeze_period = 0u8;
|
||||
{
|
||||
// Globals
|
||||
let tick_count_addr = (self.globals + 0x40).into();
|
||||
@ -170,9 +174,11 @@ impl CsData {
|
||||
// Gamerules
|
||||
let bomb_dropped_addr = (self.gamerules + cs2dumper::client::C_CSGameRules::m_bBombDropped as u64).into();
|
||||
let bomb_planted_addr = (self.gamerules + cs2dumper::client::C_CSGameRules::m_bBombPlanted as u64).into();
|
||||
let total_rounds_addr = (self.gamerules + cs2dumper::client::C_CSGameRules::m_bFreezePeriod as u64).into();
|
||||
let round_start_count_addr = (self.gamerules + cs2dumper::client::C_CSGameRules::m_nRoundStartCount as u64).into();
|
||||
|
||||
// Game Entity System
|
||||
let highest_index_addr = (self.game_ent_sys + cs2dumper::offsets::client_dll::dwGameEntitySystem_getHighestEntityIndex as u64).into();
|
||||
let highest_index_addr = (self.game_ent_sys + cs2dumper::offsets::client_dll::dwGameEntitySystem_highestEntityIndex as u64).into();
|
||||
|
||||
let mut batcher = ctx.process.batcher();
|
||||
batcher.read_into(
|
||||
@ -187,6 +193,8 @@ impl CsData {
|
||||
batcher.read_into(tick_count_addr, &mut self.tick_count);
|
||||
batcher.read_into(bomb_dropped_addr, &mut bomb_dropped);
|
||||
batcher.read_into(bomb_planted_addr, &mut bomb_planted);
|
||||
batcher.read_into(total_rounds_addr, &mut freeze_period);
|
||||
batcher.read_into(round_start_count_addr, &mut self.round_start_count);
|
||||
batcher.read_into(highest_index_addr, &mut self.highest_index);
|
||||
batcher.read_into(map_addr, &mut map_ptr);
|
||||
}
|
||||
@ -229,7 +237,7 @@ impl CsData {
|
||||
}
|
||||
|
||||
|
||||
let map_string = ctx.process.read_char_string_n(map_ptr.into(), 32).unwrap_or(String::from("<empty>"));
|
||||
let map_string = ctx.process.read_utf8_lossy(map_ptr.into(), 32).unwrap_or(String::from("<empty>"));
|
||||
|
||||
self.map = map_string;
|
||||
self.bomb_dropped = bomb_dropped != 0;
|
||||
@ -237,6 +245,7 @@ impl CsData {
|
||||
self.bomb_exploded = bomb_exploded != 0;
|
||||
self.bomb_being_defused = bomb_being_defused != 0;
|
||||
self.bomb_defused = bomb_defused != 0;
|
||||
self.freeze_period = freeze_period != 0;
|
||||
}
|
||||
|
||||
pub fn update_pointers(&mut self, ctx: &mut DmaCtx) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user