Money reveal + writing memory
This commit is contained in:
parent
d6719b0d54
commit
5f99e03b4c
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
/src/dma/cs2dumper/offsets_mod.rs
|
/src/dma/cs2dumper/offsets_mod.rs
|
||||||
/src/dma/cs2dumper/client_mod.rs
|
/src/dma/cs2dumper/client_mod.rs
|
||||||
/src/dma/cs2dumper/engine2_mod.rs
|
/src/dma/cs2dumper/engine2_mod.rs
|
||||||
|
dump.sh
|
||||||
|
@ -6,7 +6,7 @@ use memflow::plugins::Inventory;
|
|||||||
use crate::dma::Connector;
|
use crate::dma::Connector;
|
||||||
const PORT_RANGE: std::ops::RangeInclusive<usize> = 8000..=65535;
|
const PORT_RANGE: std::ops::RangeInclusive<usize> = 8000..=65535;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser, Clone)]
|
||||||
#[command(author, version = version(), about, long_about = None)]
|
#[command(author, version = version(), about, long_about = None)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
/// Specifies the connector type for DMA
|
/// Specifies the connector type for DMA
|
||||||
|
50
src/comms.rs
50
src/comms.rs
@ -51,6 +51,20 @@ pub enum EntityData {
|
|||||||
Bomb(BombData)
|
Bomb(BombData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct CheatOptions {
|
||||||
|
#[serde(rename = "revealMoney")]
|
||||||
|
pub reveal_money: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CheatOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
reveal_money: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RadarData {
|
pub struct RadarData {
|
||||||
freq: usize,
|
freq: usize,
|
||||||
@ -83,13 +97,30 @@ pub struct RadarData {
|
|||||||
#[serde(rename(serialize = "entityData"))]
|
#[serde(rename(serialize = "entityData"))]
|
||||||
player_data: Vec<EntityData>,
|
player_data: Vec<EntityData>,
|
||||||
|
|
||||||
//#[serde(rename(serialize = "localYaw"))]
|
#[serde(rename = "options")]
|
||||||
//local_yaw: f32,
|
options: CheatOptions,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
pub money_reveal_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RadarData {
|
impl RadarData {
|
||||||
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, bomb_defuse_end: f32) -> RadarData {
|
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, bomb_defuse_end: 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, bomb_defuse_end }
|
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,
|
||||||
|
bomb_defuse_end,
|
||||||
|
options: CheatOptions::default(),
|
||||||
|
money_reveal_enabled: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns empty RadarData, it's also the same data that gets sent to clients when not ingame
|
/// Returns empty RadarData, it's also the same data that gets sent to clients when not ingame
|
||||||
@ -105,9 +136,20 @@ impl RadarData {
|
|||||||
bomb_exploded: false,
|
bomb_exploded: false,
|
||||||
bomb_being_defused: false,
|
bomb_being_defused: false,
|
||||||
bomb_defuse_length: 0.0,
|
bomb_defuse_length: 0.0,
|
||||||
bomb_defuse_end: 0.0
|
bomb_defuse_end: 0.0,
|
||||||
|
options: CheatOptions::default(),
|
||||||
|
money_reveal_enabled: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_reveal_money(&mut self, value: bool) {
|
||||||
|
self.options.reveal_money = value;
|
||||||
|
self.money_reveal_enabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_reveal_money(&self) -> bool {
|
||||||
|
self.options.reveal_money
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for RadarData {}
|
unsafe impl Send for RadarData {}
|
||||||
|
@ -4,17 +4,28 @@ use memflow::{mem::MemoryView, os::Process, types::Address};
|
|||||||
|
|
||||||
use crate::{enums::PlayerType, comms::{EntityData, PlayerData, RadarData, ArcRwlockRadarData, BombData}};
|
use crate::{enums::PlayerType, comms::{EntityData, PlayerData, RadarData, ArcRwlockRadarData, BombData}};
|
||||||
|
|
||||||
|
use crate::money_reveal::MoneyReveal;
|
||||||
|
|
||||||
use self::{context::DmaCtx, threaddata::CsData};
|
use self::{context::DmaCtx, threaddata::CsData};
|
||||||
|
|
||||||
mod context;
|
pub mod context;
|
||||||
mod threaddata;
|
pub mod threaddata;
|
||||||
mod cs2dumper;
|
mod cs2dumper;
|
||||||
|
|
||||||
pub use context::Connector;
|
pub use context::Connector;
|
||||||
|
|
||||||
pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_device: String, skip_version: bool) -> anyhow::Result<()> {
|
pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_device: String, skip_version: bool) -> anyhow::Result<()> {
|
||||||
let mut ctx = DmaCtx::setup(connector, pcileech_device, skip_version)?;
|
let mut ctx = DmaCtx::setup(connector, pcileech_device, skip_version)?;
|
||||||
let mut data = CsData { recheck_bomb_holder: true, ..Default::default() };
|
let mut data = CsData {
|
||||||
|
recheck_bomb_holder: true,
|
||||||
|
money_reveal_enabled: false,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut money_reveal = MoneyReveal::new();
|
||||||
|
if let Err(e) = money_reveal.init(&mut ctx.process, &ctx.client_module) {
|
||||||
|
log::warn!("Failed to initialize money reveal: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
// For read timing
|
// For read timing
|
||||||
let mut last_bomb_dropped = false;
|
let mut last_bomb_dropped = false;
|
||||||
@ -47,6 +58,17 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
|
|||||||
|
|
||||||
data.update_common(&mut ctx);
|
data.update_common(&mut ctx);
|
||||||
|
|
||||||
|
{
|
||||||
|
let radar = radar_data.read().await;
|
||||||
|
if radar.money_reveal_enabled != data.money_reveal_enabled {
|
||||||
|
data.money_reveal_enabled = radar.money_reveal_enabled;
|
||||||
|
|
||||||
|
if let Err(e) = money_reveal.toggle(&mut ctx.process) {
|
||||||
|
log::warn!("Failed to toggle money reveal: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bomb update
|
// Bomb update
|
||||||
if (data.bomb_dropped && !last_bomb_dropped) || (data.bomb_planted && !last_bomb_planted) {
|
if (data.bomb_dropped && !last_bomb_dropped) || (data.bomb_planted && !last_bomb_planted) {
|
||||||
data.update_bomb(&mut ctx);
|
data.update_bomb(&mut ctx);
|
||||||
@ -247,9 +269,12 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
|
|||||||
data.bomb_defuse_length,
|
data.bomb_defuse_length,
|
||||||
bomb_defuse_end
|
bomb_defuse_end
|
||||||
);
|
);
|
||||||
|
|
||||||
|
radar.money_reveal_enabled = data.money_reveal_enabled;
|
||||||
} else {
|
} else {
|
||||||
let mut radar = radar_data.write().await;
|
let mut radar = radar_data.write().await;
|
||||||
*radar = RadarData::empty(freq);
|
*radar = RadarData::empty(freq);
|
||||||
|
radar.money_reveal_enabled = data.money_reveal_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_tick_count = data.tick_count;
|
last_tick_count = data.tick_count;
|
||||||
@ -264,5 +289,10 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
|
|||||||
thread::sleep(Duration::from_millis(1));
|
thread::sleep(Duration::from_millis(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cleanup_result = money_reveal.ensure_disabled(&mut ctx.process);
|
||||||
|
if let Err(e) = cleanup_result {
|
||||||
|
log::warn!("Failed to cleanup money reveal: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
@ -38,6 +38,7 @@ pub struct CsData {
|
|||||||
pub bomb_defuse_length: f32,
|
pub bomb_defuse_length: f32,
|
||||||
pub bomb_exploded: bool,
|
pub bomb_exploded: bool,
|
||||||
pub bomb_defused: bool,
|
pub bomb_defused: bool,
|
||||||
|
pub money_reveal_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
13
src/main.rs
13
src/main.rs
@ -13,6 +13,9 @@ mod comms;
|
|||||||
mod dma;
|
mod dma;
|
||||||
mod websocket;
|
mod websocket;
|
||||||
|
|
||||||
|
mod pattern;
|
||||||
|
mod money_reveal;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
let cli: Cli = Cli::parse();
|
let cli: Cli = Cli::parse();
|
||||||
@ -29,6 +32,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let radar_clone = radar_data.clone();
|
let radar_clone = radar_data.clone();
|
||||||
|
|
||||||
let dma_handle = tokio::spawn(async move {
|
let dma_handle = tokio::spawn(async move {
|
||||||
if let Err(err) = dma::run(radar_clone, cli.connector, cli.pcileech_device, cli.skip_version).await {
|
if let Err(err) = dma::run(radar_clone, cli.connector, cli.pcileech_device, cli.skip_version).await {
|
||||||
log::error!("Error in dma thread: [{}]", err.to_string());
|
log::error!("Error in dma thread: [{}]", err.to_string());
|
||||||
@ -37,16 +41,19 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let web_path = cli.web_path.clone();
|
||||||
|
let port = cli.port;
|
||||||
|
|
||||||
let _websocket_handle = tokio::spawn(async move {
|
let _websocket_handle = tokio::spawn(async move {
|
||||||
if let Ok(my_local_ip) = local_ip_address::local_ip() {
|
if let Ok(my_local_ip) = local_ip_address::local_ip() {
|
||||||
let address = format!("http://{}:{}", my_local_ip, cli.port);
|
let address = format!("http://{}:{}", my_local_ip, port);
|
||||||
println!("Launched webserver at {}", address);
|
println!("Launched webserver at {}", address);
|
||||||
} else {
|
} else {
|
||||||
let address = format!("http://0.0.0.0:{}", cli.port);
|
let address = format!("http://0.0.0.0:{}", port);
|
||||||
println!("launched webserver at {}", address);
|
println!("launched webserver at {}", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = websocket::run(cli.web_path, cli.port, radar_data).await {
|
if let Err(err) = websocket::run(web_path, port, radar_data).await {
|
||||||
log::error!("Error in ws server: [{}]", err.to_string());
|
log::error!("Error in ws server: [{}]", err.to_string());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
96
src/money_reveal.rs
Normal file
96
src/money_reveal.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use memflow::{mem::MemoryView, types::Address, os::ModuleInfo};
|
||||||
|
use crate::pattern::pattern_scan;
|
||||||
|
|
||||||
|
const BUF_SIZE: usize = 3;
|
||||||
|
|
||||||
|
pub struct MoneyReveal {
|
||||||
|
pub is_enabled: bool,
|
||||||
|
pub address: Option<Address>,
|
||||||
|
original_bytes: Option<[u8; BUF_SIZE]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MoneyReveal {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
is_enabled: false,
|
||||||
|
address: None,
|
||||||
|
original_bytes: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self, mem: &mut impl MemoryView, client_module: &ModuleInfo) -> anyhow::Result<()> {
|
||||||
|
self.address = self.find_function(mem, client_module)?;
|
||||||
|
log::info!("Money reveal function found at: {:?}", self.address);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle(&mut self, mem: &mut impl MemoryView) -> anyhow::Result<bool> {
|
||||||
|
if let Some(addr) = self.address {
|
||||||
|
if self.is_enabled {
|
||||||
|
if let Some(original) = self.original_bytes {
|
||||||
|
self.restore(mem, addr, original)?;
|
||||||
|
self.original_bytes = None;
|
||||||
|
self.is_enabled = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let original = self.patch(mem, addr)?;
|
||||||
|
self.original_bytes = Some(original);
|
||||||
|
self.is_enabled = true;
|
||||||
|
}
|
||||||
|
Ok(self.is_enabled)
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("Money reveal not initialized"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensure_disabled(&mut self, mem: &mut impl MemoryView) -> anyhow::Result<()> {
|
||||||
|
if self.is_enabled {
|
||||||
|
if let Some(addr) = self.address {
|
||||||
|
if let Some(original) = self.original_bytes {
|
||||||
|
self.restore(mem, addr, original)?;
|
||||||
|
self.is_enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_function(&self, mem: &mut impl MemoryView, module: &ModuleInfo) -> anyhow::Result<Option<Address>> {
|
||||||
|
let is_hltv = pattern_scan(
|
||||||
|
mem,
|
||||||
|
module,
|
||||||
|
"48 83 EC 28 48 8B 0D ?? ?? ?? ?? 48 8B 01 FF 90 ?? ?? ?? ?? 84 C0 75 0D"
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if is_hltv.is_none() {
|
||||||
|
Ok(pattern_scan(
|
||||||
|
mem,
|
||||||
|
module,
|
||||||
|
"B0 01 C3 28 48 8B 0D ?? ?? ?? ?? 48 8B 01 FF 90 ?? ?? ?? ?? 84 C0 75 0D"
|
||||||
|
)?)
|
||||||
|
} else {
|
||||||
|
Ok(is_hltv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patch(&self, mem: &mut impl MemoryView, location: Address) -> anyhow::Result<[u8; BUF_SIZE]> {
|
||||||
|
let mut original_buf = [0u8; BUF_SIZE];
|
||||||
|
mem.read_into(location, &mut original_buf)?;
|
||||||
|
|
||||||
|
let new_buf: [u8; BUF_SIZE] = [
|
||||||
|
0xB0, 0x01, // MOV AL,1
|
||||||
|
0xC3 // RET
|
||||||
|
];
|
||||||
|
|
||||||
|
log::debug!("Patching memory for money reveal");
|
||||||
|
mem.write(location, &new_buf)?;
|
||||||
|
|
||||||
|
Ok(original_buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore(&self, mem: &mut impl MemoryView, location: Address, original: [u8; BUF_SIZE]) -> anyhow::Result<()> {
|
||||||
|
log::debug!("Restoring memory for money reveal");
|
||||||
|
mem.write(location, &original)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
51
src/pattern.rs
Normal file
51
src/pattern.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
use std::io::Read;
|
||||||
|
use log::warn;
|
||||||
|
use memflow::{os::ModuleInfo, mem::MemoryView, types::Address};
|
||||||
|
|
||||||
|
fn pattern_to_bytes(pattern: String) -> Vec<Option<u8>> {
|
||||||
|
pattern.split(' ')
|
||||||
|
.fold(Vec::new(), |mut accum, str| {
|
||||||
|
if str == "??" {
|
||||||
|
accum.push(None);
|
||||||
|
} else {
|
||||||
|
let byte = u8::from_str_radix(str, 16).unwrap();
|
||||||
|
accum.push(Some(byte));
|
||||||
|
}
|
||||||
|
|
||||||
|
accum
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pattern_scan(mem: &mut impl MemoryView, module: &ModuleInfo, sig: &str) -> anyhow::Result<Option<Address>> {
|
||||||
|
let pattern_bytes = pattern_to_bytes(sig.to_owned());
|
||||||
|
let mut cursor = mem.cursor();
|
||||||
|
|
||||||
|
log::debug!("Searching \"{}\" for pattern: \"{}\"", module.name, sig);
|
||||||
|
|
||||||
|
for i in 0..module.size {
|
||||||
|
let mut found = true;
|
||||||
|
cursor.set_address(module.base + i);
|
||||||
|
|
||||||
|
let mut buf = vec![0u8; pattern_bytes.len()];
|
||||||
|
|
||||||
|
if let Err(_) = cursor.read(&mut buf) {
|
||||||
|
warn!("Encountered read error while scanning for pattern");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, byte) in buf.iter().enumerate() {
|
||||||
|
if let Some(pat_byte) = pattern_bytes[idx] {
|
||||||
|
if *byte != pat_byte {
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return Ok(Some(module.base + i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
@ -25,7 +25,8 @@ async fn ws_handler(ws: WebSocketUpgrade, State(state): State<AppState>) -> Resp
|
|||||||
async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
||||||
while let Some(msg) = socket.recv().await {
|
while let Some(msg) = socket.recv().await {
|
||||||
if let Ok(msg) = msg {
|
if let Ok(msg) = msg {
|
||||||
if msg == Message::Text("requestInfo".to_string()) {
|
if let Ok(text) = msg.to_text() {
|
||||||
|
if text == "requestInfo" {
|
||||||
let str = {
|
let str = {
|
||||||
let data = state.data_lock.read().await;
|
let data = state.data_lock.read().await;
|
||||||
|
|
||||||
@ -39,15 +40,28 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//println!("{str}");
|
|
||||||
|
|
||||||
if socket.send(Message::Text(str)).await.is_err() {
|
if socket.send(Message::Text(str)).await.is_err() {
|
||||||
// client disconnected
|
return;
|
||||||
|
}
|
||||||
|
} else if text == "toggleMoneyReveal" {
|
||||||
|
let new_value = {
|
||||||
|
let mut data = state.data_lock.write().await;
|
||||||
|
data.money_reveal_enabled = !data.money_reveal_enabled;
|
||||||
|
data.money_reveal_enabled
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = serde_json::json!({
|
||||||
|
"action": "toggleMoneyReveal",
|
||||||
|
"status": "success",
|
||||||
|
"enabled": new_value
|
||||||
|
});
|
||||||
|
|
||||||
|
if socket.send(Message::Text(response.to_string())).await.is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// client disconnected
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
<input type="checkbox" onclick="toggleGuns()" id="gunsCheck" name="guns"/>
|
<input type="checkbox" onclick="toggleGuns()" id="gunsCheck" name="guns"/>
|
||||||
<label for="gunsCheck">Weapons</label>
|
<label for="gunsCheck">Weapons</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" onclick="toggleMoneyReveal()" id="moneyReveal" name="money"/>
|
||||||
|
<label for="moneyReveal">Money Reveal (DANGEROUS!)</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
|
@ -652,10 +652,15 @@ function connect() {
|
|||||||
if (event.data == "error") {
|
if (event.data == "error") {
|
||||||
console.log("[radarflow] Server had an unknown error")
|
console.log("[radarflow] Server had an unknown error")
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
let data = JSON.parse(event.data);
|
let data = JSON.parse(event.data);
|
||||||
radarData = data;
|
radarData = data;
|
||||||
freq = data.freq;
|
freq = data.freq;
|
||||||
|
|
||||||
|
if (data.money_reveal_enabled !== undefined) {
|
||||||
|
document.getElementById("moneyReveal").checked = data.money_reveal_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.ingame == false) {
|
if (data.ingame == false) {
|
||||||
mapName = null
|
mapName = null
|
||||||
entityData = null
|
entityData = null
|
||||||
@ -674,6 +679,9 @@ function connect() {
|
|||||||
|
|
||||||
update = true
|
update = true
|
||||||
requestAnimationFrame(render);
|
requestAnimationFrame(render);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[radarflow] Error parsing server message:", e, event.data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -710,6 +718,7 @@ addEventListener("DOMContentLoaded", (e) => {
|
|||||||
document.getElementById("statsCheck").checked = true;
|
document.getElementById("statsCheck").checked = true;
|
||||||
document.getElementById("namesCheck").checked = true;
|
document.getElementById("namesCheck").checked = true;
|
||||||
document.getElementById("gunsCheck").checked = true;
|
document.getElementById("gunsCheck").checked = true;
|
||||||
|
document.getElementById("moneyReveal").checked = false;
|
||||||
|
|
||||||
canvas = document.getElementById('canvas');
|
canvas = document.getElementById('canvas');
|
||||||
canvas.width = 1024;
|
canvas.width = 1024;
|
||||||
@ -736,3 +745,9 @@ function toggleNames() {
|
|||||||
function toggleGuns() {
|
function toggleGuns() {
|
||||||
drawGuns = !drawGuns
|
drawGuns = !drawGuns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleMoneyReveal() {
|
||||||
|
if (websocket && websocket.readyState === WebSocket.OPEN) {
|
||||||
|
websocket.send("toggleMoneyReveal");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user