Big update
This repository is no longer meant for just radarflow, thus it will be renamed. I have split the SDK from radarflow, allowing for simpler use with new projects. Other than that, radarflow is functionally the same. - Fixed bug in radarflow where the entity loop didn't include the last entity.
This commit is contained in:
		
							
								
								
									
										130
									
								
								csflow/src/context.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								csflow/src/context.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| use memflow::{plugins::{IntoProcessInstanceArcBox, Inventory, ConnectorArgs, args::Args}, os::{ModuleInfo, Os, Process}, mem::MemoryView, types::Address}; | ||||
|  | ||||
| use crate::{error::Error, structs::{CPlayerController, CBaseEntity}, cs2dumper, traits::MemoryClass}; | ||||
|  | ||||
| pub struct CheatCtx { | ||||
|     pub process: IntoProcessInstanceArcBox<'static>, | ||||
|     pub client_module: ModuleInfo, | ||||
|     pub engine_module: ModuleInfo, | ||||
| } | ||||
|  | ||||
| impl CheatCtx { | ||||
|     fn check_version(&mut self) -> Result<(), Error> { | ||||
|         let game_build_number: u32 = self.process.read(self.engine_module.base + cs2dumper::offsets::engine2_dll::dwBuildNumber)?; | ||||
|         let offset_build_number = cs2dumper::offsets::game_info::buildNumber; | ||||
|  | ||||
|         if game_build_number as usize != offset_build_number { | ||||
|             return Err(Error::GameVersionMismatch(game_build_number as usize, offset_build_number)) | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn setup(connector: Connector, pcileech_device: String) -> Result<CheatCtx, Error> { | ||||
|         let inventory = Inventory::scan(); | ||||
|  | ||||
|         let os = {  | ||||
|             if connector == Connector::Pcileech { | ||||
|                 let args = Args::new() | ||||
|                     .insert("device", &pcileech_device); | ||||
|  | ||||
|                 let connector_args = ConnectorArgs::new(None, args, None);                 | ||||
|  | ||||
|                 inventory.builder() | ||||
|                     .connector(&connector.to_string()) | ||||
|                     .args(connector_args) | ||||
|                     .os("win32") | ||||
|                     .build()? | ||||
|             } else { | ||||
|                 inventory.builder() | ||||
|                 .connector(&connector.to_string()) | ||||
|                 .os("win32") | ||||
|                 .build()? | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let mut process = os.into_process_by_name("cs2.exe")?; | ||||
|  | ||||
|         let client_module = process.module_by_name("client.dll")?; | ||||
|  | ||||
|         let engine_module = process.module_by_name("engine2.dll")?; | ||||
|  | ||||
|         let mut ctx = Self { | ||||
|             process, | ||||
|             client_module, | ||||
|             engine_module, | ||||
|         }; | ||||
|  | ||||
|         ctx.check_version()?; | ||||
|  | ||||
|         Ok(ctx) | ||||
|     } | ||||
|  | ||||
|     pub fn get_local(&mut self) -> Result<CPlayerController, Error> { | ||||
|         let ptr = self.process.read_addr64(self.client_module.base + cs2dumper::offsets::client_dll::dwLocalPlayerController)?; | ||||
|         Ok(CPlayerController::new(ptr)) | ||||
|     } | ||||
|      | ||||
|     pub fn get_plantedc4(&mut self) -> Result<CBaseEntity, Error> { | ||||
|         let ptr = self.process.read_addr64(self.client_module.base + cs2dumper::offsets::client_dll::dwPlantedC4)?; | ||||
|         let ptr2 = self.process.read_addr64(ptr)?; | ||||
|         Ok(CBaseEntity::new(ptr2)) | ||||
|     } | ||||
|      | ||||
|     pub fn is_bomb_planted(&mut self) -> Result<bool, Error> { | ||||
|         let game_rules = self.process.read_addr64(self.client_module.base + cs2dumper::offsets::client_dll::dwGameRules)?; | ||||
|         let data: u8 = self.process.read(game_rules + cs2dumper::client::C_CSGameRules::m_bBombPlanted)?; | ||||
|         Ok(data != 0) | ||||
|     } | ||||
|      | ||||
|     pub fn is_bomb_dropped(&mut self) -> Result<bool, Error> { | ||||
|         let game_rules = self.process.read_addr64(self.client_module.base + cs2dumper::offsets::client_dll::dwGameRules)?; | ||||
|         let data: u8 = self.process.read(game_rules + cs2dumper::client::C_CSGameRules::m_bBombDropped)?; | ||||
|         Ok(data != 0) | ||||
|     } | ||||
|  | ||||
|     pub fn get_entity_list(&mut self) -> Result<Address, Error> { | ||||
|         let ptr = self.process.read_addr64(self.client_module.base + cs2dumper::offsets::client_dll::dwEntityList)?; | ||||
|         Ok(ptr) | ||||
|     } | ||||
|      | ||||
|     pub fn get_globals(&mut self) -> Result<Address, Error> { | ||||
|         let ptr = self.process.read_addr64(self.client_module.base + cs2dumper::offsets::client_dll::dwGlobalVars)?; | ||||
|         Ok(ptr) | ||||
|     } | ||||
|      | ||||
|     pub fn map_name(&mut self, global_vars: Address) -> Result<String, Error> { | ||||
|         let ptr = self.process.read_addr64(global_vars + 0x188)?; | ||||
|         Ok(self.process.read_char_string_n(ptr, 32)?) | ||||
|     } | ||||
|      | ||||
|     pub fn highest_entity_index(&mut self) -> Result<i32, Error> { | ||||
|         let game_entity_system = self.process.read_addr64(self.client_module.base + cs2dumper::offsets::client_dll::dwGameEntitySystem)?; | ||||
|         let highest_index = self.process.read(game_entity_system + cs2dumper::offsets::client_dll::dwGameEntitySystem_getHighestEntityIndex)?; | ||||
|         Ok(highest_index) | ||||
|     } | ||||
|      | ||||
|     pub fn network_is_ingame(&mut self) -> Result<bool, Error> { | ||||
|         let ptr = self.process.read_addr64(self.engine_module.base + cs2dumper::offsets::engine2_dll::dwNetworkGameClient)?; | ||||
|         let signonstate: i32 = self.process.read(ptr + cs2dumper::offsets::engine2_dll::dwNetworkGameClient_signOnState)?; | ||||
|         Ok(signonstate == 6) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum, Default)] | ||||
| pub enum Connector { | ||||
|     #[default] | ||||
|     Qemu, | ||||
|     Kvm, | ||||
|     Pcileech | ||||
| } | ||||
|  | ||||
| impl ToString for Connector { | ||||
|     fn to_string(&self) -> String { | ||||
|         match self { | ||||
|             Connector::Qemu => String::from("qemu"), | ||||
|             Connector::Kvm => String::from("kvm"), | ||||
|             Connector::Pcileech => String::from("pcileech"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										4170
									
								
								csflow/src/cs2dumper/client.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4170
									
								
								csflow/src/cs2dumper/client.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										244
									
								
								csflow/src/cs2dumper/engine2.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								csflow/src/cs2dumper/engine2.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | ||||
| /* | ||||
|  * Created using https://github.com/a2x/cs2-dumper | ||||
|  * Sat, 30 Dec 2023 03:17:25 +0000 | ||||
|  */ | ||||
|  | ||||
| #![allow(non_snake_case, non_upper_case_globals)] | ||||
|  | ||||
| pub mod CEmptyEntityInstance { | ||||
| } | ||||
|  | ||||
| pub mod CEntityComponent { | ||||
| } | ||||
|  | ||||
| pub mod CEntityComponentHelper { | ||||
|     pub const m_flags: usize = 0x8; // uint32_t | ||||
|     pub const m_pInfo: usize = 0x10; // EntComponentInfo_t* | ||||
|     pub const m_nPriority: usize = 0x18; // int32_t | ||||
|     pub const m_pNext: usize = 0x20; // CEntityComponentHelper* | ||||
| } | ||||
|  | ||||
| pub mod CEntityIOOutput { | ||||
|     pub const m_Value: usize = 0x18; // CVariantBase<CVariantDefaultAllocator> | ||||
| } | ||||
|  | ||||
| pub mod CEntityIdentity { | ||||
|     pub const m_nameStringableIndex: usize = 0x14; // int32_t | ||||
|     pub const m_name: usize = 0x18; // CUtlSymbolLarge | ||||
|     pub const m_designerName: usize = 0x20; // CUtlSymbolLarge | ||||
|     pub const m_flags: usize = 0x30; // uint32_t | ||||
|     pub const m_worldGroupId: usize = 0x38; // WorldGroupId_t | ||||
|     pub const m_fDataObjectTypes: usize = 0x3C; // uint32_t | ||||
|     pub const m_PathIndex: usize = 0x40; // ChangeAccessorFieldPathIndex_t | ||||
|     pub const m_pPrev: usize = 0x58; // CEntityIdentity* | ||||
|     pub const m_pNext: usize = 0x60; // CEntityIdentity* | ||||
|     pub const m_pPrevByClass: usize = 0x68; // CEntityIdentity* | ||||
|     pub const m_pNextByClass: usize = 0x70; // CEntityIdentity* | ||||
| } | ||||
|  | ||||
| pub mod CEntityInstance { | ||||
|     pub const m_iszPrivateVScripts: usize = 0x8; // CUtlSymbolLarge | ||||
|     pub const m_pEntity: usize = 0x10; // CEntityIdentity* | ||||
|     pub const m_CScriptComponent: usize = 0x28; // CScriptComponent* | ||||
| } | ||||
|  | ||||
| pub mod CNetworkVarChainer { | ||||
|     pub const m_PathIndex: usize = 0x20; // ChangeAccessorFieldPathIndex_t | ||||
| } | ||||
|  | ||||
| pub mod CScriptComponent { // CEntityComponent | ||||
|     pub const m_scriptClassName: usize = 0x30; // CUtlSymbolLarge | ||||
| } | ||||
|  | ||||
| pub mod CVariantDefaultAllocator { | ||||
| } | ||||
|  | ||||
| pub mod EngineLoopState_t { | ||||
|     pub const m_nPlatWindowWidth: usize = 0x18; // int32_t | ||||
|     pub const m_nPlatWindowHeight: usize = 0x1C; // int32_t | ||||
|     pub const m_nRenderWidth: usize = 0x20; // int32_t | ||||
|     pub const m_nRenderHeight: usize = 0x24; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EntComponentInfo_t { | ||||
|     pub const m_pName: usize = 0x0; // char* | ||||
|     pub const m_pCPPClassname: usize = 0x8; // char* | ||||
|     pub const m_pNetworkDataReferencedDescription: usize = 0x10; // char* | ||||
|     pub const m_pNetworkDataReferencedPtrPropDescription: usize = 0x18; // char* | ||||
|     pub const m_nRuntimeIndex: usize = 0x20; // int32_t | ||||
|     pub const m_nFlags: usize = 0x24; // uint32_t | ||||
|     pub const m_pBaseClassComponentHelper: usize = 0x60; // CEntityComponentHelper* | ||||
| } | ||||
|  | ||||
| pub mod EntInput_t { | ||||
| } | ||||
|  | ||||
| pub mod EntOutput_t { | ||||
| } | ||||
|  | ||||
| pub mod EventAdvanceTick_t { // EventSimulate_t | ||||
|     pub const m_nCurrentTick: usize = 0x30; // int32_t | ||||
|     pub const m_nCurrentTickThisFrame: usize = 0x34; // int32_t | ||||
|     pub const m_nTotalTicksThisFrame: usize = 0x38; // int32_t | ||||
|     pub const m_nTotalTicks: usize = 0x3C; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EventAppShutdown_t { | ||||
|     pub const m_nDummy0: usize = 0x0; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientAdvanceTick_t { // EventAdvanceTick_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientFrameSimulate_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRealTime: usize = 0x28; // float | ||||
|     pub const m_flFrameTime: usize = 0x2C; // float | ||||
| } | ||||
|  | ||||
| pub mod EventClientOutput_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRenderTime: usize = 0x28; // float | ||||
|     pub const m_flRealTime: usize = 0x2C; // float | ||||
|     pub const m_flRenderFrameTimeUnbounded: usize = 0x30; // float | ||||
|     pub const m_bRenderOnly: usize = 0x34; // bool | ||||
| } | ||||
|  | ||||
| pub mod EventClientPauseSimulate_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientPollInput_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRealTime: usize = 0x28; // float | ||||
| } | ||||
|  | ||||
| pub mod EventClientPollNetworking_t { | ||||
|     pub const m_nTickCount: usize = 0x0; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientPostAdvanceTick_t { // EventPostAdvanceTick_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientPostOutput_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRenderTime: usize = 0x28; // double | ||||
|     pub const m_flRenderFrameTime: usize = 0x30; // float | ||||
|     pub const m_flRenderFrameTimeUnbounded: usize = 0x34; // float | ||||
|     pub const m_bRenderOnly: usize = 0x38; // bool | ||||
| } | ||||
|  | ||||
| pub mod EventClientPostSimulate_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientPreOutput_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRenderTime: usize = 0x28; // double | ||||
|     pub const m_flRenderFrameTime: usize = 0x30; // double | ||||
|     pub const m_flRenderFrameTimeUnbounded: usize = 0x38; // double | ||||
|     pub const m_flRealTime: usize = 0x40; // float | ||||
|     pub const m_bRenderOnly: usize = 0x44; // bool | ||||
| } | ||||
|  | ||||
| pub mod EventClientPreSimulate_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientPredictionPostNetupdate_t { | ||||
| } | ||||
|  | ||||
| pub mod EventClientProcessGameInput_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRealTime: usize = 0x28; // float | ||||
|     pub const m_flFrameTime: usize = 0x2C; // float | ||||
| } | ||||
|  | ||||
| pub mod EventClientProcessInput_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRealTime: usize = 0x28; // float | ||||
|     pub const m_flTickInterval: usize = 0x2C; // float | ||||
|     pub const m_flTickStartTime: usize = 0x30; // double | ||||
| } | ||||
|  | ||||
| pub mod EventClientProcessNetworking_t { | ||||
| } | ||||
|  | ||||
| pub mod EventClientSceneSystemThreadStateChange_t { | ||||
|     pub const m_bThreadsActive: usize = 0x0; // bool | ||||
| } | ||||
|  | ||||
| pub mod EventClientSendInput_t { | ||||
|     pub const m_bFinalClientCommandTick: usize = 0x0; // bool | ||||
|     pub const m_nAdditionalClientCommandsToCreate: usize = 0x4; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EventClientSimulate_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventFrameBoundary_t { | ||||
|     pub const m_flFrameTime: usize = 0x0; // float | ||||
| } | ||||
|  | ||||
| pub mod EventModInitialized_t { | ||||
| } | ||||
|  | ||||
| pub mod EventPostAdvanceTick_t { // EventSimulate_t | ||||
|     pub const m_nCurrentTick: usize = 0x30; // int32_t | ||||
|     pub const m_nCurrentTickThisFrame: usize = 0x34; // int32_t | ||||
|     pub const m_nTotalTicksThisFrame: usize = 0x38; // int32_t | ||||
|     pub const m_nTotalTicks: usize = 0x3C; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EventPostDataUpdate_t { | ||||
|     pub const m_nCount: usize = 0x0; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EventPreDataUpdate_t { | ||||
|     pub const m_nCount: usize = 0x0; // int32_t | ||||
| } | ||||
|  | ||||
| pub mod EventProfileStorageAvailable_t { | ||||
|     pub const m_nSplitScreenSlot: usize = 0x0; // CSplitScreenSlot | ||||
| } | ||||
|  | ||||
| pub mod EventServerAdvanceTick_t { // EventAdvanceTick_t | ||||
| } | ||||
|  | ||||
| pub mod EventServerPollNetworking_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventServerPostAdvanceTick_t { // EventPostAdvanceTick_t | ||||
| } | ||||
|  | ||||
| pub mod EventServerPostSimulate_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventServerProcessNetworking_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventServerSimulate_t { // EventSimulate_t | ||||
| } | ||||
|  | ||||
| pub mod EventSetTime_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_nClientOutputFrames: usize = 0x28; // int32_t | ||||
|     pub const m_flRealTime: usize = 0x30; // double | ||||
|     pub const m_flRenderTime: usize = 0x38; // double | ||||
|     pub const m_flRenderFrameTime: usize = 0x40; // double | ||||
|     pub const m_flRenderFrameTimeUnbounded: usize = 0x48; // double | ||||
|     pub const m_flRenderFrameTimeUnscaled: usize = 0x50; // double | ||||
|     pub const m_flTickRemainder: usize = 0x58; // double | ||||
| } | ||||
|  | ||||
| pub mod EventSimpleLoopFrameUpdate_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_flRealTime: usize = 0x28; // float | ||||
|     pub const m_flFrameTime: usize = 0x2C; // float | ||||
| } | ||||
|  | ||||
| pub mod EventSimulate_t { | ||||
|     pub const m_LoopState: usize = 0x0; // EngineLoopState_t | ||||
|     pub const m_bFirstTick: usize = 0x28; // bool | ||||
|     pub const m_bLastTick: usize = 0x29; // bool | ||||
| } | ||||
|  | ||||
| pub mod EventSplitScreenStateChanged_t { | ||||
| } | ||||
							
								
								
									
										4
									
								
								csflow/src/cs2dumper/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								csflow/src/cs2dumper/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| #![allow(dead_code)] | ||||
| pub mod client; | ||||
| pub mod engine2; | ||||
| pub mod offsets; | ||||
							
								
								
									
										51
									
								
								csflow/src/cs2dumper/offsets.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								csflow/src/cs2dumper/offsets.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| /* | ||||
|  * Created using https://github.com/a2x/cs2-dumper | ||||
|  * Sat, 30 Dec 2023 03:17:26 +0000 | ||||
|  */ | ||||
|  | ||||
| #![allow(non_snake_case, non_upper_case_globals)] | ||||
|  | ||||
| pub mod client_dll { // client.dll | ||||
|     pub const dwEntityList: usize = 0x17C1950; | ||||
|     pub const dwForceAttack: usize = 0x16C1E70; | ||||
|     pub const dwForceAttack2: usize = 0x16C1F00; | ||||
|     pub const dwForceBackward: usize = 0x16C2140; | ||||
|     pub const dwForceCrouch: usize = 0x16C2410; | ||||
|     pub const dwForceForward: usize = 0x16C20B0; | ||||
|     pub const dwForceJump: usize = 0x16C2380; | ||||
|     pub const dwForceLeft: usize = 0x16C21D0; | ||||
|     pub const dwForceRight: usize = 0x16C2260; | ||||
|     pub const dwGameEntitySystem: usize = 0x18ED250; | ||||
|     pub const dwGameEntitySystem_getHighestEntityIndex: usize = 0x1510; | ||||
|     pub const dwGameRules: usize = 0x181E048; | ||||
|     pub const dwGlobalVars: usize = 0x16BDC98; | ||||
|     pub const dwGlowManager: usize = 0x181D7B0; | ||||
|     pub const dwInterfaceLinkList: usize = 0x191AEE8; | ||||
|     pub const dwLocalPlayerController: usize = 0x1810F48; | ||||
|     pub const dwLocalPlayerPawn: usize = 0x16C8F38; | ||||
|     pub const dwPlantedC4: usize = 0x1824A88; | ||||
|     pub const dwPrediction: usize = 0x16C8E00; | ||||
|     pub const dwSensitivity: usize = 0x181ED48; | ||||
|     pub const dwSensitivity_sensitivity: usize = 0x40; | ||||
|     pub const dwViewAngles: usize = 0x1880DC0; | ||||
|     pub const dwViewMatrix: usize = 0x1820150; | ||||
|     pub const dwViewRender: usize = 0x1820998; | ||||
| } | ||||
|  | ||||
| pub mod engine2_dll { // engine2.dll | ||||
|     pub const dwBuildNumber: usize = 0x4E03D4; | ||||
|     pub const dwNetworkGameClient: usize = 0x4DF988; | ||||
|     pub const dwNetworkGameClient_getLocalPlayer: usize = 0xF0; | ||||
|     pub const dwNetworkGameClient_maxClients: usize = 0x250; | ||||
|     pub const dwNetworkGameClient_signOnState: usize = 0x240; | ||||
|     pub const dwWindowHeight: usize = 0x596E1C; | ||||
|     pub const dwWindowWidth: usize = 0x596E18; | ||||
| } | ||||
|  | ||||
| pub mod game_info { // Some additional information about the game at dump time | ||||
|     pub const buildNumber: usize = 0x369F; // Game build number | ||||
| } | ||||
|  | ||||
| pub mod inputsystem_dll { // inputsystem.dll | ||||
|     pub const dwInputSystem: usize = 0x35760; | ||||
| } | ||||
							
								
								
									
										5
									
								
								csflow/src/enums/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								csflow/src/enums/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| mod player_type; | ||||
| mod teamid; | ||||
|  | ||||
| pub use player_type::PlayerType; | ||||
| pub use teamid::TeamID; | ||||
							
								
								
									
										9
									
								
								csflow/src/enums/player_type.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								csflow/src/enums/player_type.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Default, PartialEq)] | ||||
| pub enum PlayerType { | ||||
|     #[default] | ||||
|     Unknown, | ||||
|     Spectator, | ||||
|     Local, | ||||
|     Enemy, | ||||
|     Team | ||||
| } | ||||
							
								
								
									
										7
									
								
								csflow/src/enums/teamid.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								csflow/src/enums/teamid.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #[repr(i32)] | ||||
| #[derive(Debug, Eq, PartialEq, enum_primitive_derive::Primitive)] | ||||
| pub enum TeamID { | ||||
|     Spectator = 1, | ||||
|     T = 2, | ||||
|     CT = 3 | ||||
| } | ||||
							
								
								
									
										33
									
								
								csflow/src/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								csflow/src/error.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| use memflow::types::Address; | ||||
| use thiserror::Error; | ||||
|  | ||||
| use crate::structs::Vec3; | ||||
|  | ||||
| #[derive(Error, Debug)] | ||||
| pub enum Error { | ||||
|     /// Game version mismatch. | ||||
|     /// First arg is the game version, second is the offset version. | ||||
|     #[error("version mismatch, game has version {0}, but offsets have version {1}")] | ||||
|     GameVersionMismatch(usize, usize), | ||||
|  | ||||
|     #[error("memflow error: {0}")] | ||||
|     Memflow(#[from] memflow::error::Error), | ||||
|  | ||||
|     #[error("memflow partial error when reading address: {0}")] | ||||
|     MemflowPartialAddress(#[from] memflow::error::PartialError<Address>), | ||||
|  | ||||
|     #[error("memflow partial error when reading Vec3: {0}")] | ||||
|     MemflowPartialVec3(#[from] memflow::error::PartialError<Vec3>), | ||||
|  | ||||
|     #[error("memflow partial error when reading String: {0}")] | ||||
|     MemflowPartialString(#[from] memflow::error::PartialError<String>), | ||||
|  | ||||
|     #[error("memflow partial error when reading i32: {0}")] | ||||
|     MemflowPartiali32(#[from] memflow::error::PartialError<i32>), | ||||
|  | ||||
|     #[error("memflow partial error when reading u32: {0}")] | ||||
|     MemflowPartialu32(#[from] memflow::error::PartialError<u32>), | ||||
|  | ||||
|     #[error("memflow partial error when reading u8: {0}")] | ||||
|     MemflowPartialu8(#[from] memflow::error::PartialError<u8>) | ||||
| } | ||||
							
								
								
									
										14
									
								
								csflow/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								csflow/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #![allow(dead_code)] | ||||
|  | ||||
| mod cs2dumper; | ||||
| mod context; | ||||
| mod error; | ||||
|  | ||||
| pub mod structs; | ||||
| pub mod traits; | ||||
| pub mod enums; | ||||
|  | ||||
| pub use context::*; | ||||
| pub use error::Error; | ||||
|  | ||||
| pub use memflow::prelude as memflow; | ||||
							
								
								
									
										47
									
								
								csflow/src/structs/entity/base_entity.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								csflow/src/structs/entity/base_entity.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| use memflow::{types::Address, mem::MemoryView}; | ||||
| use crate::{CheatCtx, Error, cs2dumper, traits::{BaseEntity, MemoryClass}, structs::Vec3}; | ||||
|  | ||||
| pub struct CBaseEntity(Address); | ||||
|  | ||||
| impl MemoryClass for CBaseEntity { | ||||
|     fn ptr(&self) -> Address { | ||||
|         self.0 | ||||
|     } | ||||
|  | ||||
|     fn new(ptr: Address) -> Self { | ||||
|         Self(ptr) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl BaseEntity for CBaseEntity { | ||||
|     fn from_index(ctx: &mut CheatCtx, entity_list: Address, index: i32) -> Result<Option<CBaseEntity>, Error> { | ||||
|         let list_entry = ctx.process.read_addr64(entity_list + 8 * (index >> 9) + 16)?; | ||||
|         if list_entry.is_null() && !list_entry.is_valid() { | ||||
|             return Ok(None); | ||||
|         } | ||||
|  | ||||
|         let player_ptr = ctx.process.read_addr64(list_entry + 120 * (index & 0x1FF))?; | ||||
|         if player_ptr.is_null() && !player_ptr.is_valid() { | ||||
|             return Ok(None); | ||||
|         } | ||||
|  | ||||
|         Ok(Some(Self::new(player_ptr))) | ||||
|     } | ||||
|  | ||||
|     fn pos(&self, ctx: &mut CheatCtx) -> Result<Vec3, Error> { | ||||
|         let node = ctx.process.read_addr64(self.0 + cs2dumper::client::C_BaseEntity::m_pGameSceneNode)?; | ||||
|         Ok(ctx.process.read(node + cs2dumper::client::CGameSceneNode::m_vecAbsOrigin)?) | ||||
|     } | ||||
|  | ||||
|     fn class_name(&self, ctx: &mut CheatCtx) -> Result<String, Error> { | ||||
|         let entity_identity_ptr = ctx.process.read_addr64(self.0 + cs2dumper::client::CEntityInstance::m_pEntity)?; | ||||
|         let class_name_ptr = ctx.process.read_addr64(entity_identity_ptr + cs2dumper::client::CEntityIdentity::m_designerName)?; | ||||
|         Ok(ctx.process.read_char_string_n(class_name_ptr, 32)?) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl CBaseEntity { | ||||
|     pub fn to_player_controller(&self) -> super::CPlayerController { | ||||
|         super::CPlayerController::new(self.0) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								csflow/src/structs/entity/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								csflow/src/structs/entity/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| mod base_entity; | ||||
| mod player_controller; | ||||
| mod player_pawn; | ||||
|  | ||||
| pub use base_entity::CBaseEntity; | ||||
| pub use player_controller::CPlayerController; | ||||
| pub use player_pawn::CPlayerPawn; | ||||
							
								
								
									
										88
									
								
								csflow/src/structs/entity/player_controller.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								csflow/src/structs/entity/player_controller.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| use memflow::{types::Address, mem::MemoryView}; | ||||
| use num_traits::FromPrimitive; | ||||
|  | ||||
| use crate::{CheatCtx, Error, cs2dumper, structs::Vec3, traits::{MemoryClass, BaseEntity}, enums::{TeamID, PlayerType}}; | ||||
|  | ||||
| pub struct CPlayerController(Address); | ||||
|  | ||||
| impl MemoryClass for CPlayerController { | ||||
|     fn ptr(&self) -> Address { | ||||
|         self.0 | ||||
|     } | ||||
|  | ||||
|     fn new(ptr: Address) -> Self { | ||||
|         Self(ptr) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl BaseEntity for CPlayerController { | ||||
|     fn from_index(ctx: &mut CheatCtx, entity_list: Address, index: i32) -> Result<Option<CPlayerController>, Error> { | ||||
|         let list_entry = ctx.process.read_addr64(entity_list + 8 * (index >> 9) + 16)?; | ||||
|         if list_entry.is_null() && !list_entry.is_valid() { | ||||
|             return Ok(None); | ||||
|         } | ||||
|  | ||||
|         let player_ptr = ctx.process.read_addr64(list_entry + 120 * (index & 0x1FF))?; | ||||
|         if player_ptr.is_null() && !player_ptr.is_valid() { | ||||
|             return Ok(None); | ||||
|         } | ||||
|  | ||||
|         Ok(Some(Self::new(player_ptr))) | ||||
|     } | ||||
|  | ||||
|     fn pos(&self, ctx: &mut CheatCtx) -> Result<Vec3, Error> { | ||||
|         let node = ctx.process.read_addr64(self.0 + cs2dumper::client::C_BaseEntity::m_pGameSceneNode)?; | ||||
|         Ok(ctx.process.read(node + cs2dumper::client::CGameSceneNode::m_vecAbsOrigin)?) | ||||
|     } | ||||
|  | ||||
|     fn class_name(&self, ctx: &mut CheatCtx) -> Result<String, Error> { | ||||
|         let entity_identity_ptr = ctx.process.read_addr64(self.0 + cs2dumper::client::CEntityInstance::m_pEntity)?; | ||||
|         let class_name_ptr = ctx.process.read_addr64(entity_identity_ptr + cs2dumper::client::CEntityIdentity::m_designerName)?; | ||||
|         Ok(ctx.process.read_char_string_n(class_name_ptr, 32)?) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl CPlayerController { | ||||
|     pub fn get_pawn(&self, ctx: &mut CheatCtx, entity_list: Address) -> Result<Option<super::CPlayerPawn>, Error> { | ||||
|         let uhandle = ctx.process.read(self.0 + cs2dumper::client::CCSPlayerController::m_hPlayerPawn)?; | ||||
|         super::CPlayerPawn::from_uhandle(ctx, entity_list, uhandle) | ||||
|     } | ||||
|  | ||||
|     // Technically something that should be in the BaseEntity trait, but we are only gonna use it on CPlayerController | ||||
|     pub fn get_team(&self, ctx: &mut CheatCtx) -> Result<Option<TeamID>, Error> { | ||||
|         let team_num: i32 = ctx.process.read(self.0 + cs2dumper::client::C_BaseEntity::m_iTeamNum)?; | ||||
|         Ok(TeamID::from_i32(team_num)) | ||||
|     } | ||||
|  | ||||
|     pub fn get_player_type(&self, ctx: &mut CheatCtx, local: &CPlayerController) -> Result<Option<PlayerType>, Error> { | ||||
|         if self.0 == local.0 { | ||||
|             return Ok(Some(PlayerType::Local)) | ||||
|         } | ||||
|  | ||||
|         let team = { | ||||
|             match self.get_team(ctx)? { | ||||
|                 Some(t) => t, | ||||
|                 None => { return Ok(None) }, | ||||
|             } | ||||
|         }; | ||||
|          | ||||
|         let local_team = { | ||||
|             match local.get_team(ctx)? { | ||||
|                 Some(t) => t, | ||||
|                 None => { return Ok(None) }, | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let player_type = { | ||||
|             if team == TeamID::Spectator {  | ||||
|                 PlayerType::Spectator  | ||||
|             } else if team != local_team { | ||||
|                 PlayerType::Enemy | ||||
|             } else { | ||||
|                 PlayerType::Team | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         Ok(Some(player_type)) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										80
									
								
								csflow/src/structs/entity/player_pawn.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								csflow/src/structs/entity/player_pawn.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| use memflow::{types::Address, mem::MemoryView}; | ||||
|  | ||||
| use crate::{Error, CheatCtx, cs2dumper, structs::Vec3, traits::MemoryClass}; | ||||
|  | ||||
| pub struct CPlayerPawn(Address); | ||||
|  | ||||
| impl MemoryClass for CPlayerPawn { | ||||
|     fn ptr(&self) -> Address { | ||||
|         self.0 | ||||
|     } | ||||
|  | ||||
|     fn new(ptr: Address) -> Self { | ||||
|         Self(ptr) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl CPlayerPawn { | ||||
|     pub fn from_uhandle(ctx: &mut CheatCtx, entity_list: Address, uhandle: u32) -> Result<Option<Self>, Error> { | ||||
|         let list_entry = ctx.process.read_addr64(entity_list + 0x8 * ((uhandle & 0x7FFF) >> 9) + 16)?; | ||||
|          | ||||
|         if list_entry.is_null() || !list_entry.is_valid() { | ||||
|             Ok(None) | ||||
|         } else { | ||||
|             let ptr = ctx.process.read_addr64(list_entry + 120 * (uhandle & 0x1FF))?; | ||||
|             Ok(Some(Self(ptr))) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Todo: Optimize this function: find another way to do this | ||||
|     pub fn has_c4(&self, ctx: &mut CheatCtx, entity_list: Address) -> Result<bool, Error> { | ||||
|         let mut has_c4 = false; | ||||
|         let wep_services = ctx.process.read_addr64(self.0 + cs2dumper::client::C_BasePlayerPawn::m_pWeaponServices)?; | ||||
|         let wep_count: i32  = ctx.process.read(wep_services + cs2dumper::client::CPlayer_WeaponServices::m_hMyWeapons)?; | ||||
|         let wep_base = ctx.process.read_addr64(wep_services + cs2dumper::client::CPlayer_WeaponServices::m_hMyWeapons + 0x8)?; | ||||
|  | ||||
|         for wep_idx in 0..wep_count { | ||||
|             let handle: i32 = ctx.process.read(wep_base + wep_idx * 0x4)?; | ||||
|             if handle == -1 { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             let list_entry = ctx.process.read_addr64(entity_list + 0x8 * ((handle & 0x7FFF) >> 9) + 16)?; | ||||
|             if let Some(wep_ptr) = { | ||||
|                 if list_entry.is_null() || !list_entry.is_valid() { | ||||
|                     None | ||||
|                 } else { | ||||
|                     let ptr = ctx.process.read_addr64(list_entry + 120 * (handle & 0x1FF))?; | ||||
|                     Some(ptr) | ||||
|                 } | ||||
|             } { | ||||
|                 let wep_data = ctx.process.read_addr64(wep_ptr + cs2dumper::client::C_BaseEntity::m_nSubclassID + 0x8)?; | ||||
|                 let id: i32 = ctx.process.read(wep_data + cs2dumper::client::CCSWeaponBaseVData::m_WeaponType)?; | ||||
|  | ||||
|                 if id == 7 { | ||||
|                     has_c4 = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok(has_c4) | ||||
|     } | ||||
|  | ||||
|     pub fn pos(&self, ctx: &mut CheatCtx) -> Result<Vec3, Error> { | ||||
|         Ok(ctx.process.read(self.0 + cs2dumper::client::C_BasePlayerPawn::m_vOldOrigin)?) | ||||
|     } | ||||
|  | ||||
|     pub fn angles(&self, ctx: &mut CheatCtx) -> Result<Vec3, Error> { | ||||
|         Ok(ctx.process.read(self.0 + cs2dumper::client::C_CSPlayerPawnBase::m_angEyeAngles)?) | ||||
|     } | ||||
|  | ||||
|     pub fn health(&self, ctx: &mut CheatCtx) -> Result<u32, Error> { | ||||
|         Ok(ctx.process.read(self.0 + cs2dumper::client::C_BaseEntity::m_iHealth)?) | ||||
|     } | ||||
|  | ||||
|     /// Same as ::get_health > 0 | ||||
|     pub fn is_alive(&self, ctx: &mut CheatCtx) -> Result<bool, Error> { | ||||
|         Ok(self.health(ctx)? > 0) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										5
									
								
								csflow/src/structs/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								csflow/src/structs/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| mod vec3; | ||||
| mod entity; | ||||
|  | ||||
| pub use vec3::Vec3; | ||||
| pub use entity::{CBaseEntity, CPlayerController, CPlayerPawn}; | ||||
							
								
								
									
										11
									
								
								csflow/src/structs/vec3.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								csflow/src/structs/vec3.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| use serde::Serialize; | ||||
|  | ||||
| #[derive(Debug, Clone, Copy, Serialize, serde::Deserialize)] | ||||
| #[repr(C)] | ||||
| pub struct Vec3 { | ||||
|     pub x: f32,  | ||||
|     pub y: f32, | ||||
|     pub z: f32 | ||||
| } | ||||
|  | ||||
| unsafe impl dataview::Pod for Vec3 {} | ||||
							
								
								
									
										11
									
								
								csflow/src/traits/base_entity.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								csflow/src/traits/base_entity.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| use memflow::types::Address; | ||||
|  | ||||
| use crate::{CheatCtx, structs::Vec3, Error}; | ||||
|  | ||||
| /// A trait for basic functions from C_BaseEntity | ||||
| /// CCSPlayerController inherits C_BaseEntity, which is why this trait exists. | ||||
| pub trait BaseEntity { | ||||
|     fn from_index(ctx: &mut CheatCtx, entity_list: Address, index: i32) -> Result<Option<Self>, Error> where Self: std::marker::Sized; | ||||
|     fn pos(&self, ctx: &mut CheatCtx) -> Result<Vec3, Error>; | ||||
|     fn class_name(&self, ctx: &mut CheatCtx) -> Result<String, Error>; | ||||
| } | ||||
							
								
								
									
										7
									
								
								csflow/src/traits/memory_class.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								csflow/src/traits/memory_class.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| use memflow::types::Address; | ||||
|  | ||||
| /// A trait that implements basic functions for a class represented by a single pointer | ||||
| pub trait MemoryClass { | ||||
|     fn ptr(&self) -> Address; | ||||
|     fn new(ptr: Address) -> Self; | ||||
| } | ||||
							
								
								
									
										5
									
								
								csflow/src/traits/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								csflow/src/traits/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| mod base_entity; | ||||
| mod memory_class; | ||||
|  | ||||
| pub use base_entity::BaseEntity; | ||||
| pub use memory_class::MemoryClass; | ||||
		Reference in New Issue
	
	Block a user