    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    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)
        }
    }