├── .gitignore ├── Cargo.toml └── src ├── entry └── mod.rs ├── interfaces ├── baseclient.rs ├── engineclient.rs ├── entitylist.rs ├── functions.rs ├── globals.rs ├── mod.rs ├── modelinfo.rs ├── netvarengine.rs ├── panelinterface.rs ├── traceengine.rs └── types.rs ├── lib.rs ├── maths ├── functions.rs ├── mod.rs └── vector.rs ├── memory ├── functions.rs └── mod.rs ├── script_engine ├── aimbot.rs ├── bhop.rs ├── mod.rs └── modulesys.rs └── structs ├── clientclass.rs ├── clientclassid.rs ├── cmdbutton.rs ├── cusercmd.rs ├── entity.rs ├── entityflags.rs ├── entityteam.rs ├── global.rs ├── item_definition_indices.rs ├── mod.rs ├── paneltype.rs ├── recvprop.rs ├── studio.rs ├── traceflags.rs └── tracestructs.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.vs 3 | /Cargo.lock 4 | /.idea -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-csgo" 3 | version = "0.1.0" 4 | authors = ["Balen "] 5 | edition = "2018" 6 | 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [profile.release] 12 | lto = true 13 | 14 | 15 | [dependencies] 16 | winapi = {version = "0.3.9", features = ["minwindef", "libloaderapi", "winnt", "windef", "processthreadsapi", "consoleapi", "winuser"]} 17 | vtables = { git = "https://github.com/not-wlan/vtables.git", rev = "8abc814" } 18 | vtables_derive = { git = "https://github.com/balenamiaa/vtables_derive.git", rev = "53b982a" } 19 | netvars = { git = "https://github.com/balenamiaa/netvars.git", rev = "cd72756" } 20 | once_cell = "1.4.0" 21 | detour = "0.7.1" 22 | fnv = "1.0.7" 23 | bitflags = "1.2.1" 24 | lazy_static = "1.4.0" 25 | rlua = "0.17.0" -------------------------------------------------------------------------------- /src/entry/mod.rs: -------------------------------------------------------------------------------- 1 | use detour::static_detour; 2 | use std::os::raw::{c_float, c_void}; 3 | use winapi::shared::minwindef::HINSTANCE; 4 | 5 | use winapi::um::libloaderapi::{DisableThreadLibraryCalls, FreeLibraryAndExitThread}; 6 | 7 | use crate::interfaces; 8 | use crate::interfaces::{EngineClient, EntityList, PanelInterface}; 9 | use crate::memory; 10 | use crate::script_engine::ScriptEngine; 11 | use crate::structs::{CUserCMD, PanelType}; 12 | use winapi::um::consoleapi::AllocConsole; 13 | 14 | const LUA_SCRIPTS_DIR: &'static str = "C:/CSScripts/"; 15 | 16 | type FnCreateMove = unsafe extern "stdcall" fn(c_float, *mut CUserCMD) -> bool; 17 | type FnPaintTraverse = 18 | unsafe extern "thiscall" fn(&'static PanelInterface, usize, bool, bool) -> (); 19 | 20 | static_detour! { 21 | static CreateMoveHook: unsafe extern "stdcall" fn(c_float, *mut CUserCMD) -> bool; 22 | static PaintTraverseHook: unsafe extern "thiscall" fn(&'static PanelInterface, usize, bool, bool) -> (); 23 | } 24 | 25 | fn createmove_detour(input_sample_frametime: f32, cmd: *mut CUserCMD) -> bool { 26 | let ret_value: bool = unsafe { CreateMoveHook.call(input_sample_frametime, cmd) }; 27 | 28 | unsafe { 29 | let local_ptr = 30 | EntityList::get().entity_ptr_from_index(EngineClient::get().local_player_index()); 31 | if !local_ptr.is_null() { 32 | *interfaces::LOCAL_PLAYER_PTR.lock().unwrap() = local_ptr as usize; 33 | } 34 | } 35 | 36 | ScriptEngine::global().set_localplayer(); 37 | ScriptEngine::global().update_entities(); 38 | 39 | ScriptEngine::global() 40 | .fire_post_createmove(unsafe { std::mem::transmute(cmd) }, input_sample_frametime); 41 | 42 | ret_value 43 | } 44 | 45 | fn painttraverse_detour( 46 | _this: &PanelInterface, 47 | panel_id: usize, 48 | force_repaint: bool, 49 | allow_force: bool, 50 | ) { 51 | use std::hash::Hasher; 52 | 53 | fn hash(name: &str) -> u64 { 54 | let mut panel_name_hasher = fnv::FnvHasher::with_key(0x811C9DC5); 55 | panel_name_hasher.write(name.as_bytes()); 56 | panel_name_hasher.finish() 57 | } 58 | 59 | let ret_value = unsafe { 60 | PaintTraverseHook.call(PanelInterface::get(), panel_id, force_repaint, allow_force) 61 | }; 62 | let d = PanelInterface::get().get_panel_name(panel_id); 63 | let panel_name = unsafe { 64 | std::ffi::CStr::from_ptr(d) 65 | .to_str() 66 | .unwrap_or(Default::default()) 67 | }; 68 | 69 | if hash("MatSystemTopPanel") == hash(panel_name) { 70 | ScriptEngine::global().fire_painttraverse(PanelType::MatSystemTop(panel_id)); 71 | } 72 | 73 | ret_value 74 | } 75 | 76 | pub unsafe fn on_attach(dll_module: HINSTANCE) -> () { 77 | DisableThreadLibraryCalls(dll_module); 78 | let sync_dll_module = dll_module as usize; 79 | 80 | std::thread::spawn(move || { 81 | std::panic::catch_unwind(|| { 82 | AllocConsole(); 83 | interfaces::initialize(); 84 | 85 | let clientmode = { 86 | let temp1 = memory::get_virtual_raw( 87 | interfaces::BaseClient::get().vtable as *const c_void, 88 | 10, 89 | ) as usize; 90 | ((temp1 + 5) as *const *const *const c_void).read().read() 91 | }; 92 | 93 | let create_move_target: FnCreateMove = std::mem::transmute(memory::get_virtual_raw( 94 | (clientmode as *const *const c_void).read(), 95 | 24, 96 | )); 97 | let paint_traverse_target: FnPaintTraverse = std::mem::transmute( 98 | memory::get_virtual_raw(PanelInterface::get().vtable as *const c_void, 41), 99 | ); 100 | 101 | CreateMoveHook 102 | .initialize(create_move_target, createmove_detour) 103 | .expect("Couldn't initialize hook for createmove") 104 | .enable() 105 | .expect("Couldn't enable hook for createmove!"); 106 | PaintTraverseHook 107 | .initialize(paint_traverse_target, painttraverse_detour) 108 | .expect("Couldn't initialize hook for painttraverse") 109 | .enable() 110 | .expect("Couldn't enable hook for painttraverse!"); 111 | 112 | ScriptEngine::global().initialize(LUA_SCRIPTS_DIR); 113 | }) 114 | .unwrap_or_else(|_data| { 115 | FreeLibraryAndExitThread(sync_dll_module as HINSTANCE, 1213); 116 | }); 117 | }); 118 | } 119 | 120 | pub fn on_detach() -> () {} 121 | -------------------------------------------------------------------------------- /src/interfaces/baseclient.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::OnceCell; 2 | use vtables::VTable; 3 | use vtables_derive::has_vtable; 4 | use vtables_derive::virtual_index; 5 | use vtables_derive::VTable; 6 | 7 | use crate::structs::ClientClass; 8 | 9 | pub static INSTANCE: OnceCell = OnceCell::new(); 10 | 11 | #[has_vtable] 12 | #[derive(VTable, Debug)] 13 | pub struct BaseClient { 14 | pub vtable: usize, 15 | } 16 | 17 | impl BaseClient { 18 | #[virtual_index(8)] 19 | pub fn get_client_class_tail(&self) -> &'static mut ClientClass {} 20 | 21 | pub fn get() -> &'static Self { 22 | let ptr = INSTANCE 23 | .get() 24 | .expect("Tried to get BaseClient without initializing it first"); 25 | 26 | unsafe { std::mem::transmute::(*ptr) } 27 | } 28 | } 29 | 30 | pub struct ClientClassIterator { 31 | current: &'static mut ClientClass, 32 | } 33 | 34 | impl Default for ClientClassIterator { 35 | fn default() -> Self { 36 | Self { 37 | current: BaseClient::get().get_client_class_tail(), 38 | } 39 | } 40 | } 41 | 42 | impl Iterator for ClientClassIterator { 43 | type Item = &'static mut ClientClass; 44 | 45 | fn next(&mut self) -> Option { 46 | let next = self.current.next; 47 | 48 | if next.is_null() { 49 | None 50 | } else { 51 | self.current = unsafe { std::mem::transmute(next) }; 52 | 53 | Some(unsafe { std::mem::transmute(next) }) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/interfaces/engineclient.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::OnceCell; 2 | 3 | use crate::structs::EntityIndex; 4 | use vtables::VTable; 5 | use vtables_derive::has_vtable; 6 | use vtables_derive::virtual_index; 7 | use vtables_derive::VTable; 8 | 9 | pub static INSTANCE: OnceCell = OnceCell::new(); 10 | 11 | #[has_vtable] 12 | #[derive(VTable, Debug)] 13 | pub struct EngineClient { 14 | pub vtable: usize, 15 | } 16 | 17 | impl EngineClient { 18 | #[virtual_index(26)] 19 | pub fn in_game(&self) -> bool {} 20 | 21 | #[virtual_index(12)] 22 | pub fn local_player_index(&self) -> EntityIndex {} 23 | 24 | #[virtual_index(5)] 25 | pub fn get_screensize(&self, width: *mut i32, height: *mut i32) {} 26 | 27 | pub fn get() -> &'static Self { 28 | let ptr = INSTANCE 29 | .get() 30 | .expect("Tried to get EngineClient without initializing it first"); 31 | 32 | unsafe { std::mem::transmute::(*ptr) } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/interfaces/entitylist.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::OnceCell; 2 | 3 | use vtables::VTable; 4 | use vtables_derive::has_vtable; 5 | use vtables_derive::virtual_index; 6 | use vtables_derive::VTable; 7 | 8 | use crate::structs::{EntityHandle, EntityIndex}; 9 | use std::ffi::c_void; 10 | 11 | pub static INSTANCE: OnceCell = OnceCell::new(); 12 | 13 | #[has_vtable] 14 | #[derive(VTable, Debug)] 15 | pub struct EntityList { 16 | pub vtable: usize, 17 | } 18 | 19 | impl EntityList { 20 | #[virtual_index(6)] 21 | pub fn highest_entity_index(&self) -> usize {} 22 | 23 | #[virtual_index(4)] 24 | pub fn entity_ptr_from_handle(&self, handle: EntityHandle) -> *mut c_void {} 25 | 26 | #[virtual_index(3)] 27 | pub fn entity_ptr_from_index(&self, index: EntityIndex) -> *mut c_void {} 28 | 29 | pub fn get() -> &'static Self { 30 | let ptr = INSTANCE 31 | .get() 32 | .expect("Tried to get EntityList without initializing it first"); 33 | 34 | unsafe { std::mem::transmute::(*ptr) } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/interfaces/functions.rs: -------------------------------------------------------------------------------- 1 | use crate::memory::get_module_handle; 2 | 3 | pub fn create_interface(module_name: &str, interface_name: &str) -> *mut std::os::raw::c_void { 4 | use super::types::CreateInterfaceFn; 5 | use std::ffi::CString; 6 | 7 | unsafe { 8 | let cstr_interface_name = CString::new(interface_name).unwrap(); 9 | 10 | let module = get_module_handle(module_name); 11 | let function_ptr = winapi::um::libloaderapi::GetProcAddress( 12 | module as *mut _, 13 | CString::new("CreateInterface").unwrap().as_ptr(), 14 | ); 15 | 16 | let function: CreateInterfaceFn = std::mem::transmute::<_, CreateInterfaceFn>(function_ptr); 17 | let interface_ptr = function(cstr_interface_name.as_ptr(), std::ptr::null_mut()) 18 | as *mut std::os::raw::c_void; 19 | 20 | if interface_ptr.is_null() { 21 | panic!( 22 | "Failed to get interface for {} in module {}", 23 | interface_name, module_name 24 | ); 25 | } 26 | 27 | interface_ptr 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/interfaces/globals.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::OnceCell; 2 | 3 | use crate::structs::EntityIndex; 4 | use vtables::VTable; 5 | use vtables_derive::has_vtable; 6 | use vtables_derive::virtual_index; 7 | use vtables_derive::VTable; 8 | 9 | pub static INSTANCE: OnceCell = OnceCell::new(); 10 | 11 | #[repr(C)] 12 | pub struct Globals { 13 | pub real_time: f32, 14 | pub frame_coutn: isize, 15 | pub absolute_frametime: f32, 16 | pub absolute_frame_starttime: f32, 17 | pub curtime: f32, 18 | pub frametme: f32, 19 | pub max_client: usize, 20 | pub tick_count: usize, 21 | pub inv_tickspersecond: f32, 22 | pub interpolation_factor: f32, 23 | pub sim_ticks_this_frame: usize, 24 | pub network_protocol: isize, 25 | pub p_savedata: usize, 26 | pub is_client: bool, 27 | pub is_remote_client: bool, 28 | pub timestamp_networking_base: isize, 29 | pub timestamp_randomize_window: isize, 30 | } 31 | 32 | impl Globals { 33 | pub fn get() -> &'static Self { 34 | let ptr = INSTANCE 35 | .get() 36 | .expect("Tried to get Globals without initializing it first"); 37 | 38 | unsafe { std::mem::transmute::(*ptr) } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/interfaces/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::memory::get_virtual_raw; 2 | pub use baseclient::{BaseClient, ClientClassIterator}; 3 | pub use engineclient::EngineClient; 4 | pub use entitylist::EntityList; 5 | pub use globals::Globals; 6 | pub use modelinfo::ModelInfo; 7 | pub use netvarengine::{get_offset, NetvarEngine}; 8 | use once_cell::sync::{Lazy, OnceCell}; 9 | pub use panelinterface::PanelInterface; 10 | use std::sync::Mutex; 11 | pub use traceengine::TraceEngine; 12 | 13 | mod baseclient; 14 | mod engineclient; 15 | mod entitylist; 16 | mod functions; 17 | mod globals; 18 | mod modelinfo; 19 | mod netvarengine; 20 | mod panelinterface; 21 | mod traceengine; 22 | mod types; 23 | 24 | pub static LOCAL_PLAYER_PTR: Lazy> = Lazy::new(|| Mutex::new(0)); 25 | 26 | pub fn initialize() { 27 | engineclient::INSTANCE 28 | .set(functions::create_interface("engine.dll", "VEngineClient014") as usize) 29 | .expect("Failed to create EngineClient interface"); 30 | 31 | baseclient::INSTANCE 32 | .set(functions::create_interface("client.dll", "VClient018") as usize) 33 | .expect("Failed to create BaseClient interface"); 34 | 35 | panelinterface::INSTANCE 36 | .set(functions::create_interface("vgui2.dll", "VGUI_Panel009") as usize) 37 | .expect("Failed to create PanelInterface interface"); 38 | 39 | entitylist::INSTANCE 40 | .set(functions::create_interface("client.dll", "VClientEntityList003") as usize) 41 | .expect("Failed to create EntityList interface"); 42 | 43 | traceengine::INSTANCE 44 | .set(functions::create_interface("engine.dll", "EngineTraceClient004") as usize) 45 | .expect("Failed to create TraceEngine interface"); 46 | 47 | modelinfo::INSTANCE 48 | .set(functions::create_interface("engine.dll", "VModelInfoClient004") as usize) 49 | .expect("Failed to create ModelInfo interface"); 50 | 51 | globals::INSTANCE 52 | .set(unsafe { 53 | ((get_virtual_raw(BaseClient::get().vtable as *const std::ffi::c_void, 11) as *const i8) 54 | .offset(10) as *const *const usize) 55 | .read() 56 | .read() 57 | }) 58 | .expect("Failed to create Globals interface"); 59 | 60 | netvarengine::INSTANCE 61 | .set(Default::default()) 62 | .expect("Failed to create NetvarEngine interface"); 63 | } 64 | -------------------------------------------------------------------------------- /src/interfaces/modelinfo.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::OnceCell; 2 | 3 | use crate::structs::{EntityModel, StudioHdr}; 4 | use vtables::VTable; 5 | use vtables_derive::has_vtable; 6 | use vtables_derive::virtual_index; 7 | use vtables_derive::VTable; 8 | 9 | pub static INSTANCE: OnceCell = OnceCell::new(); 10 | 11 | #[has_vtable] 12 | #[derive(VTable, Debug)] 13 | pub struct ModelInfo { 14 | pub vtable: usize, 15 | } 16 | 17 | impl ModelInfo { 18 | #[virtual_index(32)] 19 | fn __studio_model(&self, model: *const EntityModel) -> *mut StudioHdr {} 20 | 21 | #[virtual_index(32)] 22 | pub fn studio_model(&self, model: &'static EntityModel) -> Option<&'static mut StudioHdr> { 23 | let ptr = self.__studio_model(model); 24 | if ptr.is_null() { 25 | None 26 | } else { 27 | Some(ptr as &'static mut StudioHdr) 28 | } 29 | } 30 | 31 | pub fn get() -> &'static Self { 32 | let ptr = INSTANCE 33 | .get() 34 | .expect("Tried to get ModelInfo without initializing it first"); 35 | 36 | unsafe { std::mem::transmute::(*ptr) } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/interfaces/netvarengine.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use std::collections::HashMap; 3 | use std::ffi::CStr; 4 | use std::sync::{Arc, Mutex, MutexGuard}; 5 | 6 | use crate::interfaces::{BaseClient, ClientClassIterator}; 7 | use crate::structs::{CRecvProp, ClientClass}; 8 | use crate::structs::{CRecvTable, EPropType}; 9 | 10 | use once_cell::sync::OnceCell; 11 | 12 | use crate::memory::{get_module_handle, pattern_scan}; 13 | use crate::structs::EntityIndex; 14 | 15 | pub static INSTANCE: OnceCell = OnceCell::new(); 16 | 17 | #[derive(Debug)] 18 | pub struct NetvarEngine { 19 | pub netvars: HashMap, 20 | pub tables: Vec<&'static mut CRecvTable>, 21 | } 22 | 23 | impl Default for NetvarEngine { 24 | fn default() -> Self { 25 | let mut ret = Self { 26 | netvars: HashMap::new(), 27 | tables: Vec::new(), 28 | }; 29 | 30 | ret.initialize(); 31 | 32 | ret 33 | } 34 | } 35 | 36 | impl NetvarEngine { 37 | unsafe fn store_props( 38 | &mut self, 39 | group_name: String, 40 | recv_table: &'static mut CRecvTable, 41 | child_offset: usize, 42 | ) { 43 | for idx in 0..recv_table.n_props { 44 | let prop = recv_table.p_props.add(idx); 45 | 46 | if !prop.is_null() { 47 | let prop: &'static mut CRecvProp = std::mem::transmute(prop); 48 | let child = prop.data_table; 49 | 50 | if !child.is_null() { 51 | let child: &'static mut CRecvTable = std::mem::transmute(child); 52 | 53 | if child.n_props > 0 { 54 | self.store_props(group_name.clone(), child, prop.offset as usize); 55 | } 56 | } 57 | 58 | let var_name = CStr::from_ptr(prop.prop_name).to_str().unwrap().to_owned(); 59 | 60 | let formatted = format!("{}->{}", group_name, var_name); 61 | 62 | if !self.netvars.contains_key(&var_name) 63 | && (prop.prop_type == EPropType::Int 64 | || prop.prop_type == EPropType::Vec 65 | || prop.prop_type == EPropType::VecXY 66 | || prop.prop_type == EPropType::String 67 | || prop.prop_type == EPropType::Float) 68 | { 69 | self.netvars.insert( 70 | formatted.to_owned(), 71 | prop.offset as usize + child_offset as usize, 72 | ); 73 | } 74 | } 75 | } 76 | } 77 | 78 | fn initialize(&mut self) { 79 | self.tables.clear(); 80 | for client_class in ClientClassIterator::default() { 81 | let recv_table = client_class.recv_table; 82 | 83 | if !recv_table.is_null() { 84 | unsafe { 85 | let recv_table_0: &mut CRecvTable = std::mem::transmute(recv_table); // TODO: Yuck. Implement this in a less uglier way, please. 86 | let recv_table_1: &mut CRecvTable = std::mem::transmute(recv_table); // TODO: Yuck. Implement this in a less uglier way, please. 87 | // Sorry, rustc. ^,^ 88 | 89 | self.tables.push(recv_table_0); 90 | 91 | let table_name = CStr::from_ptr(recv_table_1.table_name) 92 | .to_str() 93 | .unwrap() 94 | .to_owned(); 95 | 96 | self.store_props(table_name, recv_table_1, 0); 97 | } 98 | } 99 | } 100 | 101 | self.netvars 102 | .insert("CustomTable->Dormancy".to_owned(), 0xED); 103 | unsafe { 104 | self.netvars.insert( 105 | "CustomTable->InReload".to_owned(), 106 | pattern_scan( 107 | get_module_handle("client.dll") as *mut _, 108 | "C6 87 ? ? ? ? ? 8B 06 8B CE FF 90", 109 | ) as usize, 110 | ); 111 | } 112 | } 113 | 114 | //I'd rather provide a static public wrapper than expose this because of the netvars_derive proc macro's limitation; 115 | fn get_offset(&self, table: &str, netvar: &str) -> usize { 116 | let pair = format!("{}->{}", table, netvar); 117 | 118 | if self.netvars.contains_key(&pair) { 119 | *self.netvars.get(&pair).unwrap() 120 | } else { 121 | usize::default() 122 | } 123 | } 124 | 125 | pub fn get() -> &'static NetvarEngine { 126 | INSTANCE 127 | .get() 128 | .expect("Tried to get NetvarEngine without initializing it first") 129 | } 130 | } 131 | 132 | pub fn get_offset(table: &str, netvar: &str) -> usize { 133 | NetvarEngine::get().get_offset(table, netvar) 134 | } 135 | -------------------------------------------------------------------------------- /src/interfaces/panelinterface.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::OnceCell; 2 | use std::os::raw::c_char; 3 | use vtables::VTable; 4 | use vtables_derive::has_vtable; 5 | use vtables_derive::virtual_index; 6 | use vtables_derive::VTable; 7 | 8 | pub static INSTANCE: OnceCell = OnceCell::new(); 9 | 10 | #[has_vtable] 11 | #[derive(VTable, Debug)] 12 | pub struct PanelInterface { 13 | pub vtable: usize, 14 | } 15 | 16 | impl PanelInterface { 17 | #[virtual_index(36)] 18 | pub fn get_panel_name(&self, panel_id: usize) -> *const c_char {} 19 | 20 | pub fn get() -> &'static Self { 21 | let ptr = INSTANCE 22 | .get() 23 | .expect("Tried to get PanelInterface without initializing it first"); 24 | 25 | unsafe { std::mem::transmute::(*ptr) } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/interfaces/traceengine.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::OnceCell; 2 | 3 | use crate::structs::{Entity, EntityIndex, Ray, Trace, TraceContent, TraceFilterTrait, TraceType}; 4 | use vtables::VTable; 5 | use vtables_derive::has_vtable; 6 | use vtables_derive::virtual_index; 7 | use vtables_derive::VTable; 8 | 9 | pub static INSTANCE: OnceCell = OnceCell::new(); 10 | 11 | #[has_vtable] 12 | #[derive(VTable, Debug)] 13 | pub struct TraceEngine { 14 | pub vtable: usize, 15 | } 16 | 17 | impl TraceEngine { 18 | #[virtual_index(5)] 19 | pub fn trace_ray( 20 | &self, 21 | ray: &Ray, 22 | mask: TraceContent, 23 | filter: &T, 24 | trace: &Trace, 25 | ) { 26 | } 27 | 28 | pub fn get() -> &'static Self { 29 | let ptr = INSTANCE 30 | .get() 31 | .expect("Tried to get TraceEngine without initializing it first"); 32 | 33 | unsafe { std::mem::transmute::(*ptr) } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/interfaces/types.rs: -------------------------------------------------------------------------------- 1 | use winapi::ctypes::{c_char, c_int, c_void}; 2 | 3 | pub type CreateInterfaceFn = 4 | unsafe extern "cdecl" fn(name: *const c_char, return_code: *const c_int) -> *mut c_void; 5 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(clamp)] 2 | #![feature(abi_thiscall)] 3 | #![feature(const_generics)] 4 | #![feature(const_fn)] 5 | 6 | use winapi::shared::minwindef; 7 | use winapi::shared::minwindef::{BOOL, DWORD, HINSTANCE, LPVOID}; 8 | 9 | mod entry; 10 | mod interfaces; 11 | mod maths; 12 | mod memory; 13 | mod script_engine; 14 | mod structs; 15 | 16 | #[no_mangle] 17 | #[allow(non_snake_case, unused_variables)] 18 | unsafe extern "system" fn DllMain( 19 | dll_module: HINSTANCE, 20 | call_reason: DWORD, 21 | reserved: LPVOID, 22 | ) -> BOOL { 23 | const DLL_PROCESS_ATTACH: DWORD = 1; 24 | const DLL_PROCESS_DETACH: DWORD = 0; 25 | 26 | match call_reason { 27 | DLL_PROCESS_ATTACH => entry::on_attach(dll_module), 28 | DLL_PROCESS_DETACH => entry::on_detach(), 29 | _ => (), 30 | } 31 | 32 | minwindef::TRUE 33 | } 34 | -------------------------------------------------------------------------------- /src/maths/functions.rs: -------------------------------------------------------------------------------- 1 | use super::vector::Vector; 2 | use std::ops::{Div, Mul}; 3 | 4 | pub fn calc_angle(src: Vector, target: Vector) -> Vector { 5 | use std::f32::consts::PI; 6 | let delta = target - src; 7 | 8 | *Vector::new( 9 | -delta.z.atan2(delta.nullify_z().len()), 10 | { 11 | let yaw = delta.y.atan2(delta.x); 12 | if delta.y < 0e0 { 13 | yaw + 2e0 * PI 14 | } else { 15 | yaw 16 | } 17 | }, 18 | 0e0, 19 | ) 20 | .normalize_yaw_cs() 21 | .to_degrees() 22 | } 23 | 24 | pub fn get_fov + Copy>(src: Vector, target: Vector, r: Tx) -> f32 { 25 | let mut delta = target - src; 26 | delta.normalize_yaw_cs(); 27 | 28 | Vector::new( 29 | delta.x.to_radians().abs().sin().mul(r.into()), 30 | delta.y.to_radians().abs().sin().mul(r.into()), 31 | 0e0, 32 | ) 33 | .len() 34 | } 35 | 36 | pub fn compensate_velocity + Copy>( 37 | src: Vector, 38 | rel_velocity: Vector, 39 | r: Tx, 40 | ) -> Vector { 41 | src + rel_velocity / r.into() 42 | } 43 | 44 | pub fn smooth_angle + Copy>( 45 | src: Vector, 46 | target: Vector, 47 | smooth_percentage: Tx, 48 | ) -> Vector { 49 | let mut delta = target - src; 50 | delta.normalize_yaw_cs(); 51 | 52 | src + delta * smooth_percentage.into() 53 | } 54 | -------------------------------------------------------------------------------- /src/maths/mod.rs: -------------------------------------------------------------------------------- 1 | pub use functions::{calc_angle, compensate_velocity, get_fov, smooth_angle}; 2 | pub use vector::Vector; 3 | 4 | mod functions; 5 | mod vector; 6 | -------------------------------------------------------------------------------- /src/maths/vector.rs: -------------------------------------------------------------------------------- 1 | use ::std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign}; 2 | use std::ops::{Deref, Rem}; 3 | 4 | #[repr(C)] 5 | #[derive(Clone, Copy, Default)] 6 | pub struct Vector { 7 | pub x: f32, 8 | pub y: f32, 9 | pub z: f32, 10 | } 11 | 12 | trait NormalizeTrait { 13 | fn normalize + Copy, Ty: Into + Copy>(&mut self, lo: Tx, hi: Ty) 14 | where 15 | Self: Sized + PartialOrd + PartialOrd; 16 | } 17 | 18 | impl NormalizeTrait for f32 { 19 | fn normalize + Copy, Ty: Into + Copy>(&mut self, lo: Tx, hi: Ty) 20 | where 21 | Self: Sized + PartialOrd + PartialOrd, 22 | { 23 | *self = self.rem_euclid(2e0 * hi.into()); 24 | 25 | if *self > hi { 26 | *self -= 2e0 * hi.into(); 27 | } 28 | 29 | if *self < lo { 30 | *self += 2e0 * hi.into(); 31 | } 32 | } 33 | } 34 | 35 | impl From<[f32; 3]> for Vector { 36 | fn from(other: [f32; 3]) -> Self { 37 | Self { 38 | x: other[0] as f32, 39 | y: other[1] as f32, 40 | z: other[2] as f32, 41 | } 42 | } 43 | } 44 | 45 | impl From<[f32; 2]> for Vector { 46 | fn from(other: [f32; 2]) -> Self { 47 | Self { 48 | x: other[0] as f32, 49 | y: other[1] as f32, 50 | z: 0e0, 51 | } 52 | } 53 | } 54 | 55 | impl Into<[f32; 3]> for &Vector { 56 | fn into(self) -> [f32; 3] { 57 | [self.x as f32, self.y as f32, self.z as f32] 58 | } 59 | } 60 | 61 | impl Into<[f32; 2]> for &Vector { 62 | fn into(self) -> [f32; 2] { 63 | [self.x as f32, self.y as f32] 64 | } 65 | } 66 | 67 | impl Vector { 68 | pub fn new + Copy, Ty: Into + Copy, Tz: Into + Copy>( 69 | x: Tx, 70 | y: Ty, 71 | z: Tz, 72 | ) -> Self { 73 | Self { 74 | x: x.into(), 75 | y: y.into(), 76 | z: z.into(), 77 | } 78 | } 79 | 80 | pub fn len_sqr(&self) -> f32 { 81 | f32::powi(self.x, 2) + f32::powi(self.y, 2) + f32::powi(self.z, 2) 82 | } 83 | 84 | pub fn len(&self) -> f32 { 85 | self.len_sqr().sqrt() 86 | } 87 | 88 | pub fn nullify_x(self) -> Self { 89 | Self { 90 | x: 0e0, 91 | y: self.y, 92 | z: self.z, 93 | } 94 | } 95 | 96 | pub fn nullify_y(self) -> Self { 97 | Self { 98 | x: self.x, 99 | y: 0e0, 100 | z: self.z, 101 | } 102 | } 103 | 104 | pub fn nullify_z(self) -> Self { 105 | Self { 106 | x: self.x, 107 | y: self.y, 108 | z: 0e0, 109 | } 110 | } 111 | 112 | pub fn unit(&self) -> Self { 113 | self.clone() / self.len() 114 | } 115 | 116 | pub fn normalize(&mut self, vec_lo: &Self, vec_hi: &Self) -> &mut Self { 117 | self.x.normalize(vec_lo.x, vec_hi.x); 118 | self.y.normalize(vec_lo.y, vec_hi.y); 119 | self.z.normalize(vec_lo.z, vec_hi.z); 120 | 121 | self 122 | } 123 | 124 | pub fn normalize_yaw_cs(&mut self) -> &mut Self { 125 | let lo = -180f32; 126 | let hi = 180f32; 127 | 128 | self.y.normalize(lo, hi); 129 | 130 | self 131 | } 132 | 133 | pub fn clamp(&mut self, vec_lo: &Self, vec_hi: &Self) -> &mut Self { 134 | self.x = self.x.clamp(vec_lo.x, vec_hi.x); 135 | self.y = self.y.clamp(vec_lo.y, vec_hi.y); 136 | self.z = self.z.clamp(vec_lo.z, vec_hi.z); 137 | 138 | self 139 | } 140 | 141 | pub fn clamp_csgo(&mut self) -> &mut Self { 142 | let vec_lo = Self::new(-180e0, -90e0, 0e0); 143 | let vec_hi = Self::new(180e0, 90e0, 0e0); 144 | 145 | self.clamp(&vec_lo, &vec_hi); 146 | 147 | self 148 | } 149 | 150 | pub fn to_degrees(&mut self) -> &mut Self { 151 | self.as_mut().iter_mut().for_each(|x| *x = x.to_degrees()); 152 | 153 | self 154 | } 155 | 156 | pub fn to_radians(&mut self) -> &mut Self { 157 | self.as_mut().iter_mut().for_each(|x| *x = x.to_radians()); 158 | 159 | self 160 | } 161 | 162 | pub fn swap_system(&mut self) -> &mut Self { 163 | self.y = -self.y; 164 | std::mem::swap(&mut self.x, &mut self.y); 165 | self 166 | } 167 | } 168 | 169 | impl AsRef<[f32]> for Vector { 170 | fn as_ref(&self) -> &[f32] { 171 | unsafe { std::slice::from_raw_parts(self as *const Vector as *const f32, 3) } 172 | } 173 | } 174 | 175 | impl AsMut<[f32]> for Vector { 176 | fn as_mut(&mut self) -> &mut [f32] { 177 | unsafe { std::slice::from_raw_parts_mut(self as *mut Vector as *mut f32, 3) } 178 | } 179 | } 180 | 181 | impl Add for Vector { 182 | type Output = Vector; 183 | 184 | fn add(self, rhs: Self) -> Self::Output { 185 | Self::Output { 186 | x: self.x + rhs.x, 187 | y: self.y + rhs.y, 188 | z: self.z + rhs.z, 189 | } 190 | } 191 | } 192 | 193 | impl AddAssign for Vector { 194 | fn add_assign(&mut self, rhs: Self) { 195 | self.x = self.x + rhs.x; 196 | self.y = self.y + rhs.y; 197 | self.z = self.z + rhs.z; 198 | } 199 | } 200 | 201 | impl Sub for Vector { 202 | type Output = Vector; 203 | 204 | fn sub(self, rhs: Self) -> Self::Output { 205 | Self::Output { 206 | x: self.x - rhs.x, 207 | y: self.y - rhs.y, 208 | z: self.z - rhs.z, 209 | } 210 | } 211 | } 212 | 213 | impl SubAssign for Vector { 214 | fn sub_assign(&mut self, rhs: Self) { 215 | self.x = self.x - rhs.x; 216 | self.y = self.y - rhs.y; 217 | self.z = self.z - rhs.z; 218 | } 219 | } 220 | 221 | impl + Copy> Add for Vector { 222 | type Output = Vector; 223 | 224 | fn add(self, rhs: T) -> Self::Output { 225 | Self::Output { 226 | x: self.x + rhs.into(), 227 | y: self.y + rhs.into(), 228 | z: self.z + rhs.into(), 229 | } 230 | } 231 | } 232 | 233 | impl + Copy> AddAssign for Vector { 234 | fn add_assign(&mut self, rhs: T) { 235 | self.x = self.x + rhs.into(); 236 | self.y = self.y + rhs.into(); 237 | self.z = self.z + rhs.into(); 238 | } 239 | } 240 | 241 | impl + Copy> Sub for Vector { 242 | type Output = Vector; 243 | 244 | fn sub(self, rhs: T) -> Self::Output { 245 | Self::Output { 246 | x: self.x - rhs.into(), 247 | y: self.y - rhs.into(), 248 | z: self.z - rhs.into(), 249 | } 250 | } 251 | } 252 | 253 | impl + Copy> SubAssign for Vector { 254 | fn sub_assign(&mut self, rhs: T) { 255 | self.x = self.x - rhs.into(); 256 | self.y = self.y - rhs.into(); 257 | self.z = self.z - rhs.into(); 258 | } 259 | } 260 | 261 | impl Mul for Vector { 262 | type Output = f32; 263 | 264 | fn mul(self, rhs: Self) -> Self::Output { 265 | self.x * rhs.x + self.y * rhs.y + self.z * rhs.z 266 | } 267 | } 268 | 269 | impl + Copy> Mul for Vector { 270 | type Output = Vector; 271 | 272 | fn mul(self, rhs: T) -> Self::Output { 273 | Self::Output { 274 | x: self.x * rhs.into(), 275 | y: self.y * rhs.into(), 276 | z: self.z * rhs.into(), 277 | } 278 | } 279 | } 280 | 281 | impl + Copy> MulAssign for Vector { 282 | fn mul_assign(&mut self, rhs: T) { 283 | self.x = self.x * rhs.into(); 284 | self.y = self.y * rhs.into(); 285 | self.z = self.z * rhs.into(); 286 | } 287 | } 288 | 289 | impl + Copy> Div for Vector { 290 | type Output = Vector; 291 | 292 | fn div(self, rhs: T) -> Self::Output { 293 | Self::Output { 294 | x: self.x / rhs.into(), 295 | y: self.y / rhs.into(), 296 | z: self.z / rhs.into(), 297 | } 298 | } 299 | } 300 | 301 | impl + Copy> DivAssign for Vector { 302 | fn div_assign(&mut self, rhs: T) { 303 | self.x = self.x / rhs.into(); 304 | self.y = self.y / rhs.into(); 305 | self.z = self.z / rhs.into(); 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /src/memory/functions.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{CStr, CString}; 2 | use std::os::raw::c_void; 3 | use winapi::{ 4 | ctypes::c_long, 5 | shared::minwindef::HMODULE, 6 | um::winnt::{PIMAGE_DOS_HEADER, PIMAGE_NT_HEADERS}, 7 | }; 8 | 9 | fn pattern_to_bytes(pattern: String) -> Vec { 10 | pattern 11 | .replace(' ', "") 12 | .as_bytes() 13 | .chunks(2) 14 | .map(std::str::from_utf8) 15 | .collect::, _>>() 16 | .unwrap() 17 | .into_iter() 18 | .filter(|&q| !q.contains('?')) 19 | .map(|q| i32::from_str_radix(q, 16).unwrap()) 20 | .collect::>() 21 | } 22 | 23 | //https://github.com/zorftw/Ion/blob/552f99fc1f1c9e3e82e9822c19ec665185583f07/Ion/src/utils/sig.rs#L27 24 | pub fn pattern_scan(module: HMODULE, sig: &str) -> *mut u8 { 25 | unsafe { 26 | let dos_headers = module as PIMAGE_DOS_HEADER; 27 | 28 | let module_addr = module as usize; 29 | let e_lfanew = (*dos_headers).e_lfanew as c_long; 30 | 31 | let nt_headers = (module_addr + e_lfanew as usize) as PIMAGE_NT_HEADERS; 32 | 33 | let size_of_image = (*nt_headers).OptionalHeader.SizeOfImage as usize; 34 | let pattern_bytes = pattern_to_bytes(sig.to_owned()); 35 | let bytes = module as *mut u8; 36 | 37 | let size = pattern_bytes.len(); 38 | 39 | for i in 0..(size_of_image - size as usize) { 40 | let mut found = true; 41 | for j in 0..size { 42 | if *bytes.offset(i as isize + j as isize) != pattern_bytes[j] as _ 43 | && pattern_bytes[j] != -1 44 | { 45 | found = false; 46 | break; 47 | } 48 | } 49 | 50 | if found { 51 | return bytes.offset(i as _) as _; 52 | } 53 | } 54 | } 55 | 56 | 0 as *mut _ 57 | } 58 | 59 | pub unsafe fn get_virtual_raw(vfmt: *const c_void, index: usize) -> *const c_void { 60 | (vfmt as *const *const c_void).offset(index as isize).read() 61 | } 62 | 63 | pub unsafe fn get_module_handle(module_name: &str) -> *const c_void { 64 | winapi::um::libloaderapi::GetModuleHandleA(CString::new(module_name).unwrap().as_ptr()) 65 | as *const c_void 66 | } 67 | -------------------------------------------------------------------------------- /src/memory/mod.rs: -------------------------------------------------------------------------------- 1 | pub use functions::{get_module_handle, get_virtual_raw, pattern_scan}; 2 | 3 | mod functions; 4 | -------------------------------------------------------------------------------- /src/script_engine/aimbot.rs: -------------------------------------------------------------------------------- 1 | use crate::structs::{ 2 | CUserCMD, CmdButton, Entity, EntityFlags, EntityIterator, HitBoxes, ItemDefIndices, 3 | }; 4 | 5 | use super::modulesys::Module; 6 | use crate::interfaces::{Globals, NetvarEngine}; 7 | use crate::maths::{calc_angle, compensate_velocity, get_fov, smooth_angle, Vector}; 8 | use winapi::um::winuser::GetAsyncKeyState; 9 | 10 | struct AimbotConfig { 11 | pistol_mode: bool, 12 | smooth_fn: Option f32>>, 13 | max_fov: f32, 14 | hitboxes: Vec, 15 | lock: bool, 16 | } 17 | 18 | impl Default for AimbotConfig { 19 | fn default() -> Self { 20 | Self { 21 | pistol_mode: false, 22 | smooth_fn: None, 23 | max_fov: 90e0, 24 | hitboxes: Vec::new(), 25 | lock: true, 26 | } 27 | } 28 | } 29 | 30 | pub struct Aimbot { 31 | current_target: Option<&'static Entity>, 32 | prev_target: Option<&'static Entity>, 33 | current_hitbox: Option<(HitBoxes, Vector)>, 34 | current_config: AimbotConfig, 35 | current_aimtime: Option, 36 | } 37 | 38 | unsafe impl Send for Aimbot {} 39 | unsafe impl Sync for Aimbot {} 40 | 41 | impl Aimbot { 42 | pub fn new() -> Aimbot { 43 | Self { 44 | current_target: None, 45 | prev_target: None, 46 | current_config: AimbotConfig::default(), 47 | current_hitbox: None, 48 | current_aimtime: None, 49 | } 50 | } 51 | 52 | fn triggered(&mut self, local_player: &'static Entity, cmd: &mut CUserCMD) -> bool { 53 | if !cmd.buttons.contains(CmdButton::IN_ATTACK) { 54 | self.current_target = None; 55 | self.current_hitbox = None; 56 | self.current_aimtime = None; 57 | 58 | false 59 | } else { 60 | true 61 | } 62 | } 63 | 64 | fn set_target(&mut self, local_player: &'static Entity, cmd: &mut CUserCMD) -> bool { 65 | if let Some(old_target) = self.current_target { 66 | if old_target.alive() && !old_target.dormant() { 67 | 68 | true 69 | } else { 70 | self.current_target = None; 71 | self.current_hitbox = None; 72 | self.current_aimtime = None; 73 | 74 | false 75 | } 76 | } else { 77 | let mut valid_targets: Vec<&'static Entity> = EntityIterator::new() 78 | .filter_map(|entity| entity) 79 | .filter(|&entity| { 80 | !entity.dormant() 81 | && entity.is_player() 82 | && entity.alive() 83 | && (entity.team() != local_player.team()) 84 | }) 85 | .collect(); 86 | 87 | if valid_targets.is_empty() { 88 | return false; 89 | } 90 | 91 | valid_targets.sort_by(|&a, &b| { 92 | let pseudo_fov_a = (cmd.view_angles - calc_angle(local_player.eye(), a.eye())) 93 | .normalize_yaw_cs() 94 | .len(); 95 | 96 | let pseudo_fov_b = (cmd.view_angles - calc_angle(local_player.eye(), b.eye())) 97 | .normalize_yaw_cs() 98 | .len(); 99 | 100 | pseudo_fov_a.partial_cmp(&pseudo_fov_b).unwrap() 101 | }); 102 | 103 | self.current_target = Some(*valid_targets.first().unwrap()); 104 | 105 | true 106 | } 107 | } 108 | 109 | fn set_hitbox(&mut self, local_player: &'static Entity, cmd: &mut CUserCMD) -> bool { 110 | if let Some(current_target) = self.current_target { 111 | if let Some(current_hitbox) = self.current_hitbox { 112 | if let Some(updated_hitbox) = current_target.hitbox_center(current_hitbox.0) { 113 | self.current_hitbox = Some((current_hitbox.0, updated_hitbox)); 114 | 115 | true 116 | } else { 117 | false 118 | } 119 | } else { 120 | let mut copy: Vec<_> = self 121 | .current_config 122 | .hitboxes 123 | .clone() 124 | .iter() 125 | .map(|&hitbox| { 126 | ( 127 | hitbox, 128 | compensate_velocity( 129 | current_target.hitbox_center(hitbox).unwrap(), 130 | current_target.vel() - local_player.vel(), 131 | (local_player.origin() - current_target.origin()).len(), 132 | ), 133 | ) 134 | }) 135 | .collect(); 136 | copy.sort_by(|&a, &b| { 137 | let lp_eye = local_player.eye(); 138 | 139 | let a_fov = get_fov( 140 | cmd.view_angles + local_player.viewpunch() + local_player.aimpunch() * 2e0 * 0.45e0, 141 | calc_angle(lp_eye, a.1), 142 | (lp_eye - a.1).len(), 143 | ); 144 | 145 | let b_fov = get_fov( 146 | cmd.view_angles + local_player.viewpunch() + local_player.aimpunch() * 2e0 * 0.45e0, 147 | calc_angle(lp_eye, b.1), 148 | (lp_eye - b.1).len(), 149 | ); 150 | 151 | a_fov.partial_cmp(&b_fov).unwrap() 152 | }); 153 | 154 | self.current_hitbox = Some(*copy.first().unwrap()); 155 | 156 | true 157 | } 158 | } else { 159 | false 160 | } 161 | } 162 | 163 | /* 164 | smooth_fn: Some(Box::new(|time| { 165 | ((time.mul(2e0) - 1f32.div(2e0)).div(4e0).sin().powi(2) 166 | + (time - 1f32.div(2e0)).div(4e0).cos() 167 | - 1.2) 168 | .abs() 169 | })), 170 | */ 171 | 172 | fn set_config(&mut self, local_player: &'static Entity, cmd: &mut CUserCMD) -> bool { 173 | use std::ops::{Div, Mul, Neg, Sub}; 174 | 175 | if let Some(wep) = local_player.active_weapon() { 176 | use ItemDefIndices::*; 177 | 178 | match wep.weapon_id() { 179 | AK47 | M4A1 | MP9 | MP7 | GALILAR | FAMAS | P90 | SG556 => { 180 | self.current_config = AimbotConfig { 181 | pistol_mode: false, 182 | lock: true, 183 | smooth_fn: Some(Box::new(|time| { 184 | let a = (2e0 * time - 1e0).abs(); 185 | 186 | (a - 0.8e0).abs().div(2e0) 187 | })), 188 | max_fov: 18e0, 189 | hitboxes: vec![HitBoxes::Head, HitBoxes::UpperChest], 190 | }; 191 | 192 | true 193 | } 194 | 195 | AWP | SSG08 => { 196 | self.current_config = AimbotConfig { 197 | pistol_mode: false, 198 | lock: false, 199 | smooth_fn: Option::None, //ambiguity introduced due to ItemDefIndices::None 200 | max_fov: 27e0, 201 | hitboxes: vec![ 202 | HitBoxes::Head, 203 | HitBoxes::Neck, 204 | HitBoxes::Chest, 205 | HitBoxes::Stomach, 206 | HitBoxes::LowerChest, 207 | ], 208 | }; 209 | 210 | true 211 | } 212 | 213 | DEAGLE => { 214 | self.current_config = AimbotConfig { 215 | pistol_mode: false, 216 | lock: false, 217 | smooth_fn: Option::None, //ambiguity introduced due to ItemDefIndices::None 218 | max_fov: 12e0, 219 | hitboxes: vec![HitBoxes::Head], 220 | }; 221 | 222 | true 223 | } 224 | 225 | P250 | TEC9 | GLOCK | USP_SILENCER | HKP2000 | FIVESEVEN => { 226 | self.current_config = AimbotConfig { 227 | pistol_mode: true, 228 | lock: false, 229 | smooth_fn: Option::None, //ambiguity introduced due to ItemDefIndices::None 230 | max_fov: 8e0, 231 | hitboxes: vec![HitBoxes::Head], 232 | }; 233 | 234 | true 235 | } 236 | 237 | _ => { 238 | self.current_config = AimbotConfig::default(); 239 | 240 | false 241 | } 242 | } 243 | } else { 244 | false 245 | } 246 | } 247 | 248 | fn is_ready(&mut self, local_player: &'static Entity, cmd: &mut CUserCMD) -> bool { 249 | if let Some(current_target) = self.current_target { 250 | if let Some(current_hitbox) = self.current_hitbox { 251 | if let Some(current_weapon) = local_player.active_weapon() { 252 | if !local_player.is_visible(current_target, current_hitbox.1) { 253 | return false; 254 | } 255 | 256 | if self.prev_target != self.current_target 257 | && get_fov( 258 | cmd.view_angles + local_player.viewpunch() + local_player.aimpunch() * 2e0 * 0.45e0, 259 | calc_angle(local_player.eye(), current_hitbox.1), 260 | (current_hitbox.1 - local_player.eye()).len(), 261 | ) > self.current_config.max_fov 262 | { 263 | self.current_target = None; 264 | self.current_hitbox = None; 265 | self.current_aimtime = None; 266 | 267 | return false; 268 | } 269 | 270 | if current_weapon.is_reloading() || current_weapon.clip1_rem() <= 0 { 271 | return false; 272 | } 273 | 274 | /*let server_time = 275 | local_player.tickbase() as f32 * Globals::get().inv_tickspersecond; 276 | if local_player.next_attack() > server_time { 277 | return false; 278 | }*/ 279 | 280 | if self.current_config.pistol_mode { 281 | use ItemDefIndices::*; 282 | let rem = current_weapon.clip1_rem(); 283 | match current_weapon.weapon_id() { 284 | P250 => { 285 | if (13 + 1 - rem) % 3 == 0 { 286 | return false; 287 | } 288 | } 289 | TEC9 => { 290 | if (18 + 1 - rem) % 3 == 0 { 291 | return false; 292 | } 293 | } 294 | GLOCK => { 295 | if (20 + 1 - rem) % 3 == 0 { 296 | return false; 297 | } 298 | } 299 | USP_SILENCER => { 300 | if (12 + 1 - rem) % 2 == 0 { 301 | return false; 302 | } 303 | } 304 | HKP2000 => { 305 | if (12 + 1 - rem) % 2 == 0 { 306 | return false; 307 | } 308 | } 309 | FIVESEVEN => { 310 | if (20 + 1 - rem) % 3 == 0 { 311 | return false; 312 | } 313 | } 314 | _ => { 315 | return false; 316 | } 317 | } 318 | } 319 | 320 | //current_weapon.next_primary_attack() <= server_time 321 | true 322 | } else { 323 | false 324 | } 325 | } else { 326 | false 327 | } 328 | } else { 329 | false 330 | } 331 | } 332 | 333 | fn aim_at_current_target( 334 | &mut self, 335 | local_player: &'static Entity, 336 | cmd: &mut CUserCMD, 337 | frame_time: f32, 338 | ) { 339 | if let Some(current_target) = self.current_target { 340 | if let Some((_, target_vec)) = self.current_hitbox { 341 | let mut target_angle = calc_angle(local_player.eye(), target_vec); 342 | 343 | let punch = Vector { 344 | x: local_player.aimpunch().x, 345 | y: if local_player.shotsfired() > 1 { 346 | local_player.aimpunch().y 347 | } else { 348 | 0e0 349 | }, 350 | z: 0e0, 351 | }; 352 | 353 | target_angle -= punch * 2e0; 354 | 355 | if let Some(current_aimtime) = self.current_aimtime { 356 | if let Some(ref smooth_fn) = self.current_config.smooth_fn { 357 | 358 | target_angle = smooth_angle( 359 | cmd.view_angles, 360 | target_angle, 361 | smooth_fn(current_aimtime.clamp(0e0, 1e0)), 362 | ); 363 | } 364 | 365 | self.current_aimtime = Some(current_aimtime + Globals::get().inv_tickspersecond) 366 | } else { 367 | self.current_aimtime = Some(f32::default()); 368 | 369 | return; 370 | } 371 | 372 | cmd.view_angles = target_angle; 373 | } 374 | } 375 | 376 | self.prev_target = self.current_target; 377 | } 378 | } 379 | 380 | impl Module for Aimbot { 381 | fn post_createmove(&mut self, cmd: &mut CUserCMD, frame_time: f32) -> () { 382 | if let Some(local_player) = Entity::local() { 383 | if !local_player.alive() { 384 | return; 385 | } 386 | 387 | if self.triggered(local_player, cmd) { 388 | if self.set_config(local_player, cmd) { 389 | if self.set_target(local_player, cmd) { 390 | if self.set_hitbox(local_player, cmd) { 391 | if self.is_ready(local_player, cmd) { 392 | self.aim_at_current_target(local_player, cmd, frame_time); 393 | } 394 | } 395 | } 396 | } 397 | } 398 | } 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /src/script_engine/bhop.rs: -------------------------------------------------------------------------------- 1 | use crate::structs::{CUserCMD, CmdButton, Entity, EntityFlags, EntityIterator, HitBoxes}; 2 | 3 | use super::modulesys::Module; 4 | 5 | pub struct BHop {} 6 | 7 | impl BHop { 8 | pub fn new() -> BHop { 9 | Self {} 10 | } 11 | } 12 | 13 | impl Module for BHop { 14 | fn post_createmove(&mut self, cmd: &mut CUserCMD, frame_time: f32) -> () { 15 | if let Some(local_player) = Entity::local() { 16 | if !local_player.alive() { 17 | return; 18 | } 19 | 20 | if cmd.buttons.contains(CmdButton::IN_JUMP) { 21 | if local_player.flags().contains(EntityFlags::ON_GROUND) { 22 | cmd.buttons.set(CmdButton::IN_JUMP, true); 23 | } else { 24 | cmd.buttons.set(CmdButton::IN_JUMP, false); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/script_engine/mod.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use std::sync::{Mutex, MutexGuard}; 3 | 4 | use crate::maths; 5 | use crate::maths::Vector; 6 | use crate::script_engine::aimbot::Aimbot; 7 | use crate::script_engine::bhop::BHop; 8 | use crate::structs::{ 9 | CUserCMD, CmdButton, Entity, EntityIterator, EntityTeam, HitBoxes, PanelType, 10 | }; 11 | use rlua::{ 12 | Context, ExternalError, FromLua, Function, Lua, MetaMethod, ToLua, UserData, UserDataMethods, 13 | Value, 14 | }; 15 | 16 | mod aimbot; 17 | mod bhop; 18 | mod modulesys; 19 | 20 | struct LuaContext { 21 | ctx: Lua, 22 | } 23 | 24 | unsafe impl Send for LuaContext {} 25 | unsafe impl Sync for LuaContext {} 26 | 27 | pub struct ScriptEngine { 28 | modules: Vec>, 29 | lua: LuaContext, 30 | } 31 | 32 | impl UserData for Vector { 33 | fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(_methods: &mut T) { 34 | _methods.add_method("Magnitude", |_, vec, ()| Ok(vec.len())); 35 | _methods.add_method("MagnitudeSqr", |_, vec, ()| Ok(vec.len_sqr())); 36 | _methods.add_method("InRadian", |_, vec, ()| Ok(*vec.clone().to_radians())); 37 | _methods.add_method("InDegree", |_, vec, ()| Ok(*vec.clone().to_degrees())); 38 | _methods.add_method_mut("Normalize", |_, vec, ()| { 39 | vec.normalize_yaw_cs(); 40 | Ok(()) 41 | }); 42 | _methods.add_method_mut("Clamp", |_, vec, ()| { 43 | vec.clamp_csgo(); 44 | Ok(()) 45 | }); 46 | 47 | _methods.add_meta_function(MetaMethod::Add, |_, (vec_a, vec_b): (Vector, Vector)| { 48 | Ok(vec_a + vec_b) 49 | }); 50 | 51 | _methods.add_meta_function(MetaMethod::Add, |_, (mut vec_a, factor): (Vector, f32)| { 52 | vec_a.as_mut().iter_mut().for_each(|x| *x += factor); 53 | Ok(vec_a) 54 | }); 55 | 56 | _methods.add_meta_function(MetaMethod::Sub, |_, (vec_a, vec_b): (Vector, Vector)| { 57 | Ok(vec_a - vec_b) 58 | }); 59 | 60 | _methods.add_meta_function(MetaMethod::Sub, |_, (mut vec_a, factor): (Vector, f32)| { 61 | vec_a.as_mut().iter_mut().for_each(|x| *x -= factor); 62 | Ok(vec_a) 63 | }); 64 | 65 | _methods.add_meta_function(MetaMethod::Div, |_, (vec_a, factor): (Vector, f32)| { 66 | Ok(vec_a / factor) 67 | }); 68 | 69 | _methods.add_meta_function(MetaMethod::Mul, |_, (vec_a, factor): (Vector, f32)| { 70 | Ok(vec_a * factor) 71 | }); 72 | 73 | _methods.add_meta_function(MetaMethod::Mul, |_, (vec_a, vec_b): (Vector, Vector)| { 74 | Ok(vec_a * vec_b) 75 | }); 76 | } 77 | } 78 | 79 | impl<'lua> FromLua<'lua> for HitBoxes { 80 | fn from_lua(lua_value: Value<'lua>, lua: Context<'lua>) -> Result { 81 | if let Value::Integer(hitbox_id) = lua_value { 82 | use std::convert::TryFrom; 83 | 84 | if let Ok(hitbox) = HitBoxes::try_from(hitbox_id as usize) { 85 | Ok(hitbox) 86 | } else { 87 | Err(rlua::Error::RuntimeError( 88 | "Wrong hitbox argument! Must be an integer that's between 1 and 12.".to_owned(), 89 | )) //TODO: Use custom error types. 90 | } 91 | } else { 92 | Err(rlua::Error::FromLuaConversionError { 93 | from: "hitbox id", 94 | to: "hitbox", 95 | message: None, 96 | }) 97 | } 98 | } 99 | } 100 | 101 | impl UserData for &Entity { 102 | fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(_methods: &mut T) { 103 | use rlua::ExternalResult; 104 | _methods.add_method("GetOrigin", |_, &ent, ()| Ok(ent.origin())); 105 | _methods.add_method("GetHealth", |_, &ent, ()| Ok(ent.health())); 106 | _methods.add_method("IsAlive", |_, &ent, ()| Ok(ent.alive())); 107 | _methods.add_method("GetTeam", |_, &ent, ()| Ok(ent.team() as usize)); 108 | _methods.add_method("ActiveWeapon", |_, &ent, ()| { 109 | Ok(ent.active_weapon().unwrap()) //TODO: Use custom error types. 110 | }); 111 | _methods.add_method("WeaponId", |_, &ent, ()| Ok(ent.weapon_id() as usize)); 112 | _methods.add_method("GetHitboxCenter", |_, &ent, hitbox_id| { 113 | Ok(ent.hitbox_center(hitbox_id)) 114 | }); 115 | _methods.add_method("GetEyePosition", |_, &ent, ()| Ok(ent.eye())); 116 | _methods.add_method("GetAimPunch", |_, &ent, ()| Ok(ent.aimpunch())); 117 | _methods.add_method("GetViewPunch", |_, &ent, ()| Ok(ent.viewpunch())); 118 | _methods.add_method("GetShotsFired", |_, &ent, ()| Ok(ent.shotsfired())); 119 | _methods.add_method( 120 | "viewpunch", 121 | |_, &ent, (other, position): (&Entity, Vector)| Ok(ent.is_visible(other, position)), 122 | ); 123 | _methods.add_method("GetVelocity", |_, &ent, ()| Ok(ent.vel())); 124 | _methods.add_method("IsDormant", |_, &ent, ()| Ok(ent.dormant())); 125 | _methods.add_method("GetFlags", |_, &ent, ()| Ok(ent.flags().bits() as usize)); 126 | _methods.add_method("IsPlayer", |_, &ent, ()| Ok(ent.is_player())); 127 | _methods.add_method("IsWeapon", |_, &ent, ()| Ok(ent.is_weapon())); 128 | _methods.add_method("GetAmmoClip1", |_, &ent, ()| Ok(ent.clip1_rem())); 129 | } 130 | } 131 | 132 | impl UserData for &mut CUserCMD { 133 | fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(_methods: &mut T) { 134 | _methods.add_method_mut("SetViewAngle", |_, cmd, (view_angle)| { 135 | cmd.view_angles = view_angle; 136 | Ok(()) 137 | }); 138 | _methods.add_method_mut("SetButtons", |_, cmd, (mask, state)| { 139 | cmd.buttons.set(CmdButton::from_bits(mask).unwrap(), state); 140 | Ok(()) 141 | }); 142 | _methods.add_method_mut("GetViewAngle", |_, cmd, ()| Ok(cmd.view_angles)); 143 | _methods.add_method_mut("GetButtonsRaw", |_, cmd, ()| Ok(cmd.buttons.bits())); 144 | _methods.add_method_mut("IsButtonSet", |_, cmd, (mask)| { 145 | Ok(cmd.buttons.contains(CmdButton::from_bits(mask).unwrap())) 146 | }); 147 | } 148 | } 149 | 150 | impl ScriptEngine { 151 | pub fn fire_post_createmove(&mut self, cmd: &mut CUserCMD, frame_time: f32) { 152 | self.modules.iter_mut().for_each(|module| { 153 | module.post_createmove(cmd, frame_time); 154 | }); 155 | } 156 | 157 | pub fn fire_painttraverse(&mut self, panel_type: PanelType) { 158 | self.modules 159 | .iter_mut() 160 | .for_each(|module| module.paint_traverse(panel_type)); 161 | } 162 | 163 | #[allow(unused_must_use)] 164 | pub fn lua_createmove(&mut self, cmd: &'static mut CUserCMD) { 165 | self.lua.ctx.context(|ctx| -> rlua::Result<()> { 166 | // I don't think this is idiomatic??? Probably there's an overhead for accessing the context and getting the globals each createmove tick. 167 | let globals = ctx.globals(); 168 | let vec_createmove: Vec = globals.get("CreateMoves")?; 169 | vec_createmove.iter().for_each(|f| unsafe { 170 | f.call::<&mut CUserCMD, ()>(std::mem::transmute(cmd as *mut _)) // K, this is soooo unrusty. I gotta find a way to do it in a proper way. 171 | .expect("Calling createmove in lua space failed.") 172 | }); 173 | 174 | Ok(()) 175 | }); 176 | } 177 | 178 | #[allow(unused_must_use)] 179 | pub fn initialize(&mut self, scripts_dir: &str) { 180 | self.modules.push(Box::new(BHop::new())); 181 | self.modules.push(Box::new(Aimbot::new())); 182 | 183 | self.lua.ctx.context(|ctx| -> rlua::Result<()> { 184 | let globals = ctx.globals(); 185 | 186 | let maths_table = ctx.create_table()?; 187 | let calc_angle = ctx.create_function(|_, (src, target): (Vector, Vector)| { 188 | Ok(maths::calc_angle(src, target)) 189 | })?; 190 | let get_fov = ctx.create_function(|_, (src, target, r): (Vector, Vector, f32)| { 191 | Ok(maths::get_fov(src, target, r)) 192 | })?; 193 | let compensate_velocity = 194 | ctx.create_function(|_, (src, rel_velocity, r): (Vector, Vector, f32)| { 195 | Ok(maths::compensate_velocity(src, rel_velocity, r)) 196 | })?; 197 | let smooth_angle = ctx.create_function( 198 | |_, (src, target, delta_coefficient): (Vector, Vector, f32)| { 199 | Ok(maths::smooth_angle(src, target, delta_coefficient)) 200 | }, 201 | )?; 202 | maths_table.set("CalcAngle", calc_angle); 203 | maths_table.set("GetFov", get_fov); 204 | maths_table.set("CompensateVelocity", compensate_velocity); 205 | maths_table.set("SmoothAngle", smooth_angle); 206 | 207 | globals.set("Maths", maths_table); 208 | //TODO: Engine interfaces. 209 | globals.set("Players", Vec::<&Entity>::new()); 210 | 211 | let functions_table = ctx.create_table()?; 212 | globals.set("CreateMoves", functions_table); 213 | globals.set("CreateMovesCounter", 0); 214 | 215 | let register_createmove = ctx.create_function(|ctx, function: Function| { 216 | let globals = ctx.globals(); 217 | let functions_table: rlua::Table = globals.get("CreateMoves")?; 218 | let counter: usize = globals.get("CreateMovesCounter")?; 219 | functions_table.set(counter, function); 220 | globals.set("CreateMovesCounter", counter + 1); 221 | Ok(()) 222 | })?; 223 | 224 | globals.set("RegisterCreateMove", register_createmove); 225 | 226 | //load file into ctx 227 | use std::fs::File; 228 | use std::io::prelude::*; 229 | use std::path::Path; 230 | let lua_scripts_dir = Path::new(scripts_dir); 231 | 232 | //TODO: GOD, I need better error handling throughout the entire project. 233 | for entry in lua_scripts_dir.read_dir().expect("Invalid lua directory") { 234 | if let Ok(entry) = entry { 235 | let path_buf = entry.path(); 236 | 237 | if let Some(file_type) = path_buf.as_path().extension() { 238 | let file_type = file_type.to_str().unwrap(); //D; 239 | if file_type == "lua" { 240 | let src = std::fs::read_to_string(path_buf.as_path()).unwrap(); // D; 241 | 242 | ctx.load(src.as_str()).exec(); 243 | } 244 | } 245 | } 246 | } 247 | Ok(()) 248 | }); 249 | } 250 | 251 | #[allow(unused_must_use)] 252 | pub fn update_entities(&mut self) -> () { 253 | self.lua.ctx.context(|ctx| { 254 | ctx.globals().set( 255 | "players", 256 | EntityIterator::new() 257 | .filter_map(|ent| match ent { 258 | Some(ent) => { 259 | if ent.dormant() || !ent.alive() || !ent.is_player() { 260 | return None; 261 | } 262 | 263 | Some(ent) 264 | } 265 | 266 | None => None, 267 | }) 268 | .collect::>(), 269 | ); 270 | }); 271 | } 272 | 273 | pub fn set_localplayer(&mut self) -> () { 274 | self.lua.ctx.context(|ctx| { 275 | if let Some(local_player) = Entity::local() { 276 | ctx.globals().set("LocalPlayer", local_player); 277 | } 278 | }); 279 | } 280 | 281 | pub fn global() -> MutexGuard<'static, ScriptEngine> { 282 | INSTANCE.lock().unwrap() 283 | } 284 | } 285 | 286 | static INSTANCE: Lazy> = Lazy::new(|| Mutex::new(ScriptEngine::default())); 287 | 288 | impl Default for ScriptEngine { 289 | fn default() -> Self { 290 | Self { 291 | modules: Vec::new(), 292 | lua: LuaContext { ctx: Lua::new() }, 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /src/script_engine/modulesys.rs: -------------------------------------------------------------------------------- 1 | use crate::structs::{CUserCMD, PanelType}; 2 | 3 | pub trait Module { 4 | fn post_createmove(&mut self, cmd: &mut CUserCMD, frame_time: f32) -> () {} 5 | fn paint_traverse(&mut self, panel_type: PanelType) -> () {} 6 | } 7 | -------------------------------------------------------------------------------- /src/structs/clientclass.rs: -------------------------------------------------------------------------------- 1 | use std::os::raw::c_char; 2 | 3 | use super::recvprop; 4 | use crate::structs::ClientClassId; 5 | 6 | type CreateClientClassFn = unsafe extern "system" fn(ent: i32, serial: i32); 7 | type CreateEventFn = unsafe extern "system" fn(); 8 | 9 | #[repr(C)] 10 | pub struct ClientClass { 11 | create_client_class: CreateClientClassFn, 12 | create_event: CreateEventFn, 13 | network_name: *mut c_char, 14 | pub recv_table: *mut recvprop::CRecvTable, 15 | pub next: *mut ClientClass, 16 | pub class_id: ClientClassId, 17 | } 18 | -------------------------------------------------------------------------------- /src/structs/clientclassid.rs: -------------------------------------------------------------------------------- 1 | #[allow(conflicting_repr_hints)] 2 | #[repr(C, u32)] 3 | #[derive(Copy, Clone)] 4 | pub enum ClientClassId { 5 | AK47 = 1, 6 | BaseAnimating = 2, 7 | BaseAnimatingOverlay = 3, 8 | BaseAttributableItem = 4, 9 | BaseButton = 5, 10 | BaseCombatCharacter = 6, 11 | BaseCombatWeapon = 7, 12 | BaseCSGrenade = 8, 13 | BaseCSGrenadeProjectile = 9, 14 | BaseDoor = 10, 15 | BaseEntity = 11, 16 | BaseFlex = 12, 17 | BaseGrenade = 13, 18 | BaseParticleEntity = 14, 19 | BasePlayer = 15, 20 | BasePropDoor = 16, 21 | BaseTeamObjectiveResource = 17, 22 | BaseTempEntity = 18, 23 | BaseToggle = 19, 24 | BaseTrigger = 20, 25 | BaseViewModel = 21, 26 | BaseVPhysicsTrigger = 22, 27 | BaseWeaponWorldModel = 23, 28 | Beam = 24, 29 | BeamSpotlight = 25, 30 | BoneFollower = 26, 31 | BreakableProp = 27, 32 | BreakableSurface = 28, 33 | C4 = 29, 34 | CascadeLight = 30, 35 | Chicken = 31, 36 | ColorCorrection = 32, 37 | ColorCorrectionVolume = 33, 38 | CSGameRulesProxy = 34, 39 | CSPlayer = 35, 40 | CSPlayerResource = 36, 41 | CSRagdoll = 37, 42 | CSTeam = 38, 43 | DEagle = 39, 44 | DecoyGrenade = 40, 45 | DecoyProjectile = 41, 46 | DynamicLight = 42, 47 | DynamicProp = 43, 48 | EconEntity = 44, 49 | EconWearable = 45, 50 | Embers = 46, 51 | EntityDissolve = 47, 52 | EntityFlame = 48, 53 | EntityFreezing = 49, 54 | EntityParticleTrail = 50, 55 | EnvAmbientLight = 51, 56 | EnvDetailController = 52, 57 | EnvDOFController = 53, 58 | EnvParticleScript = 54, 59 | EnvProjectedTexture = 55, 60 | EnvQuadraticBeam = 56, 61 | EnvScreenEffect = 57, 62 | EnvScreenOverlay = 58, 63 | EnvToneMapController = 59, 64 | EnvWind = 60, 65 | FEPlayerDecal = 61, 66 | FireCrackerBlast = 62, 67 | FireSmoke = 63, 68 | FireTrail = 64, 69 | Fish = 65, 70 | FlashBang = 66, 71 | FogController = 67, 72 | FootstepControl = 68, 73 | FuncDust = 69, 74 | FuncLOD = 70, 75 | FuncAreaPortalWindow = 71, 76 | FuncBrush = 72, 77 | FuncConveyor = 73, 78 | FuncLadder = 74, 79 | FuncMonitor = 75, 80 | FuncMoveLinear = 76, 81 | FuncOccluder = 77, 82 | FuncReflectiveGlass = 78, 83 | FuncRotating = 79, 84 | FuncSmokeVolume = 80, 85 | FuncTrackTrain = 81, 86 | GameRulesProxy = 82, 87 | HandleTest = 83, 88 | HEGrenade = 84, 89 | Hostage = 85, 90 | HostageCarriableProp = 86, 91 | IncendiaryGrenade = 87, 92 | Inferno = 88, 93 | InfoLadderDismount = 89, 94 | InfoOverlayAccessor = 90, 95 | ItemHealthShot = 91, 96 | ItemDogTags = 92, 97 | Knife = 93, 98 | KnifeGG = 94, 99 | LightGlow = 95, 100 | MaterialModifyControl = 96, 101 | MolotovGrenade = 97, 102 | MolotovProjectile = 98, 103 | MovieDisplay = 99, 104 | ParticleFire = 100, 105 | ParticlePerformanceMonitor = 101, 106 | ParticleSystem = 102, 107 | PhysBox = 103, 108 | PhysBoxMultiPlayer = 104, 109 | PhysicsProp = 105, 110 | PhysicsPropMultiPlayer = 106, 111 | PhysMagnet = 107, 112 | PlantedC4 = 108, 113 | Plasma = 109, 114 | PlayerResource = 110, 115 | PointCamera = 111, 116 | PointCommentaryNode = 112, 117 | PointWorldText = 113, 118 | PoseController = 114, 119 | PostProcessController = 115, 120 | Precipitation = 116, 121 | PrecipitationBlocker = 117, 122 | PredictedViewModel = 118, 123 | PropHallucination = 119, 124 | PropDoorRotating = 120, 125 | PropJeep = 121, 126 | PropVehicleDriveable = 122, 127 | RagDollManager = 123, 128 | RagDollProp = 124, 129 | RagDollPropAttached = 125, 130 | RopeKeyframe = 126, 131 | SCAR17 = 127, 132 | SceneEntity = 128, 133 | SensorGrenade = 129, 134 | SensorGrenadeProjectile = 130, 135 | ShadowControl = 131, 136 | SlideShowDisplay = 132, 137 | SmokeGrenade = 133, 138 | SmokeGrenadeProjectile = 134, 139 | SmokeStack = 135, 140 | SpatialEntity = 136, 141 | SpotlightEnd = 137, 142 | Sprite = 138, 143 | SpriteOriented = 139, 144 | SpriteTrail = 140, 145 | StatueProp = 141, 146 | SteamJet = 142, 147 | Sun = 143, 148 | SunlightShadowControl = 144, 149 | Team = 145, 150 | TeamPlayRoundBasedRulesProxy = 146, 151 | TEArmorRicochet = 147, 152 | TEBaseBeam = 148, 153 | TEBeamEntPoint = 149, 154 | TEBeamEntities = 150, 155 | TEBeamFollow = 151, 156 | TEBeamLaser = 152, 157 | TEBeamPoints = 153, 158 | TEBeamRing = 154, 159 | TEBeamRingPoint = 155, 160 | TEBeamSpline = 156, 161 | TEBloodSprite = 157, 162 | TEBloodStream = 158, 163 | TEBreakModel = 159, 164 | TEBSPDecal = 160, 165 | TEBubbles = 161, 166 | TEBubbleTrail = 162, 167 | TEClientProjectile = 163, 168 | TEDecal = 164, 169 | TEDust = 165, 170 | TEDynamicLight = 166, 171 | TEEffectDispatch = 167, 172 | TEEnergySplash = 168, 173 | TEExplosion = 169, 174 | TEFireBullets = 170, 175 | TEFizz = 171, 176 | TEFootprintDecal = 172, 177 | TEFoundryHelpers = 173, 178 | TEGaussExplosion = 174, 179 | TEGlowSprite = 175, 180 | TEImpact = 176, 181 | TEKillPlayerAttachments = 177, 182 | TELargeFunnel = 178, 183 | TEMetalSparks = 179, 184 | TEMuzzleFlash = 180, 185 | TEParticleSystem = 181, 186 | TEPhysicsProp = 182, 187 | TEPlantBomb = 183, 188 | TEPlayerAnimEvent = 184, 189 | TEPlayerDecal = 185, 190 | TEProjectedDecal = 186, 191 | TERadioIcon = 187, 192 | TEShatterSurface = 188, 193 | TEShowLine = 189, 194 | Tesla = 190, 195 | TESmoke = 191, 196 | TESparks = 192, 197 | TESprite = 193, 198 | TESpriteSpray = 194, 199 | __UNK0 = 195, 200 | TestTraceLine = 196, 201 | TEWorldDecal = 197, 202 | TriggerPlayerMovement = 198, 203 | TriggerSoundOperator = 199, 204 | VGuiScreen = 200, 205 | VoteController = 201, 206 | WaterBullet = 202, 207 | WaterLODControl = 203, 208 | WeaponAug = 204, 209 | WeaponAWP = 205, 210 | WeaponBaseItem = 206, 211 | WeaponBizon = 207, 212 | WeaponCSBase = 208, 213 | WeaponCSBaseGun = 209, 214 | WeaponCycler = 210, 215 | WeaponElite = 211, 216 | WeaponFamas = 212, 217 | WeaponFiveSeven = 213, 218 | WeaponG3SG1 = 214, 219 | WeaponGalil = 215, 220 | WeaponGalilAR = 216, 221 | WeaponGlock = 217, 222 | WeaponHKP2000 = 218, 223 | WeaponM249 = 219, 224 | WeaponM3 = 220, 225 | WeaponM4A1 = 221, 226 | WeaponMAC10 = 222, 227 | WeaponMag7 = 223, 228 | WeaponMP5Navy = 224, 229 | WeaponMP7 = 225, 230 | WeaponMP9 = 226, 231 | WeaponNegev = 227, 232 | WeaponNOVA = 228, 233 | WeaponP228 = 229, 234 | WeaponP250 = 230, 235 | WeaponP90 = 231, 236 | WeaponSawedOff = 232, 237 | WeaponSCAR20 = 233, 238 | WeaponScout = 234, 239 | WeaponSG550 = 235, 240 | WeaponSG552 = 236, 241 | WeaponSG556 = 237, 242 | WeaponSSG08 = 238, 243 | WeaponTaser = 239, 244 | WeaponTec9 = 240, 245 | WeaponTMP = 241, 246 | WeaponUMP45 = 242, 247 | WeaponUSP = 243, 248 | WeaponXM1014 = 244, 249 | World = 245, 250 | DustTrail = 246, 251 | MovieExplosion = 247, 252 | ParticleSmokeGrenade = 248, 253 | RocketTrail = 249, 254 | SmokeTrail = 250, 255 | SporeExplosion = 251, 256 | SporeTrail = 252, 257 | } 258 | -------------------------------------------------------------------------------- /src/structs/cmdbutton.rs: -------------------------------------------------------------------------------- 1 | use bitflags::bitflags; 2 | 3 | bitflags! { 4 | #[repr(C)] 5 | pub struct CmdButton: u32 { 6 | const IN_ATTACK = 0b000000000000000000000000000000001; 7 | const IN_JUMP = 0b000000000000000000000000000000010; 8 | const IN_DUCK = 0b000000000000000000000000000000100; 9 | const IN_FORWARD = 0b000000000000000000000000000001000; 10 | const IN_BACK = 0b000000000000000000000000000010000; 11 | const IN_USE = 0b000000000000000000000000000100000; 12 | const IN_CANCEL = 0b000000000000000000000000001000000; 13 | const IN_LEFT = 0b000000000000000000000000010000000; 14 | const IN_RIGHT = 0b000000000000000000000000100000000; 15 | const IN_MOVE_LEFT = 0b000000000000000000000001000000000; 16 | const IN_MOVE_RIGHT = 0b000000000000000000000010000000000; 17 | const IN_ATTACK_2 = 0b000000000000000000000100000000000; 18 | const IN_RUN = 0b000000000000000000001000000000000; 19 | const IN_RELOAD = 0b000000000000000000010000000000000; 20 | const IN_ALT_1 = 0b000000000000000000100000000000000; 21 | const IN_ALT_2 = 0b000000000000000001000000000000000; 22 | const IN_SCORE = 0b000000000000000010000000000000000; 23 | const IN_SPEED = 0b000000000000000100000000000000000; 24 | const IN_WALK = 0b000000000000001000000000000000000; 25 | const IN_ZOOM = 0b000000000000010000000000000000000; 26 | const IN_WEAPON_1 = 0b000000000000100000000000000000000; 27 | const IN_WEAPON_2 = 0b000000000001000000000000000000000; 28 | const IN_BULL_RUSH = 0b000000000010000000000000000000000; 29 | const IN_GRENADE_1 = 0b000000000100000000000000000000000; 30 | const IN_GRENADE_2 = 0b000000001000000000000000000000000; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/structs/cusercmd.rs: -------------------------------------------------------------------------------- 1 | use crate::maths::Vector; 2 | use crate::structs::CmdButton; 3 | 4 | #[derive(Copy, Clone)] 5 | #[repr(C)] 6 | pub struct CUserCMD { 7 | padding: [u8; 4], 8 | pub command_number: i32, 9 | pub tick_count: i32, 10 | pub view_angles: Vector, 11 | pub aim_direction: Vector, 12 | pub forward_move: f32, 13 | pub side_move: f32, 14 | pub up_move: f32, 15 | pub buttons: CmdButton, 16 | pub impulse: u8, 17 | pub weapon_select: i32, 18 | pub weapon_subtype: i32, 19 | pub random_seed: i32, 20 | pub mouse_dx: i16, 21 | pub mouse_dy: i16, 22 | pub predicted: bool, 23 | } 24 | -------------------------------------------------------------------------------- /src/structs/entity.rs: -------------------------------------------------------------------------------- 1 | use netvars::prelude::*; 2 | use vtables::VTable; 3 | use vtables_derive::has_vtable; 4 | use vtables_derive::virtual_index; 5 | use vtables_derive::VTable; 6 | 7 | use crate::interfaces::{EntityList, ModelInfo, NetvarEngine, TraceEngine}; 8 | use crate::maths::Vector; 9 | use crate::structs::{ 10 | BoneFlags, ClientClass, EntityFlags, EntityTeam, HitBoxes, ItemDefIndices, Ray, Trace, 11 | TraceContent, TraceFilterGeneric, 12 | }; 13 | use crate::{interfaces, memory}; 14 | use bitflags::_core::ffi::c_void; 15 | use winapi::um::libloaderapi::GetModuleHandleA; 16 | 17 | #[allow(conflicting_repr_hints)] 18 | #[repr(C, u32)] 19 | pub enum EntityLifeState { 20 | Alive = 0, 21 | Dying, 22 | Dead, 23 | } 24 | 25 | #[repr(C)] 26 | #[has_vtable] 27 | #[derive(VTable, Debug)] 28 | pub struct EntityCollidable { 29 | pub vtable: usize, 30 | } 31 | 32 | #[repr(C)] 33 | #[has_vtable] 34 | #[derive(VTable, Debug)] 35 | pub struct EntityNetworkable { 36 | pub vtable: usize, 37 | } 38 | 39 | #[repr(C)] 40 | #[has_vtable] 41 | #[derive(VTable, Debug)] 42 | pub struct EntityAnimating { 43 | pub vtable: usize, 44 | } 45 | 46 | #[repr(C)] 47 | pub struct EntityModel { 48 | handle: *const std::ffi::c_void, 49 | name: [std::os::raw::c_char; 260], 50 | load_flags: isize, 51 | server_count: isize, 52 | r#type: isize, 53 | flags: isize, 54 | vec_mins: Vector, 55 | vec_maxs: Vector, 56 | radius: f32, 57 | } 58 | 59 | #[repr(C)] 60 | #[derive(Copy, Clone)] 61 | pub struct EntityHandle { 62 | handle: usize, 63 | } 64 | 65 | #[repr(C)] 66 | #[derive(Copy, Clone)] 67 | pub struct EntityIndex { 68 | index: usize, 69 | } 70 | 71 | #[repr(C)] 72 | #[has_vtable] 73 | #[derive(VTable, HasNetvar, Debug)] 74 | pub struct Entity { 75 | pub vtable: usize, 76 | } 77 | 78 | impl EntityCollidable { 79 | #[virtual_index(1)] 80 | pub fn mins(&self) -> &'static Vector {} 81 | 82 | #[virtual_index(2)] 83 | pub fn maxs(&self) -> &'static Vector {} 84 | } 85 | 86 | impl EntityNetworkable { 87 | #[virtual_index(2)] 88 | pub fn get_clientclass(&self) -> &'static mut ClientClass {} 89 | 90 | #[virtual_index(10)] 91 | pub fn index(&self) -> EntityIndex {} 92 | } 93 | 94 | impl EntityAnimating { 95 | #[virtual_index(13)] 96 | pub fn setup_bones( 97 | &self, 98 | out_matrix: *const [[f32; 4]; 3], 99 | max_bones: usize, 100 | mask: usize, 101 | time: f32, 102 | ) -> bool { 103 | } 104 | 105 | #[virtual_index(9)] 106 | pub fn draw_model(&self, flags: isize, alpha: u8) -> () {} 107 | 108 | #[virtual_index(8)] 109 | pub fn model(&self) -> &'static mut EntityModel {} 110 | } 111 | 112 | impl EntityHandle { 113 | pub fn new>(handle: T) -> Self { 114 | Self { 115 | handle: handle.into(), 116 | } 117 | } 118 | } 119 | 120 | impl EntityIndex { 121 | pub fn new>(index: T) -> Self { 122 | Self { 123 | index: index.into(), 124 | } 125 | } 126 | } 127 | 128 | impl From<*const std::ffi::c_void> for EntityHandle { 129 | fn from(handle: *const c_void) -> Self { 130 | Self { 131 | handle: handle as usize, 132 | } 133 | } 134 | } 135 | 136 | impl Into<*const std::ffi::c_void> for EntityHandle { 137 | fn into(self) -> *const c_void { 138 | self.handle as *const c_void 139 | } 140 | } 141 | 142 | impl From for EntityIndex { 143 | fn from(handle: EntityHandle) -> Self { 144 | Self { 145 | index: handle.handle & 0xFFF, 146 | } 147 | } 148 | } 149 | 150 | #[offset_fn(interfaces::get_offset)] 151 | impl Entity { 152 | #[virtual_index(218)] 153 | pub fn update(&self) -> () {} 154 | 155 | #[virtual_index(165)] 156 | pub fn is_weapon(&self) -> bool {} 157 | 158 | #[virtual_index(155)] 159 | pub fn is_player(&self) -> bool {} 160 | 161 | #[virtual_index(3)] 162 | pub fn collidable(&self) -> &'static EntityCollidable {} 163 | 164 | #[netvar(("DT_BasePlayer", "m_iHealth"))] 165 | pub fn health(&self) -> i32 {} 166 | 167 | #[netvar(("DT_CSPlayer", "m_hActiveWeapon"))] 168 | pub fn active_weapon_handle(&self) -> EntityHandle {} 169 | 170 | pub fn active_weapon(&self) -> Option<&'static Entity> { 171 | From::from(EntityIndex::from(self.active_weapon_handle())) 172 | } 173 | 174 | #[netvar(("DT_CSPlayer", "m_lifeState"))] 175 | pub fn lifestate(&self) -> EntityLifeState {} 176 | 177 | pub fn alive(&self) -> bool { 178 | (match self.lifestate() { 179 | EntityLifeState::Alive => true, 180 | _ => false, 181 | }) && self.health() > 0 182 | } 183 | 184 | #[netvar(("CustomTable", "Dormancy"))] 185 | pub fn dormant(&self) -> bool {} 186 | 187 | #[netvar(("DT_CSPlayer", "m_iTeamNum"))] 188 | pub fn team(&self) -> EntityTeam {} 189 | 190 | #[netvar(("DT_BaseEntity", "m_bSpotted"))] 191 | pub fn spotted(&self) -> bool {} 192 | 193 | #[netvar(("DT_CSPlayer", "m_fFlags"))] 194 | pub fn flags(&self) -> EntityFlags {} 195 | 196 | #[netvar(("DT_BaseEntity", "m_hOwnerEntity"))] 197 | pub fn owner_handle(&self) -> EntityHandle {} 198 | 199 | #[netvar(("DT_CSPlayer", "m_flSimulationTime"))] 200 | pub fn simulation_time(&self) -> f32 {} 201 | 202 | #[netvar(("DT_BasePlayer", "m_vecOrigin"))] 203 | pub fn origin(&self) -> Vector {} 204 | 205 | #[netvar(("DT_BasePlayer", "m_aimPunchAngle"))] 206 | pub fn aimpunch(&self) -> Vector {} 207 | 208 | #[netvar(("DT_BasePlayer", "m_viewPunchAngle"))] 209 | pub fn viewpunch(&self) -> Vector {} 210 | 211 | #[netvar(("DT_CSPlayer", "m_iShotsFired"))] 212 | pub fn shotsfired(&self) -> usize {} 213 | 214 | #[netvar(("DT_BasePlayer", "m_vecViewOffset[0]"))] 215 | pub fn view_offset(&self) -> Vector {} 216 | 217 | #[netvar(("CustomTable", "InReload"))] 218 | pub fn is_reloading(&self) -> bool {} 219 | 220 | #[netvar(("DT_BaseCombatWeapon", "m_iClip1"))] 221 | pub fn clip1_rem(&self) -> isize {} 222 | 223 | #[netvar(("DT_CSPlayer", "m_nTickBase"))] 224 | pub fn tickbase(&self) -> isize {} 225 | 226 | #[netvar(("DT_BaseCombatWeapon", "m_flNextPrimaryAttack"))] 227 | pub fn next_primary_attack(&self) -> f32 {} 228 | 229 | #[netvar(("DT_BaseCombatCharacter", "m_flNextAttack"))] 230 | pub fn next_attack(&self) -> f32 {} 231 | 232 | #[netvar(("DT_BasePlayer", "m_vecVelocity[0]"))] 233 | pub fn vel(&self) -> Vector {} 234 | 235 | pub fn weapon_id(&self) -> ItemDefIndices { 236 | unsafe { 237 | *std::mem::transmute::<_, &ItemDefIndices>((self as *const _ as *const u8).add(0x2FAA)) 238 | } 239 | } 240 | 241 | pub fn eye(&self) -> Vector { 242 | self.origin() + self.view_offset() 243 | } 244 | 245 | pub fn is_visible(&self, other: &Entity, position: Vector) -> bool { 246 | let trace: Trace = unsafe { std::mem::zeroed() }; 247 | let ray = Ray::new(self.eye().into(), position); 248 | let mut filter = TraceFilterGeneric::new(self); 249 | TraceEngine::get().trace_ray(&ray, TraceContent::HUH, &filter, &trace); 250 | 251 | trace.ptr_entity as *const _ as usize == other as *const _ as usize || trace.fraction == 1e0 252 | } 253 | 254 | pub fn hitbox_center(&self, id: HitBoxes) -> Option { 255 | let mut bone_matrices = [[[0f32; 4]; 3]; 128]; 256 | if self.animating().setup_bones( 257 | bone_matrices.as_ptr(), 258 | 128, 259 | BoneFlags::BONE_USED_BY_HITBOX.bits(), 260 | 0f32, 261 | ) { 262 | if let Some(studio_model) = ModelInfo::get().studio_model(self.animating().model()) { 263 | if let Some(hitbox_set) = studio_model.hitbox_set(0) { 264 | if let Some(hitbox) = hitbox_set.hitbox(id) { 265 | let bone_matrix = bone_matrices[hitbox.bone]; 266 | 267 | fn transform(bone_matrix: &[[f32; 4]; 3], mins: Vector) -> Vector { 268 | let vec_x: Vector = 269 | [bone_matrix[0][0], bone_matrix[0][1], bone_matrix[0][2]].into(); 270 | 271 | let vec_y: Vector = 272 | [bone_matrix[1][0], bone_matrix[1][1], bone_matrix[1][2]].into(); 273 | 274 | let vec_z: Vector = 275 | [bone_matrix[2][0], bone_matrix[2][1], bone_matrix[2][2]].into(); 276 | 277 | Vector::new( 278 | mins * vec_x + bone_matrix[0][3], 279 | mins * vec_y + bone_matrix[1][3], 280 | mins * vec_z + bone_matrix[2][3], 281 | ) 282 | } 283 | 284 | let mut res = transform(&bone_matrix, hitbox.mins.into()) 285 | + transform(&bone_matrix, hitbox.maxs.into()); 286 | res.as_mut().iter_mut().for_each(|x| *x /= 2e0); 287 | 288 | return Some(res); 289 | } 290 | } 291 | } 292 | } 293 | 294 | None 295 | } 296 | 297 | pub fn animating(&self) -> &'static EntityAnimating { 298 | unsafe { std::mem::transmute((self as *const _ as *const usize).offset(1)) } 299 | } 300 | 301 | pub fn networkable(&self) -> &'static EntityNetworkable { 302 | unsafe { std::mem::transmute((self as *const _ as *const usize).offset(2)) } 303 | } 304 | 305 | //Is this even useful? 306 | /// #Returns an EntityIterator that starts from the current entity 307 | pub fn iter(&self) -> EntityIterator { 308 | EntityIterator { 309 | count: self.networkable().index().index, 310 | } 311 | } 312 | 313 | pub fn local() -> Option<&'static Self> { 314 | match *interfaces::LOCAL_PLAYER_PTR.lock().unwrap() { 315 | 0 => None, 316 | ptr => Some(unsafe { std::mem::transmute::<_, &'static Self>(ptr) }), 317 | } 318 | } 319 | } 320 | 321 | impl From for Option<&'static Entity> { 322 | fn from(handle: EntityHandle) -> Self { 323 | let ptr = EntityList::get().entity_ptr_from_handle(handle); 324 | 325 | if ptr.is_null() { 326 | None 327 | } else { 328 | Some(unsafe { std::mem::transmute::<_, &'static Entity>(ptr) }) 329 | } 330 | } 331 | } 332 | 333 | impl From for Option<&'static Entity> { 334 | fn from(index: EntityIndex) -> Self { 335 | let ptr = EntityList::get().entity_ptr_from_index(index); 336 | if ptr.is_null() { 337 | None 338 | } else { 339 | Some(unsafe { std::mem::transmute::<_, &'static Entity>(ptr) }) 340 | } 341 | } 342 | } 343 | 344 | impl PartialEq<&'static Entity> for &'static Entity { 345 | fn eq(&self, other: &&'static Entity) -> bool { 346 | (*self as *const Entity).eq(&(*other as *const Entity)) 347 | } 348 | } 349 | 350 | pub struct EntityIterator { 351 | count: usize, 352 | } 353 | 354 | impl EntityIterator { 355 | pub fn new() -> Self { 356 | Self { count: 1 } 357 | } 358 | } 359 | 360 | impl Iterator for EntityIterator { 361 | type Item = Option<&'static Entity>; 362 | 363 | fn next(&mut self) -> Option { 364 | let ret = if self.count <= EntityList::get().highest_entity_index() { 365 | Some(From::from(EntityIndex::new(self.count))) 366 | } else { 367 | None 368 | }; 369 | 370 | self.count += 1; 371 | 372 | ret 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /src/structs/entityflags.rs: -------------------------------------------------------------------------------- 1 | use bitflags::bitflags; 2 | 3 | bitflags! { 4 | #[repr(C)] 5 | pub struct EntityFlags: u32 { 6 | const ON_GROUND = 0b000000000000000000000000000000001; 7 | const DUCKING = 0b000000000000000000000000000000010; 8 | const WATER_JUMP = 0b000000000000000000000000000000100; 9 | const ON_TRAIN = 0b000000000000000000000000000001000; 10 | const IN_RAIN = 0b000000000000000000000000000010000; 11 | const FROZEN = 0b000000000000000000000000000100000; 12 | const AT_CONTROLS = 0b000000000000000000000000001000000; 13 | const CLIENT = 0b000000000000000000000000010000000; 14 | const FAKE_CLIENT = 0b000000000000000000000000100000000; 15 | const IN_WATER = 0b000000000000000000000001000000000; 16 | const FLY = 0b000000000000000000000010000000000; 17 | const SWIM = 0b000000000000000000000100000000000; 18 | const CONVEYOR = 0b000000000000000000001000000000000; 19 | const NPC = 0b000000000000000000010000000000000; 20 | const GOD_MODE = 0b000000000000000000100000000000000; 21 | const NO_TARGET = 0b000000000000000001000000000000000; 22 | const AIM_TARGET = 0b000000000000000010000000000000000; 23 | const PARTIAL_GROUND = 0b000000000000000100000000000000000; 24 | const STATIC_PROP = 0b000000000000001000000000000000000; 25 | const GRAPHED = 0b000000000000010000000000000000000; 26 | const GRENADE = 0b000000000000100000000000000000000; 27 | const STEP_MOVEMENT = 0b000000000001000000000000000000000; 28 | const DONT_TOUCH = 0b000000000010000000000000000000000; 29 | const BASE_VELOCITY = 0b000000000100000000000000000000000; 30 | const WORLD_BRUSH = 0b000000001000000000000000000000000; 31 | const OBJECT = 0b000000010000000000000000000000000; 32 | const KILL_ME = 0b000000100000000000000000000000000; 33 | const ON_FIRE = 0b000001000000000000000000000000000; 34 | const DISSOLVING = 0b000010000000000000000000000000000; 35 | const TRANS_RAG_DOLL = 0b000100000000000000000000000000000; 36 | const UN_BLOCKABLE_BY_PLAYER = 0b001000000000000000000000000000000; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/structs/entityteam.rs: -------------------------------------------------------------------------------- 1 | #[allow(conflicting_repr_hints)] 2 | #[repr(C, i32)] 3 | #[derive(Copy, Clone, PartialEq)] 4 | pub enum EntityTeam { 5 | CT = 3, 6 | T = 2, 7 | SPECTATOR = 1, 8 | NONE = 0, 9 | } 10 | -------------------------------------------------------------------------------- /src/structs/global.rs: -------------------------------------------------------------------------------- 1 | use std::os::raw::c_void; 2 | 3 | #[repr(C)] 4 | pub struct CGlobalVars { 5 | pub realtime: f32, 6 | pub frame_count: i32, 7 | pub absolute_frame_time: f32, 8 | pub absolute_frame_start: f32, 9 | pub cur_time: f32, 10 | pub frame_time: f32, 11 | pub max_clients: i32, 12 | pub tick_count: i32, 13 | pub interval_per_tick: f32, 14 | pub interpolation_amount: f32, 15 | pub sim_ticks: i32, 16 | pub network_protocol: i32, 17 | pub save_data: *const c_void, 18 | pub client: bool, 19 | pub remote_client: bool, 20 | } 21 | -------------------------------------------------------------------------------- /src/structs/item_definition_indices.rs: -------------------------------------------------------------------------------- 1 | #[allow(conflicting_repr_hints)] 2 | #[repr(C, u16)] 3 | #[derive(Copy, Clone)] 4 | pub enum ItemDefIndices { 5 | None = 0, 6 | DEAGLE, 7 | ELITE, 8 | FIVESEVEN, 9 | GLOCK, 10 | AK47 = 7, 11 | AUG, 12 | AWP, 13 | FAMAS, 14 | G3SG1, 15 | GALILAR = 13, 16 | M249, 17 | M4A1 = 16, 18 | MAC10, 19 | P90 = 19, 20 | MP5SD = 23, 21 | UMP45, 22 | XM1014, 23 | BIZON, 24 | MAG7, 25 | NEGEV, 26 | SAWEDOFF, 27 | TEC9, 28 | TASER, 29 | HKP2000, 30 | MP7, 31 | MP9, 32 | NOVA, 33 | P250, 34 | SHIELD, 35 | SCAR20, 36 | SG556, 37 | SSG08, 38 | KNIFEGG, 39 | KNIFE, 40 | FLASHBANG, 41 | HEGRENADE, 42 | SMOKEGRENADE, 43 | MOLOTOV, 44 | DECOY, 45 | INCGRENADE, 46 | C4, 47 | HEALTHSHOT = 57, 48 | KNIFE_T = 59, 49 | M4A1_SILENCER, 50 | USP_SILENCER, 51 | CZ75A = 63, 52 | REVOLVER, 53 | TAGRENADE = 68, 54 | FISTS, 55 | BREACHCHARGE, 56 | TABLET = 72, 57 | MELEE = 74, 58 | AXE, 59 | HAMMER, 60 | SPANNER = 78, 61 | KNIFE_GHOST = 80, 62 | FIREBOMB, 63 | DIVERSION, 64 | FRAG_GRENADE, 65 | SNOWBALL, 66 | BUMPMINE, 67 | BAYONET = 500, 68 | KNIFE_CSS = 503, 69 | KNIFE_FLIP = 505, 70 | KNIFE_GUT, 71 | KNIFE_KARAMBIT, 72 | KNIFE_M9_BAYONET, 73 | KNIFE_TACTICAL, 74 | KNIFE_FALCHION = 512, 75 | KNIFE_SURVIVAL_BOWIE = 514, 76 | KNIFE_BUTTERFLY, 77 | KNIFE_PUSH, 78 | KNIFE_URSUS = 519, 79 | KNIFE_GYPSY_JACKKNIFE, 80 | KNIFE_STILETTO = 522, 81 | KNIFE_WIDOWMAKER, 82 | GLOVE_STUDDED_BLOODHOUND = 5027, 83 | GLOVE_T_SIDE = 5028, 84 | GLOVE_CT_SIDE = 5029, 85 | GLOVE_SPORTY = 5030, 86 | GLOVE_SLICK = 5031, 87 | GLOVE_LEATHER_WRAP = 5032, 88 | GLOVE_MOTORCYCLE = 5033, 89 | GLOVE_SPECIALIST = 5034, 90 | GLOVE_HYDRA = 5035, 91 | } 92 | -------------------------------------------------------------------------------- /src/structs/mod.rs: -------------------------------------------------------------------------------- 1 | pub use clientclass::ClientClass; 2 | pub use clientclassid::ClientClassId; 3 | pub use cmdbutton::CmdButton; 4 | pub use cusercmd::CUserCMD; 5 | pub use entity::{ 6 | Entity, EntityAnimating, EntityCollidable, EntityHandle, EntityIndex, EntityIterator, 7 | EntityLifeState, EntityModel, EntityNetworkable, 8 | }; 9 | pub use entityflags::EntityFlags; 10 | pub use entityteam::EntityTeam; 11 | pub use global::CGlobalVars; 12 | pub use item_definition_indices::ItemDefIndices; 13 | pub use paneltype::PanelType; 14 | pub use recvprop::*; 15 | pub use studio::{BoneFlags, HitBoxes, HitGroup, StudioBone, StudioBox, StudioBoxSet, StudioHdr}; 16 | pub use traceflags::{TraceContent, TraceSurf}; 17 | pub use tracestructs::{Ray, Trace, TraceFilterGeneric, TraceFilterTrait, TraceType}; 18 | 19 | mod clientclass; 20 | mod clientclassid; 21 | mod cmdbutton; 22 | mod cusercmd; 23 | mod entity; 24 | mod entityflags; 25 | mod entityteam; 26 | mod global; 27 | mod item_definition_indices; 28 | mod paneltype; 29 | mod recvprop; 30 | mod studio; 31 | mod traceflags; 32 | mod tracestructs; 33 | -------------------------------------------------------------------------------- /src/structs/paneltype.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone)] 2 | pub enum PanelType { 3 | MatSystemTop(usize), 4 | } 5 | -------------------------------------------------------------------------------- /src/structs/recvprop.rs: -------------------------------------------------------------------------------- 1 | use crate::maths::Vector; 2 | use std::os::raw::{c_char, c_void}; 3 | 4 | pub type RecvVarProxyFn = 5 | fn(data: *const CRecvProxy, struct_ptr: *mut c_void, out_ptr: *mut c_void); 6 | pub type ArrayLengthRecvProxyFn = 7 | fn(struct_ptr: *mut c_void, object_id: i32, current_array_length: i32); 8 | pub type DataTableRecvVarProxyFn = 9 | fn(prop: *const CRecvProp, out_ptr: *mut *mut c_void, data_ptr: *mut c_void, object_id: i32); 10 | 11 | #[repr(i32)] 12 | #[derive(Copy, Clone, Debug, PartialEq)] 13 | pub enum EPropType { 14 | Int = 0, 15 | Float, 16 | Vec, 17 | VecXY, 18 | String, 19 | Array, 20 | DataTable, 21 | Int64, 22 | } 23 | 24 | #[repr(C)] 25 | pub union CVariantData { 26 | pub float: f32, 27 | pub int: i32, 28 | pub string: *const c_char, 29 | pub data: *mut c_void, 30 | pub vector: Vector, 31 | pub int64: i64, 32 | } 33 | 34 | #[repr(C)] 35 | pub struct CVariant { 36 | pub data: CVariantData, 37 | pub prop_type: EPropType, 38 | } 39 | 40 | #[repr(C)] 41 | #[derive(Debug)] 42 | pub struct CRecvTable { 43 | pub p_props: *mut CRecvProp, 44 | pub n_props: usize, 45 | pub decoder: *const c_void, 46 | pub table_name: *const c_char, 47 | pub is_initialized: bool, 48 | pub is_in_main_list: bool, 49 | } 50 | 51 | unsafe impl Send for CRecvTable {} 52 | 53 | unsafe impl Sync for CRecvTable {} 54 | 55 | #[repr(C)] 56 | #[derive(Debug, Copy, Clone)] 57 | pub struct CRecvProp { 58 | pub prop_name: *const c_char, 59 | pub prop_type: EPropType, 60 | pub prop_flags: i32, 61 | pub buffer_size: i32, 62 | pub is_inside_array: i32, 63 | pub extra_data_ptr: *const c_void, 64 | pub array_prop: *const CRecvProp, 65 | pub array_length_proxy: ArrayLengthRecvProxyFn, 66 | pub proxy_fn: RecvVarProxyFn, 67 | pub data_table_proxy_fn: DataTableRecvVarProxyFn, 68 | pub data_table: *mut CRecvTable, 69 | pub offset: i32, 70 | pub element_stride: i32, 71 | pub elements_count: i32, 72 | pub parent_array_prop_name: *const c_char, 73 | } 74 | 75 | #[repr(C)] 76 | pub struct CRecvProxy { 77 | pub recv_prop: *const CRecvProp, 78 | pub value: CVariant, 79 | pub element_index: i32, 80 | pub object_id: i32, 81 | } 82 | -------------------------------------------------------------------------------- /src/structs/studio.rs: -------------------------------------------------------------------------------- 1 | use crate::maths::Vector; 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | #[repr(C)] 6 | pub struct BoneFlags: usize { 7 | const BONE_CALCULATE_MASK = 0x1f; 8 | const BONE_PHYSICALLY_SIMULATED = 0x01; 9 | const BONE_PHYSICS_PROCEDURAL = 0x02; 10 | const BONE_ALWAYS_PROCEDURAL = 0x04; 11 | const BONE_SCREEN_ALIGN_SPHERE = 0x08; 12 | const BONE_SCREEN_ALIGN_CYLINDER = 0x10; 13 | const BONE_USED_MASK = 0x0007ff00; 14 | const BONE_USED_BY_ANYTHING = 0x0007ff00; 15 | const BONE_USED_BY_HITBOX = 0x00000100; 16 | const BONE_USED_BY_ATTACHMENT = 0x00000200; 17 | const BONE_USED_BY_VERTEX_mask = 0x0003fc00; 18 | const BONE_USED_BY_VERTEX_LOD0 = 0x00000400; 19 | const BONE_USED_BY_VERTEX_LOD1 = 0x00000800; 20 | const BONE_USED_BY_VERTEX_LOD2 = 0x00001000; 21 | const BONE_USED_BY_VERTEX_LOD3 = 0x00002000; 22 | const BONE_USED_BY_VERTEX_LOD4 = 0x00004000; 23 | const BONE_USED_BY_VERTEX_LOD5 = 0x00008000; 24 | const BONE_USED_BY_VERTEX_LOD6 = 0x00010000; 25 | const BONE_USED_BY_VERTEX_LOD7 = 0x00020000; 26 | const BONE_USED_BY_BONE_MERGE = 0x00040000; 27 | const BONE_TYPE_MASK = 0x00f00000; 28 | const BONE_FIXED_ALIGNMENT = 0x00100000; 29 | const BONE_HAS_SAVEFRAME_POS = 0x00200000; 30 | const BONE_HAS_SAVEFRAME_ROT = 0x00400000; 31 | } 32 | } 33 | 34 | #[repr(C)] 35 | #[derive(Copy, Clone)] 36 | pub enum HitGroup { 37 | Generic, 38 | Head, 39 | Chest, 40 | Stomach, 41 | LeftArm, 42 | RightArm, 43 | LeftLeg, 44 | RightLeg, 45 | Gear = 10, 46 | } 47 | 48 | #[repr(C)] 49 | #[derive(Copy, Clone)] 50 | pub enum ModType { 51 | Bad0, 52 | Brush, 53 | Sprite, 54 | Studio, 55 | } 56 | 57 | #[repr(C)] 58 | #[derive(Copy, Clone)] 59 | pub enum HitBoxes { 60 | Head, 61 | Neck, 62 | Pelvis, 63 | Stomach, 64 | LowerChest, 65 | Chest, 66 | UpperChest, 67 | RightThigh, 68 | LeftThigh, 69 | RightCalf, 70 | LeftCalf, 71 | RightFoot, 72 | LeftFoot, 73 | RightHand, 74 | LeftHand, 75 | RightUpperArm, 76 | RightForeArm, 77 | LeftUpperArm, 78 | LeftForeArm, 79 | Max, 80 | } 81 | 82 | use std::convert::TryFrom; 83 | 84 | impl TryFrom for HitBoxes { 85 | type Error = (); 86 | 87 | fn try_from(v: usize) -> Result { 88 | match v { 89 | x if x == HitBoxes::Head as usize => Ok(HitBoxes::Head), 90 | x if x == HitBoxes::Neck as usize => Ok(HitBoxes::Neck), 91 | x if x == HitBoxes::Pelvis as usize => Ok(HitBoxes::Pelvis), 92 | x if x == HitBoxes::Stomach as usize => Ok(HitBoxes::Stomach), 93 | x if x == HitBoxes::LowerChest as usize => Ok(HitBoxes::LowerChest), 94 | x if x == HitBoxes::Chest as usize => Ok(HitBoxes::Chest), 95 | x if x == HitBoxes::UpperChest as usize => Ok(HitBoxes::UpperChest), 96 | x if x == HitBoxes::RightThigh as usize => Ok(HitBoxes::RightThigh), 97 | x if x == HitBoxes::LeftThigh as usize => Ok(HitBoxes::LeftThigh), 98 | x if x == HitBoxes::RightCalf as usize => Ok(HitBoxes::RightCalf), 99 | x if x == HitBoxes::LeftCalf as usize => Ok(HitBoxes::LeftCalf), 100 | x if x == HitBoxes::RightFoot as usize => Ok(HitBoxes::RightFoot), 101 | x if x == HitBoxes::LeftFoot as usize => Ok(HitBoxes::LeftFoot), 102 | x if x == HitBoxes::RightHand as usize => Ok(HitBoxes::RightHand), 103 | x if x == HitBoxes::LeftHand as usize => Ok(HitBoxes::LeftHand), 104 | x if x == HitBoxes::RightUpperArm as usize => Ok(HitBoxes::RightUpperArm), 105 | x if x == HitBoxes::RightForeArm as usize => Ok(HitBoxes::RightForeArm), 106 | x if x == HitBoxes::LeftUpperArm as usize => Ok(HitBoxes::LeftUpperArm), 107 | x if x == HitBoxes::LeftForeArm as usize => Ok(HitBoxes::LeftForeArm), 108 | _ => Err(()), 109 | } 110 | } 111 | } 112 | 113 | #[repr(C)] 114 | pub struct StudioBone { 115 | name_index: usize, 116 | parent: i32, 117 | bone_controller: [i32; 6], 118 | pos: Vector, 119 | quat: [f32; 4], 120 | rotation: Vector, 121 | pos_scale: Vector, 122 | rot_scale: Vector, 123 | pose_to_bone: [[f32; 4]; 3], 124 | quat_alignment: [f32; 4], 125 | flags: usize, 126 | proc_type: usize, 127 | proc_index: usize, 128 | physics_bone: usize, 129 | surface_prop_idx: usize, 130 | contents: i32, 131 | surf_prop_lookup: i32, 132 | __junk_0: [u8; 28], 133 | } 134 | 135 | #[repr(C)] 136 | pub struct StudioBox { 137 | pub bone: usize, 138 | group: usize, 139 | pub mins: Vector, 140 | pub maxs: Vector, 141 | name_idx: usize, 142 | __pad_0: [u8; 12], 143 | radius: f32, 144 | __junk_0: [u8; 16], 145 | } 146 | 147 | #[repr(C)] 148 | pub struct StudioBoxSet { 149 | name_idx: usize, 150 | hitbox_count: usize, 151 | hitbox_index: usize, 152 | } 153 | 154 | impl StudioBoxSet { 155 | pub fn name(&self) -> Option<&str> { 156 | use std::ffi::CStr; 157 | unsafe { 158 | CStr::from_ptr((self as *const _ as *const i8).add(self.name_idx)) 159 | .to_str() 160 | .ok() 161 | } 162 | } 163 | 164 | pub fn hitbox(&self, idx: HitBoxes) -> Option<&'static mut StudioBox> { 165 | let ptr = unsafe { 166 | ((self as *const _ as *const i8).add(self.hitbox_index) as *const StudioBox) 167 | .add(idx as usize) 168 | }; 169 | 170 | if ptr.is_null() { 171 | None 172 | } else { 173 | Some(unsafe { std::mem::transmute(ptr) }) 174 | } 175 | } 176 | } 177 | 178 | #[repr(C)] 179 | pub struct StudioHdr { 180 | id: usize, 181 | version: i32, 182 | checksum: usize, 183 | name: [u8; 64], 184 | length: usize, 185 | eye_pos: Vector, 186 | illium_pos: Vector, 187 | hull_mins: Vector, 188 | hull_maxs: Vector, 189 | mins: Vector, 190 | maxs: Vector, 191 | flags: usize, 192 | bones_count: usize, 193 | bone_idx: usize, 194 | bone_controllers_count: usize, 195 | bone_controllers_idx: usize, 196 | hitbox_sets_count: usize, 197 | hitbox_sets_idx: usize, 198 | local_anim_count: usize, 199 | local_anim_idx: usize, 200 | local_seq_count: usize, 201 | local_seq_idx: usize, 202 | activity_list_version: usize, 203 | events_indexed: usize, 204 | texture_count: usize, 205 | texture_index: usize, 206 | } 207 | 208 | impl StudioHdr { 209 | pub fn hitbox_set(&self, idx: usize) -> Option<&'static mut StudioBoxSet> { 210 | if idx > self.hitbox_sets_count { 211 | None 212 | } else { 213 | Some(unsafe { 214 | std::mem::transmute( 215 | ((self as *const _ as *const i8).add(self.hitbox_sets_idx) 216 | as *const StudioBoxSet) 217 | .add(idx), 218 | ) 219 | }) 220 | } 221 | } 222 | 223 | pub fn bone(&self, idx: usize) -> Option<&'static mut StudioBone> { 224 | if idx > self.bones_count { 225 | None 226 | } else { 227 | Some(unsafe { 228 | std::mem::transmute( 229 | ((self as *const _ as *const i8).add(self.bone_idx) as *const Self).add(idx), 230 | ) 231 | }) 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/structs/traceflags.rs: -------------------------------------------------------------------------------- 1 | use bitflags::bitflags; 2 | 3 | bitflags! { 4 | #[repr(C)] 5 | pub struct TraceSurf: u32{ 6 | const LIGHT = 0b00000000000000000000000000000001; 7 | const SKY2D = 0b00000000000000000000000000000010; 8 | const SKY = 0b00000000000000000000000000000100; 9 | const WARP = 0b00000000000000000000000000001000; 10 | const NOPORTAL = 0b00000000000000000000000000010000; 11 | const TRIGGER = 0b00000000000000000000000000100000; 12 | const NODRAW = 0b00000000000000000000000001000000; 13 | const HINT = 0b00000000000000000000000010000000; 14 | const SKIP = 0b00000000000000000000000100000000; 15 | const NOLIGHT = 0b00000000000000000000001000000000; 16 | const BUMPLIGHT = 0b00000000000000000000010000000000; 17 | const NOSHADOWS = 0b00000000000000000000100000000000; 18 | const NODECALS = 0b00000000000000000001000000000000; 19 | const NOPAINT = 0b00000000000000000010000000000000; 20 | const NOCHOP = 0b00000000000000000100000000000000; 21 | const HITBOX = 0b00000000000000001000000000000000; 22 | } 23 | } 24 | 25 | bitflags! { 26 | #[repr(C)] 27 | pub struct TraceContent: u32{ 28 | const EMPTY = 0b00000000000000000000000000000000; 29 | const SOLID = 0b00000000000000000000000000000001; 30 | const WINDOW = 0b00000000000000000000000000000010; 31 | const AUX = 0b00000000000000000000000000000100; 32 | const GRATE = 0b00000000000000000000000000001000; 33 | const SLIME = 0b00000000000000000000000000010000; 34 | const WATER = 0b00000000000000000000000000100000; 35 | const MIST = 0b00000000000000000000000001000000; 36 | const OPAQUE = 0b00000000000000000000000010000000; 37 | const LAST_VISIBLE_CONTENTS = 0b00000000000000000000000010000000; 38 | const ALL_VISIBLE_CONTENTS = Self::LAST_VISIBLE_CONTENTS.bits | (Self::LAST_VISIBLE_CONTENTS.bits-1); 39 | const TESTFOGVOLUME = 0b00000000000000000000000100000000; 40 | const UNUSED5 = 0b00000000000000000000001000000000; 41 | const UNUSED6 = 0b00000000000000000000010000000000; 42 | const TEAM1 = 0b00000000000000000000100000000000; 43 | const TEAM2 = 0b00000000000000000001000000000000; 44 | const IGNORE_NODRAW_OPAQUE = 0b00000000000000000010000000000000; 45 | const MOVEABLE = 0b00000000000000000100000000000000; 46 | const AREAPORTAL = 0b00000000000000001000000000000000; 47 | const PLAYERCLIP = 0b00000000000000010000000000000000; 48 | const MONSTERCLIP = 0b00000000000000100000000000000000; 49 | const CURRENT_0 = 0b00000000000001000000000000000000; 50 | const CURRENT_90 = 0b00000000000010000000000000000000; 51 | const CURRENT_180 = 0b00000000000100000000000000000000; 52 | const CURRENT_270 = 0b00000000001000000000000000000000; 53 | const CURRENT_UP = 0b00000000010000000000000000000000; 54 | const CURRENT_DOWN = 0b00000000100000000000000000000000; 55 | const ORIGIN = 0b00000001000000000000000000000000; 56 | const MONSTER = 0b00000010000000000000000000000000; 57 | const DEBRIS = 0b00000100000000000000000000000000; 58 | const DETAIL = 0b00001000000000000000000000000000; 59 | const TRANSLUCENT = 0b00010000000000000000000000000000; 60 | const LADDER = 0b00100000000000000000000000000000; 61 | const HITBOX = 0b01000000000000000000000000000000; 62 | const MASK_ALL = 0b11111111111111111111111111111111; 63 | const MASK_SOLID = Self::SOLID.bits | Self::MOVEABLE.bits | Self::WINDOW.bits | Self::MONSTER.bits | Self::GRATE.bits; 64 | const MASK_PLAYER_SOLID = Self::SOLID.bits | Self::MOVEABLE.bits | Self::PLAYERCLIP.bits | Self::WINDOW.bits | Self::MONSTER.bits | Self::GRATE.bits; 65 | const MASK_NPC_SOLID = Self::SOLID.bits | Self::MOVEABLE.bits | Self::MONSTERCLIP.bits | Self::WINDOW.bits | Self::MONSTER.bits | Self::GRATE.bits; 66 | const MASK_WATER = Self::WATER.bits | Self::MOVEABLE.bits | Self::SLIME.bits; 67 | const MASK_SHOT = Self::SOLID.bits | Self::MOVEABLE.bits | Self::WINDOW.bits | Self::MONSTER.bits | Self::DEBRIS.bits | Self::HITBOX.bits; 68 | const HUH = 0x4600400B; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/structs/tracestructs.rs: -------------------------------------------------------------------------------- 1 | use crate::maths::Vector; 2 | use crate::structs::Entity; 3 | 4 | #[repr(C, align(16))] 5 | #[derive(Copy, Clone, Default)] 6 | struct VectorAligned { 7 | x: f32, 8 | y: f32, 9 | z: f32, 10 | w: f32, 11 | } 12 | 13 | impl From for VectorAligned { 14 | fn from(vec: Vector) -> Self { 15 | Self { 16 | x: vec.x as f32, 17 | y: vec.y as f32, 18 | z: vec.z as f32, 19 | w: 0e0, 20 | } 21 | } 22 | } 23 | 24 | impl From for Vector { 25 | fn from(vec_aligned: VectorAligned) -> Self { 26 | Self::new(vec_aligned.x, vec_aligned.y, vec_aligned.z) 27 | } 28 | } 29 | 30 | #[repr(C)] 31 | #[derive(Copy, Clone)] 32 | pub struct Ray { 33 | start: VectorAligned, 34 | delta: VectorAligned, 35 | start_offset: VectorAligned, 36 | extents: VectorAligned, 37 | pub p_world_axis_transform_matrix: *const std::ffi::c_void, 38 | pub is_ray: bool, 39 | pub is_swept: bool, 40 | } 41 | 42 | impl Ray { 43 | pub fn new(start: Vector, end: Vector) -> Self { 44 | let mut instance = unsafe { std::mem::zeroed::() }; 45 | instance.delta = VectorAligned::from(end - start); 46 | instance.start = VectorAligned::from(start); 47 | instance.is_swept = Vector::from(instance.delta).len_sqr() != 0e0; 48 | instance.is_ray = true; 49 | instance 50 | } 51 | } 52 | 53 | #[repr(C)] 54 | #[derive(Copy, Clone)] 55 | pub struct CSurface { 56 | pub name: *const i8, 57 | pub surface_props: i16, 58 | pub flags: u16, 59 | } 60 | 61 | #[repr(C)] 62 | #[derive(Copy, Clone)] 63 | pub struct CPlane { 64 | pub normal: Vector, 65 | pub dist: f32, 66 | pub r#type: u8, 67 | pub sign_bit: u8, 68 | pad: [u8; 2], 69 | } 70 | 71 | #[repr(C)] 72 | #[derive(Copy, Clone)] 73 | pub struct Trace { 74 | pub start: Vector, 75 | pub end: Vector, 76 | pub plane: CPlane, 77 | pub fraction: f32, 78 | pub contents: i32, 79 | pub disp_flags: u16, 80 | pub all_solid: bool, 81 | pub start_solid: bool, 82 | pub fraction_solid_left: f32, 83 | pub surface: CSurface, 84 | pub hit_group: i32, 85 | pub physics_bone: i16, 86 | pub ptr_entity: &'static Entity, 87 | pub hitbox: i32, 88 | } 89 | 90 | #[repr(C)] 91 | pub enum TraceType { 92 | EVERYTHING = 0, 93 | WORLD_ONLY, 94 | ENTITIES_ONLY, 95 | EVERYTHING_FILTER_PROPS, 96 | } 97 | 98 | pub trait TraceFilterTrait { 99 | fn should_hit_entity(&self, entity: &Entity, contents_mask: u32) -> bool; 100 | fn get_trace_type(&self) -> TraceType; 101 | } 102 | 103 | #[repr(C)] 104 | pub struct TraceFilterGeneric { 105 | vtable: usize, 106 | skip: *const Entity, 107 | vec_vtable: Vec, 108 | } 109 | 110 | impl TraceFilterGeneric { 111 | pub fn new(skip: &Entity) -> Self { 112 | extern "thiscall" fn should_hit_entity_wrapper( 113 | this: &TraceFilterGeneric, 114 | entity: &Entity, 115 | contents_mask: u32, 116 | ) -> bool { 117 | TraceFilterGeneric::should_hit_entity(this, entity, contents_mask) 118 | } 119 | 120 | extern "thiscall" fn get_trace_type_wrapper(this: &TraceFilterGeneric) -> TraceType { 121 | TraceFilterGeneric::get_trace_type(this) 122 | } 123 | 124 | let mut vec = Vec::::new(); 125 | 126 | vec.push(should_hit_entity_wrapper as usize); 127 | vec.push(get_trace_type_wrapper as usize); 128 | 129 | Self { 130 | vtable: vec.as_ptr() as usize, 131 | skip, 132 | vec_vtable: vec, 133 | } 134 | } 135 | } 136 | 137 | impl TraceFilterTrait for TraceFilterGeneric { 138 | fn should_hit_entity(&self, entity: &Entity, contents_mask: u32) -> bool { 139 | entity as *const _ as usize != self.skip as *const _ as usize 140 | } 141 | 142 | fn get_trace_type(&self) -> TraceType { 143 | TraceType::EVERYTHING 144 | } 145 | } 146 | --------------------------------------------------------------------------------