This commit is contained in:
Oscar
2025-07-29 20:23:06 +03:00
parent 860be9ac4c
commit 5717c7999c
253 changed files with 873847 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
#pragma once
// @source: master/game/shared/cstrike15/gametypes.h
#pragma region valve_gametypes
enum EGameType : int
{
GAMETYPE_UNKNOWN = -1,
GAMETYPE_CLASSIC,
GAMETYPE_GUNGAME,
GAMETYPE_TRAINING,
GAMETYPE_CUSTOM,
GAMETYPE_COOPERATIVE,
GAMETYPE_SKIRMISH,
GAMETYPE_FREEFORALL
};
enum EGameMode : int
{
GAMEMODE_UNKNOWN = -1,
// GAMETYPE_CLASSIC
GAMEMODE_CLASSIC_CASUAL = 0,
GAMEMODE_CLASSIC_COMPETITIVE,
GAMEMODE_CLASSIC_SCRIM_COMPETITIVE2V2,
GAMEMODE_CLASSIC_SCRIM_COMPETITIVE5V5,
// GAMETYPE_GUNGAME
GAMEMODE_GUNGAME_PROGRESSIVE = 0,
GAMEMODE_GUNGAME_BOMB,
GAMEMODE_GUNGAME_DEATHMATCH,
// GAMETYPE_TRAINING
GAMEMODE_TRAINING_DEFAULT = 0,
// GAMETYPE_CUSTOM
GAMEMODE_CUSTOM_DEFAULT = 0,
// GAMETYPE_COOPERATIVE
GAMEMODE_COOPERATIVE_DEFAULT = 0,
GAMEMODE_COOPERATIVE_MISSION,
// GAMETYPE_SKIRMISH
GAMEMODE_SKIRMISH_DEFAULT = 0,
// GAMETYPE_FREEFORALL
GAMEMODE_FREEFORALL_SURVIVAL = 0
};
#pragma endregion
enum ELifeState : int
{
LIFE_ALIVE = 0,
LIFE_DYING,
LIFE_DEAD,
LIFE_RESPAWNABLE,
LIFE_DISCARDBODY
};
enum EFlags : int
{
FL_ONGROUND = (1 << 0), // entity is at rest / on the ground
FL_DUCKING = (1 << 1), // player is fully crouched/uncrouched
FL_ANIMDUCKING = (1 << 2), // player is in the process of crouching or uncrouching but could be in transition
FL_WATERJUMP = (1 << 3), // player is jumping out of water
FL_ONTRAIN = (1 << 4), // player is controlling a train, so movement commands should be ignored on client during prediction
FL_INRAIN = (1 << 5), // entity is standing in rain
FL_FROZEN = (1 << 6), // player is frozen for 3rd-person camera
FL_ATCONTROLS = (1 << 7), // player can't move, but keeps key inputs for controlling another entity
FL_CLIENT = (1 << 8), // entity is a client (player)
FL_FAKECLIENT = (1 << 9), // entity is a fake client, simulated server side; don't send network messages to them
FL_INWATER = (1 << 10), // entity is in water
FL_FLY = (1 << 11),
FL_SWIM = (1 << 12),
FL_CONVEYOR = (1 << 13),
FL_NPC = (1 << 14),
FL_GODMODE = (1 << 15),
FL_NOTARGET = (1 << 16),
FL_AIMTARGET = (1 << 17),
FL_PARTIALGROUND = (1 << 18), // entity is standing on a place where not all corners are valid
FL_STATICPROP = (1 << 19), // entity is a static property
FL_GRAPHED = (1 << 20),
FL_GRENADE = (1 << 21),
FL_STEPMOVEMENT = (1 << 22),
FL_DONTTOUCH = (1 << 23),
FL_BASEVELOCITY = (1 << 24), // entity have applied base velocity this frame
FL_WORLDBRUSH = (1 << 25), // entity is not moveable/removeable brush (part of the world, but represented as an entity for transparency or something)
FL_OBJECT = (1 << 26),
FL_KILLME = (1 << 27), // entity is marked for death and will be freed by the game
FL_ONFIRE = (1 << 28),
FL_DISSOLVING = (1 << 29),
FL_TRANSRAGDOLL = (1 << 30), // entity is turning into client-side ragdoll
FL_UNBLOCKABLE_BY_PLAYER = (1 << 31)
};
enum EEFlags : int
{
EFL_KILLME = (1 << 0),
EFL_DORMANT = (1 << 1),
EFL_NOCLIP_ACTIVE = (1 << 2),
EFL_SETTING_UP_BONES = (1 << 3),
EFL_KEEP_ON_RECREATE_ENTITIES = (1 << 4),
EFL_DIRTY_SHADOWUPDATE = (1 << 5),
EFL_NOTIFY = (1 << 6),
EFL_FORCE_CHECK_TRANSMIT = (1 << 7),
EFL_BOT_FROZEN = (1 << 8),
EFL_SERVER_ONLY = (1 << 9),
EFL_NO_AUTO_EDICT_ATTACH = (1 << 10),
EFL_DIRTY_ABSTRANSFORM = (1 << 11),
EFL_DIRTY_ABSVELOCITY = (1 << 12),
EFL_DIRTY_ABSANGVELOCITY = (1 << 13),
EFL_DIRTY_SURROUNDING_COLLISION_BOUNDS = (1 << 14),
EFL_DIRTY_SPATIAL_PARTITION = (1 << 15),
EFL_HAS_PLAYER_CHILD = (1 << 16),
EFL_IN_SKYBOX = (1 << 17),
EFL_USE_PARTITION_WHEN_NOT_SOLID = (1 << 18),
EFL_TOUCHING_FLUID = (1 << 19),
EFL_IS_BEING_LIFTED_BY_BARNACLE = (1 << 20),
EFL_NO_ROTORWASH_PUSH = (1 << 21),
EFL_NO_THINK_FUNCTION = (1 << 22),
EFL_NO_GAME_PHYSICS_SIMULATION = (1 << 23),
EFL_CHECK_UNTOUCH = (1 << 24),
EFL_DONTBLOCKLOS = (1 << 25),
EFL_DONTWALKON = (1 << 26),
EFL_NO_DISSOLVE = (1 << 27),
EFL_NO_MEGAPHYSCANNON_RAGDOLL = (1 << 28),
EFL_NO_WATER_VELOCITY_CHANGE = (1 << 29),
EFL_NO_PHYSCANNON_INTERACTION = (1 << 30),
EFL_NO_DAMAGE_FORCES = (1 << 31)
};
enum EMoveType : std::uint8_t
{
MOVETYPE_NONE = 0,
MOVETYPE_OBSOLETE,
MOVETYPE_WALK,
MOVETYPE_FLY,
MOVETYPE_FLYGRAVITY,
MOVETYPE_VPHYSICS,
MOVETYPE_PUSH,
MOVETYPE_NOCLIP,
MOVETYPE_OBSERVER,
MOVETYPE_LADDER,
MOVETYPE_CUSTOM,
MOVETYPE_LAST,
MOVETYPE_INVALID,
MOVETYPE_MAX_BITS = 5
};
// identifies how submerged in water a player is
enum : int
{
WL_NOTINWATER = 0,
WL_FEET,
WL_WAIST,
WL_EYES
};
enum ETeamID : int
{
TEAM_UNK,
TEAM_SPECTATOR,
TEAM_TT,
TEAM_CT
};
using ItemDefinitionIndex_t = std::uint16_t;
enum EItemDefinitionIndexes : ItemDefinitionIndex_t
{
WEAPON_NONE,
WEAPON_DESERT_EAGLE,
WEAPON_DUAL_BERETTAS,
WEAPON_FIVE_SEVEN,
WEAPON_GLOCK_18,
WEAPON_AK_47 = 7,
WEAPON_AUG,
WEAPON_AWP,
WEAPON_FAMAS,
WEAPON_G3SG1,
WEAPON_GALIL_AR = 13,
WEAPON_M249,
WEAPON_M4A4 = 16,
WEAPON_MAC_10,
WEAPON_P90 = 19,
WEAPON_REPULSOR_DEVICE,
WEAPON_MP5_SD = 23,
WEAPON_UMP_45,
WEAPON_XM1014,
WEAPON_PP_BIZON,
WEAPON_MAG_7,
WEAPON_NEGEV,
WEAPON_SAWED_OFF,
WEAPON_TEC_9,
WEAPON_ZEUS_X27,
WEAPON_P2000,
WEAPON_MP7,
WEAPON_MP9,
WEAPON_NOVA,
WEAPON_P250,
WEAPON_RIOT_SHIELD,
WEAPON_SCAR_20,
WEAPON_SG_553,
WEAPON_SSG_08,
WEAPON_KNIFE0,
WEAPON_KNIFE1,
WEAPON_FLASHBANG,
WEAPON_HIGH_EXPLOSIVE_GRENADE,
WEAPON_SMOKE_GRENADE,
WEAPON_MOLOTOV,
WEAPON_DECOY_GRENADE,
WEAPON_INCENDIARY_GRENADE,
WEAPON_C4_EXPLOSIVE,
WEAPON_KEVLAR_VEST,
WEAPON_KEVLAR_and_HELMET,
WEAPON_HEAVY_ASSAULT_SUIT,
WEAPON_NO_LOCALIZED_NAME0 = 54,
WEAPON_DEFUSE_KIT,
WEAPON_RESCUE_KIT,
WEAPON_MEDI_SHOT,
WEAPON_MUSIC_KIT,
WEAPON_KNIFE2,
WEAPON_M4A1_S,
WEAPON_USP_S,
WEAPON_TRADE_UP_CONTRACT,
WEAPON_CZ75_AUTO,
WEAPON_R8_REVOLVER,
WEAPON_TACTICAL_AWARENESS_GRENADE = 68,
WEAPON_BARE_HANDS,
WEAPON_BREACH_CHARGE,
WEAPON_TABLET = 72,
WEAPON_KNIFE3 = 74,
WEAPON_AXE,
WEAPON_HAMMER,
WEAPON_WRENCH = 78,
WEAPON_SPECTRAL_SHIV = 80,
WEAPON_FIRE_BOMB,
WEAPON_DIVERSION_DEVICE,
WEAPON_FRAG_GRENADE,
WEAPON_SNOWBALL,
WEAPON_BUMP_MINE,
WEAPON_BAYONET = 500,
WEAPON_CLASSIC_KNIFE = 503,
WEAPON_FLIP_KNIFE = 505,
WEAPON_GUT_KNIFE,
WEAPON_KARAMBIT,
WEAPON_M9_BAYONET,
WEAPON_HUNTSMAN_KNIFE,
WEAPON_FALCHION_KNIFE = 512,
WEAPON_BOWIE_KNIFE = 514,
WEAPON_BUTTERFLY_KNIFE,
WEAPON_SHADOW_DAGGERS,
WEAPON_PARACORD_KNIFE,
WEAPON_SURVIVAL_KNIFE,
WEAPON_URSUS_KNIFE,
WEAPON_NAVAJA_KNIFE,
WEAPON_NOMAD_KNIFE,
WEAPON_STILETTO_KNIFE,
WEAPON_TALON_KNIFE,
WEAPON_SKELETON_KNIFE = 525,
};
enum EWeaponType : std::uint32_t
{
WEAPONTYPE_KNIFE = 0,
WEAPONTYPE_PISTOL = 1,
WEAPONTYPE_SUBMACHINEGUN = 2,
WEAPONTYPE_RIFLE = 3,
WEAPONTYPE_SHOTGUN = 4,
WEAPONTYPE_SNIPER_RIFLE = 5,
WEAPONTYPE_MACHINEGUN = 6,
WEAPONTYPE_C4 = 7,
WEAPONTYPE_TASER = 8,
WEAPONTYPE_GRENADE = 9,
WEAPONTYPE_EQUIPMENT = 10,
WEAPONTYPE_STACKABLEITEM = 11,
WEAPONTYPE_FISTS = 12,
WEAPONTYPE_BREACHCHARGE = 13,
WEAPONTYPE_BUMPMINE = 14,
WEAPONTYPE_TABLET = 15,
WEAPONTYPE_MELEE = 16,
WEAPONTYPE_SHIELD = 17,
WEAPONTYPE_ZONE_REPULSOR = 18,
WEAPONTYPE_UNKNOWN = 19
};

View File

@@ -0,0 +1,232 @@
#pragma once
// used: [crt] fmodf
#include <cmath>
// used: bit_cast
#include <bit>
#include "../../common.h"
// used: swap
#include "../../utilities/crt.h"
// used: [ext] imu32
#include "../../../dependencies/imgui/imgui.h"
enum
{
COLOR_R = 0,
COLOR_G = 1,
COLOR_B = 2,
COLOR_A = 3
};
struct ColorRGBExp32
{
std::uint8_t r, g, b;
std::int8_t iExponent;
};
static_assert(sizeof(ColorRGBExp32) == 0x4);
struct Color_t
{
Color_t() = default;
// 8-bit color constructor (in: [0 .. 255])
constexpr Color_t(const std::uint8_t r, const std::uint8_t g, const std::uint8_t b, const std::uint8_t a = 255) :
r(r), g(g), b(b), a(a) { }
// 8-bit color constructor (in: [0 .. 255])
constexpr Color_t(const int r, const int g, const int b, const int a = 255) :
r(static_cast<std::uint8_t>(r)), g(static_cast<std::uint8_t>(g)), b(static_cast<std::uint8_t>(b)), a(static_cast<std::uint8_t>(a)) { }
// 8-bit array color constructor (in: [0.0 .. 1.0])
explicit constexpr Color_t(const std::uint8_t arrColor[4]) :
r(arrColor[COLOR_R]), g(arrColor[COLOR_G]), b(arrColor[COLOR_B]), a(arrColor[COLOR_A]) { }
// 32-bit packed color constructor (in: 0x00000000 - 0xFFFFFFFF)
explicit constexpr Color_t(const ImU32 uPackedColor) :
r(static_cast<std::uint8_t>((uPackedColor >> IM_COL32_R_SHIFT) & 0xFF)), g(static_cast<std::uint8_t>((uPackedColor >> IM_COL32_G_SHIFT) & 0xFF)), b(static_cast<std::uint8_t>((uPackedColor >> IM_COL32_B_SHIFT) & 0xFF)), a(static_cast<std::uint8_t>((uPackedColor >> IM_COL32_A_SHIFT) & 0xFF)) { }
// 32-bit color constructor (in: [0.0 .. 1.0])
constexpr Color_t(const float r, const float g, const float b, const float a = 1.0f) :
r(static_cast<std::uint8_t>(r * 255.f)), g(static_cast<std::uint8_t>(g * 255.f)), b(static_cast<std::uint8_t>(b * 255.f)), a(static_cast<std::uint8_t>(a * 255.f)) { }
/// @returns: 32-bit packed integer representation of color
[[nodiscard]] constexpr ImU32 GetU32(const float flAlphaMultiplier = 1.0f) const
{
return IM_COL32(r, g, b, a * flAlphaMultiplier);
}
/// @return: converted color to imgui vector
[[nodiscard]] ImVec4 GetVec4(const float flAlphaMultiplier = 1.0f) const
{
return ImVec4(this->Base<COLOR_R>(), this->Base<COLOR_G>(), this->Base<COLOR_B>(), this->Base<COLOR_A>() * flAlphaMultiplier);
}
std::uint8_t& operator[](const std::uint8_t nIndex)
{
CS_ASSERT(nIndex <= COLOR_A); // given index is out of range
return reinterpret_cast<std::uint8_t*>(this)[nIndex];
}
const std::uint8_t& operator[](const std::uint8_t nIndex) const
{
CS_ASSERT(nIndex <= COLOR_A); // given index is out of range
return reinterpret_cast<const std::uint8_t*>(this)[nIndex];
}
bool operator==(const Color_t& colSecond) const
{
return (std::bit_cast<std::uint32_t>(*this) == std::bit_cast<std::uint32_t>(colSecond));
}
bool operator!=(const Color_t& colSecond) const
{
return (std::bit_cast<std::uint32_t>(*this) != std::bit_cast<std::uint32_t>(colSecond));
}
/// @returns: copy of color with certain R/G/B/A component changed to given value
template <std::size_t N>
[[nodiscard]] Color_t Set(const std::uint8_t nValue) const
{
static_assert(N >= COLOR_R && N <= COLOR_A, "color component index is out of range");
Color_t colCopy = *this;
colCopy[N] = nValue;
return colCopy;
}
/// @returns: copy of color with certain R/G/B/A component multiplied by given value
template <std::size_t N>
[[nodiscard]] Color_t Multiplier(const float flValue) const
{
static_assert(N >= COLOR_R && N <= COLOR_A, "color component index is out of range");
Color_t colCopy = *this;
colCopy[N] = static_cast<std::uint8_t>(static_cast<float>(colCopy[N]) * flValue);
return colCopy;
}
/// @returns: copy of color with certain R/G/B/A component divided by given value
template <std::size_t N>
[[nodiscard]] Color_t Divider(const int iValue) const
{
static_assert(N >= COLOR_R && N <= COLOR_A, "color component index is out of range");
Color_t colCopy = *this;
colCopy[N] /= iValue;
return colCopy;
}
/// @returns: certain R/G/B/A float value (in: [0 .. 255], out: [0.0 .. 1.0])
template <std::size_t N>
[[nodiscard]] float Base() const
{
static_assert(N >= COLOR_R && N <= COLOR_A, "color component index is out of range");
return reinterpret_cast<const std::uint8_t*>(this)[N] / 255.f;
}
/// @param[out] arrBase output array of R/G/B color components converted to float (in: [0 .. 255], out: [0.0 .. 1.0])
constexpr void Base(float (&arrBase)[3]) const
{
arrBase[COLOR_R] = static_cast<float>(r) / 255.f;
arrBase[COLOR_G] = static_cast<float>(g) / 255.f;
arrBase[COLOR_B] = static_cast<float>(b) / 255.f;
}
/// @returns: color created from float[3] array (in: [0.0 .. 1.0], out: [0 .. 255])
static Color_t FromBase3(const float arrBase[3])
{
return { arrBase[0], arrBase[1], arrBase[2] };
}
/// @param[out] arrBase output array of R/G/B/A color components converted to float (in: [0 .. 255], out: [0.0 .. 1.0])
constexpr void BaseAlpha(float (&arrBase)[4]) const
{
arrBase[COLOR_R] = static_cast<float>(r) / 255.f;
arrBase[COLOR_G] = static_cast<float>(g) / 255.f;
arrBase[COLOR_B] = static_cast<float>(b) / 255.f;
arrBase[COLOR_A] = static_cast<float>(a) / 255.f;
}
/// @returns : color created from float[3] array (in: [0.0 .. 1.0], out: [0 .. 255])
static Color_t FromBase4(const float arrBase[4])
{
return { arrBase[COLOR_R], arrBase[COLOR_G], arrBase[COLOR_B], arrBase[COLOR_A] };
}
/// @param[out] arrHSB output array of HSB/HSV color converted from RGB color
void ToHSB(float (&arrHSB)[3]) const
{
float arrBase[3] = {};
Base(arrBase);
float flKernel = 0.0f;
if (arrBase[COLOR_G] < arrBase[COLOR_B])
{
CRT::Swap(arrBase[COLOR_G], arrBase[COLOR_B]);
flKernel = -1.0f;
}
if (arrBase[COLOR_R] < arrBase[COLOR_G])
{
CRT::Swap(arrBase[COLOR_R], arrBase[COLOR_G]);
flKernel = -2.0f / 6.0f - flKernel;
}
const float flChroma = arrBase[COLOR_R] - MATH::Min(arrBase[COLOR_G], arrBase[COLOR_B]);
arrHSB[COLOR_R] = std::fabsf(flKernel + (arrBase[COLOR_G] - arrBase[COLOR_B]) / (6.0f * flChroma + std::numeric_limits<float>::epsilon()));
arrHSB[COLOR_G] = flChroma / (arrBase[COLOR_R] + std::numeric_limits<float>::epsilon());
arrHSB[COLOR_G] = arrBase[COLOR_R];
}
/// @returns: RGB color converted from HSB/HSV color
static Color_t FromHSB(const float flHue, const float flSaturation, const float flBrightness, const float flAlpha = 1.0f)
{
constexpr float flHueRange = (60.0f / 360.0f);
const float flHuePrime = std::fmodf(flHue, 1.0f) / flHueRange;
const int iRoundHuePrime = static_cast<int>(flHuePrime);
const float flDelta = flHuePrime - static_cast<float>(iRoundHuePrime);
const float p = flBrightness * (1.0f - flSaturation);
const float q = flBrightness * (1.0f - flSaturation * flDelta);
const float t = flBrightness * (1.0f - flSaturation * (1.0f - flDelta));
float flRed, flGreen, flBlue;
switch (iRoundHuePrime)
{
case 0:
flRed = flBrightness;
flGreen = t;
flBlue = p;
break;
case 1:
flRed = q;
flGreen = flBrightness;
flBlue = p;
break;
case 2:
flRed = p;
flGreen = flBrightness;
flBlue = t;
break;
case 3:
flRed = p;
flGreen = q;
flBlue = flBrightness;
break;
case 4:
flRed = t;
flGreen = p;
flBlue = flBrightness;
break;
default:
flRed = flBrightness;
flGreen = p;
flBlue = q;
break;
}
return { flRed, flGreen, flBlue, flAlpha };
}
std::uint8_t r = 0U, g = 0U, b = 0U, a = 0U;
};

View File

@@ -0,0 +1,35 @@
#pragma once
// used: MEM_PAD, FindPattern
#include "../../utilities/memory.h"
struct KV3ID_t
{
const char* szName;
std::uint64_t unk0;
std::uint64_t unk1;
};
class CKeyValues3
{
public:
MEM_PAD(0x100);
std::uint64_t uKey;
void* pValue;
MEM_PAD(0x8);
void LoadFromBuffer(const char* szString);
bool LoadKV3(CUtlBuffer* buffer);
static CKeyValues3* CreateMaterialResource()
{
using fnSetTypeKV3 = CKeyValues3*(CS_FASTCALL*)(CKeyValues3*, unsigned int, unsigned int);
static const fnSetTypeKV3 oSetTypeKV3 = reinterpret_cast<fnSetTypeKV3>(MEM::FindPattern(CLIENT_DLL, CS_XOR("40 53 48 83 EC 20 48 8B 01 48 8B D9 44")));
#ifdef CS_PARANOID
CS_ASSERT(oSetTypeKV3 != nullptr);
#endif
CKeyValues3* pKeyValue = new CKeyValues3[0x10];
return oSetTypeKV3(pKeyValue, 1U, 6U);
}
};

View File

@@ -0,0 +1,26 @@
#include "keyvalue3.h"
// used: CRT
#include "../../utilities/crt.h"
// used: utlbuffer
#include "utlbuffer.h"
void CKeyValues3::LoadFromBuffer(const char* szString)
{
CUtlBuffer buffer(0, (CRT::StringLength(szString) + 10), 1);
buffer.PutString(szString);
LoadKV3(&buffer);
}
bool CKeyValues3::LoadKV3(CUtlBuffer* buffer)
{
using fnLoadKeyValues = bool(CS_FASTCALL*)(CKeyValues3*, void*, CUtlBuffer*, KV3ID_t*, void*, void*, void*, void*, const char*);
static const fnLoadKeyValues oLoadKeyValues = reinterpret_cast<fnLoadKeyValues>(MEM::GetAbsoluteAddress(MEM::FindPattern(TIER0_DLL, CS_XOR("E8 ? ? ? ? EB 36 8B 43 10")), 0x1, 0x0));
#ifdef CS_PARANOID
CS_ASSERT(oLoadKeyValues != nullptr);
#endif
const char* szName = CS_XOR("");
KV3ID_t kv3ID = KV3ID_t(CS_XOR("generic"), 0x41B818518343427E, 0xB5F447C23C0CDF8C);
return oLoadKeyValues(this, nullptr, buffer, &kv3ID, nullptr, nullptr, nullptr, nullptr, CS_XOR(""));
}

View File

@@ -0,0 +1,25 @@
#include "matrix.h"
#include "qangle.h"
// used: m_rad2deg
#include "../../utilities/math.h"
[[nodiscard]] QAngle_t Matrix3x4_t::ToAngles() const
{
// extract the basis vectors from the matrix. since we only need the z component of the up vector, we don't get x and y
const Vector_t vecForward = this->GetForward();
const Vector_t vecLeft = this->GetLeft();
const float flUpZ = this->arrData[2][2];
const float flLength2D = vecForward.Length2D();
const float flPitch = M_RAD2DEG(std::atan2f(-vecForward.z, flLength2D));
// check is enough here to get angles
if (flLength2D > 0.001f)
return { flPitch, M_RAD2DEG(std::atan2f(vecForward.y, vecForward.x)), M_RAD2DEG(std::atan2f(vecLeft.z, flUpZ)) };
// forward is mostly Z, gimbal lock
// assume no roll in this case as one degree of freedom has been lost (i.e. yaw equals roll)
return { flPitch, M_RAD2DEG(std::atan2f(-vecLeft.x, vecLeft.y)), 0.0f };
}

View File

@@ -0,0 +1,439 @@
#pragma once
// used: sse2 intrinsics
#include <xmmintrin.h>
// used: bit_cast
#include <bit>
#include "../../common.h"
#include "vector.h"
// forward declarations
struct QAngle_t;
#pragma pack(push, 4)
using Matrix3x3_t = float[3][3];
struct Matrix3x4_t
{
Matrix3x4_t() = default;
constexpr Matrix3x4_t(
const float m00, const float m01, const float m02, const float m03,
const float m10, const float m11, const float m12, const float m13,
const float m20, const float m21, const float m22, const float m23)
{
arrData[0][0] = m00;
arrData[0][1] = m01;
arrData[0][2] = m02;
arrData[0][3] = m03;
arrData[1][0] = m10;
arrData[1][1] = m11;
arrData[1][2] = m12;
arrData[1][3] = m13;
arrData[2][0] = m20;
arrData[2][1] = m21;
arrData[2][2] = m22;
arrData[2][3] = m23;
}
constexpr Matrix3x4_t(const Vector_t& vecForward, const Vector_t& vecLeft, const Vector_t& vecUp, const Vector_t& vecOrigin)
{
SetForward(vecForward);
SetLeft(vecLeft);
SetUp(vecUp);
SetOrigin(vecOrigin);
}
[[nodiscard]] float* operator[](const int nIndex)
{
return arrData[nIndex];
}
[[nodiscard]] const float* operator[](const int nIndex) const
{
return arrData[nIndex];
}
constexpr void SetForward(const Vector_t& vecForward)
{
arrData[0][0] = vecForward.x;
arrData[1][0] = vecForward.y;
arrData[2][0] = vecForward.z;
}
constexpr void SetLeft(const Vector_t& vecLeft)
{
arrData[0][1] = vecLeft.x;
arrData[1][1] = vecLeft.y;
arrData[2][1] = vecLeft.z;
}
constexpr void SetUp(const Vector_t& vecUp)
{
arrData[0][2] = vecUp.x;
arrData[1][2] = vecUp.y;
arrData[2][2] = vecUp.z;
}
constexpr void SetOrigin(const Vector_t& vecOrigin)
{
arrData[0][3] = vecOrigin.x;
arrData[1][3] = vecOrigin.y;
arrData[2][3] = vecOrigin.z;
}
[[nodiscard]] constexpr Vector_t GetForward() const
{
return { arrData[0][0], arrData[1][0], arrData[2][0] };
}
[[nodiscard]] constexpr Vector_t GetLeft() const
{
return { arrData[0][1], arrData[1][1], arrData[2][1] };
}
[[nodiscard]] constexpr Vector_t GetUp() const
{
return { arrData[0][2], arrData[1][2], arrData[2][2] };
}
[[nodiscard]] constexpr Vector_t GetOrigin() const
{
return { arrData[0][3], arrData[1][3], arrData[2][3] };
}
constexpr void Invalidate()
{
for (auto& arrSubData : arrData)
{
for (auto& flData : arrSubData)
flData = std::numeric_limits<float>::infinity();
}
}
/// concatenate transformations of two matrices into one
/// @returns: matrix with concatenated transformations
[[nodiscard]] constexpr Matrix3x4_t ConcatTransforms(const Matrix3x4_t& matOther) const
{
return {
arrData[0][0] * matOther.arrData[0][0] + arrData[0][1] * matOther.arrData[1][0] + arrData[0][2] * matOther.arrData[2][0],
arrData[0][0] * matOther.arrData[0][1] + arrData[0][1] * matOther.arrData[1][1] + arrData[0][2] * matOther.arrData[2][1],
arrData[0][0] * matOther.arrData[0][2] + arrData[0][1] * matOther.arrData[1][2] + arrData[0][2] * matOther.arrData[2][2],
arrData[0][0] * matOther.arrData[0][3] + arrData[0][1] * matOther.arrData[1][3] + arrData[0][2] * matOther.arrData[2][3] + arrData[0][3],
arrData[1][0] * matOther.arrData[0][0] + arrData[1][1] * matOther.arrData[1][0] + arrData[1][2] * matOther.arrData[2][0],
arrData[1][0] * matOther.arrData[0][1] + arrData[1][1] * matOther.arrData[1][1] + arrData[1][2] * matOther.arrData[2][1],
arrData[1][0] * matOther.arrData[0][2] + arrData[1][1] * matOther.arrData[1][2] + arrData[1][2] * matOther.arrData[2][2],
arrData[1][0] * matOther.arrData[0][3] + arrData[1][1] * matOther.arrData[1][3] + arrData[1][2] * matOther.arrData[2][3] + arrData[1][3],
arrData[2][0] * matOther.arrData[0][0] + arrData[2][1] * matOther.arrData[1][0] + arrData[2][2] * matOther.arrData[2][0],
arrData[2][0] * matOther.arrData[0][1] + arrData[2][1] * matOther.arrData[1][1] + arrData[2][2] * matOther.arrData[2][1],
arrData[2][0] * matOther.arrData[0][2] + arrData[2][1] * matOther.arrData[1][2] + arrData[2][2] * matOther.arrData[2][2],
arrData[2][0] * matOther.arrData[0][3] + arrData[2][1] * matOther.arrData[1][3] + arrData[2][2] * matOther.arrData[2][3] + arrData[2][3]
};
}
/// @returns: angles converted from this matrix
[[nodiscard]] QAngle_t ToAngles() const;
float arrData[3][4] = {};
};
#pragma pack(pop)
class alignas(16) Matrix3x4a_t : public Matrix3x4_t
{
public:
Matrix3x4a_t() = default;
constexpr Matrix3x4a_t(
const float m00, const float m01, const float m02, const float m03,
const float m10, const float m11, const float m12, const float m13,
const float m20, const float m21, const float m22, const float m23)
{
arrData[0][0] = m00;
arrData[0][1] = m01;
arrData[0][2] = m02;
arrData[0][3] = m03;
arrData[1][0] = m10;
arrData[1][1] = m11;
arrData[1][2] = m12;
arrData[1][3] = m13;
arrData[2][0] = m20;
arrData[2][1] = m21;
arrData[2][2] = m22;
arrData[2][3] = m23;
}
constexpr Matrix3x4a_t(const Matrix3x4_t& matSource)
{
*this = matSource;
}
constexpr Matrix3x4a_t& operator=(const Matrix3x4_t& matSource)
{
arrData[0][0] = matSource.arrData[0][0];
arrData[0][1] = matSource.arrData[0][1];
arrData[0][2] = matSource.arrData[0][2];
arrData[0][3] = matSource.arrData[0][3];
arrData[1][0] = matSource.arrData[1][0];
arrData[1][1] = matSource.arrData[1][1];
arrData[1][2] = matSource.arrData[1][2];
arrData[1][3] = matSource.arrData[1][3];
arrData[2][0] = matSource.arrData[2][0];
arrData[2][1] = matSource.arrData[2][1];
arrData[2][2] = matSource.arrData[2][2];
arrData[2][3] = matSource.arrData[2][3];
return *this;
}
/// concatenate transformations of two aligned matrices into one
/// @returns: aligned matrix with concatenated transformations
[[nodiscard]] Matrix3x4a_t ConcatTransforms(const Matrix3x4a_t& matOther) const
{
Matrix3x4a_t matOutput;
CS_ASSERT((reinterpret_cast<std::uintptr_t>(this) & 15U) == 0 && (reinterpret_cast<std::uintptr_t>(&matOther) & 15U) == 0 && (reinterpret_cast<std::uintptr_t>(&matOutput) & 15U) == 0); // matrices aren't aligned
__m128 thisRow0 = _mm_load_ps(this->arrData[0]);
__m128 thisRow1 = _mm_load_ps(this->arrData[1]);
__m128 thisRow2 = _mm_load_ps(this->arrData[2]);
__m128 otherRow0 = _mm_load_ps(matOther.arrData[0]);
__m128 otherRow1 = _mm_load_ps(matOther.arrData[1]);
__m128 otherRow2 = _mm_load_ps(matOther.arrData[2]);
__m128 outRow0 = _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(thisRow0, thisRow0, _MM_SHUFFLE(0, 0, 0, 0)), otherRow0), _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(thisRow0, thisRow0, _MM_SHUFFLE(1, 1, 1, 1)), otherRow1), _mm_mul_ps(_mm_shuffle_ps(thisRow0, thisRow0, _MM_SHUFFLE(2, 2, 2, 2)), otherRow2)));
__m128 outRow1 = _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(thisRow1, thisRow1, _MM_SHUFFLE(0, 0, 0, 0)), otherRow0), _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(thisRow1, thisRow1, _MM_SHUFFLE(1, 1, 1, 1)), otherRow1), _mm_mul_ps(_mm_shuffle_ps(thisRow1, thisRow1, _MM_SHUFFLE(2, 2, 2, 2)), otherRow2)));
__m128 outRow2 = _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(thisRow2, thisRow2, _MM_SHUFFLE(0, 0, 0, 0)), otherRow0), _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(thisRow2, thisRow2, _MM_SHUFFLE(1, 1, 1, 1)), otherRow1), _mm_mul_ps(_mm_shuffle_ps(thisRow2, thisRow2, _MM_SHUFFLE(2, 2, 2, 2)), otherRow2)));
// add in translation vector
constexpr std::uint32_t arrComponentMask[4] = { 0x0, 0x0, 0x0, 0xFFFFFFFF };
outRow0 = _mm_add_ps(outRow0, _mm_and_ps(thisRow0, std::bit_cast<__m128>(arrComponentMask)));
outRow1 = _mm_add_ps(outRow1, _mm_and_ps(thisRow1, std::bit_cast<__m128>(arrComponentMask)));
outRow2 = _mm_add_ps(outRow2, _mm_and_ps(thisRow2, std::bit_cast<__m128>(arrComponentMask)));
_mm_store_ps(matOutput.arrData[0], outRow0);
_mm_store_ps(matOutput.arrData[1], outRow1);
_mm_store_ps(matOutput.arrData[2], outRow2);
return matOutput;
}
};
static_assert(alignof(Matrix3x4a_t) == 16);
#pragma pack(push, 4)
struct ViewMatrix_t
{
ViewMatrix_t() = default;
constexpr ViewMatrix_t(
const float m00, const float m01, const float m02, const float m03,
const float m10, const float m11, const float m12, const float m13,
const float m20, const float m21, const float m22, const float m23,
const float m30, const float m31, const float m32, const float m33)
{
arrData[0][0] = m00;
arrData[0][1] = m01;
arrData[0][2] = m02;
arrData[0][3] = m03;
arrData[1][0] = m10;
arrData[1][1] = m11;
arrData[1][2] = m12;
arrData[1][3] = m13;
arrData[2][0] = m20;
arrData[2][1] = m21;
arrData[2][2] = m22;
arrData[2][3] = m23;
arrData[3][0] = m30;
arrData[3][1] = m31;
arrData[3][2] = m32;
arrData[3][3] = m33;
}
constexpr ViewMatrix_t(const Matrix3x4_t& matFrom, const Vector4D_t& vecAdditionalRow = {})
{
arrData[0][0] = matFrom.arrData[0][0];
arrData[0][1] = matFrom.arrData[0][1];
arrData[0][2] = matFrom.arrData[0][2];
arrData[0][3] = matFrom.arrData[0][3];
arrData[1][0] = matFrom.arrData[1][0];
arrData[1][1] = matFrom.arrData[1][1];
arrData[1][2] = matFrom.arrData[1][2];
arrData[1][3] = matFrom.arrData[1][3];
arrData[2][0] = matFrom.arrData[2][0];
arrData[2][1] = matFrom.arrData[2][1];
arrData[2][2] = matFrom.arrData[2][2];
arrData[2][3] = matFrom.arrData[2][3];
arrData[3][0] = vecAdditionalRow.x;
arrData[3][1] = vecAdditionalRow.y;
arrData[3][2] = vecAdditionalRow.z;
arrData[3][3] = vecAdditionalRow.w;
}
[[nodiscard]] float* operator[](const int nIndex)
{
return arrData[nIndex];
}
[[nodiscard]] const float* operator[](const int nIndex) const
{
return arrData[nIndex];
}
[[nodiscard]] const bool operator==(const ViewMatrix_t& viewOther) const
{
return (
arrData[0][0] == viewOther.arrData[0][0] && arrData[0][1] == viewOther.arrData[0][1] && arrData[0][2] == viewOther.arrData[0][2] && arrData[0][3] == viewOther.arrData[0][3] &&
arrData[1][0] == viewOther.arrData[1][0] && arrData[1][1] == viewOther.arrData[1][1] && arrData[1][2] == viewOther.arrData[1][2] && arrData[1][3] == viewOther.arrData[1][3] &&
arrData[2][0] == viewOther.arrData[2][0] && arrData[2][1] == viewOther.arrData[2][1] && arrData[2][2] == viewOther.arrData[2][2] && arrData[2][3] == viewOther.arrData[2][3] &&
arrData[3][0] == viewOther.arrData[3][0] && arrData[3][1] == viewOther.arrData[3][1] && arrData[3][2] == viewOther.arrData[3][2] && arrData[3][3] == viewOther.arrData[3][3]);
}
[[nodiscard]] const Matrix3x4_t& As3x4() const
{
return *reinterpret_cast<const Matrix3x4_t*>(this);
}
[[nodiscard]] Matrix3x4_t& As3x4()
{
return *reinterpret_cast<Matrix3x4_t*>(this);
}
constexpr ViewMatrix_t& operator+=(const ViewMatrix_t& matAdd)
{
for (std::uint8_t c = 0U; c < 4U; c++)
{
for (std::uint8_t r = 0U; r < 4U; r++)
arrData[c][r] += matAdd[c][r];
}
return *this;
}
constexpr ViewMatrix_t& operator-=(const ViewMatrix_t& matSubtract)
{
for (std::uint8_t c = 0U; c < 4U; c++)
{
for (std::uint8_t r = 0U; r < 4U; r++)
arrData[c][r] -= matSubtract[c][r];
}
return *this;
}
[[nodiscard]] constexpr Vector4D_t GetRow(const int nIndex) const
{
return { arrData[nIndex][0], arrData[nIndex][1], arrData[nIndex][2], arrData[nIndex][3] };
}
[[nodiscard]] constexpr Vector4D_t GetColumn(const int nIndex) const
{
return { arrData[0][nIndex], arrData[1][nIndex], arrData[2][nIndex], arrData[3][nIndex] };
}
constexpr void Identity()
{
for (std::uint8_t c = 0U; c < 4U; c++)
{
for (std::uint8_t r = 0U; r < 4U; r++)
arrData[c][r] = (c == r) ? 1.0f : 0.0f;
}
}
/// concatenate transformations of two matrices into one
/// @returns: matrix with concatenated transformations
[[nodiscard]] constexpr ViewMatrix_t ConcatTransforms(const ViewMatrix_t& matOther) const
{
return {
arrData[0][0] * matOther.arrData[0][0] + arrData[0][1] * matOther.arrData[1][0] + arrData[0][2] * matOther.arrData[2][0] + arrData[0][3] * matOther.arrData[3][0],
arrData[0][0] * matOther.arrData[0][1] + arrData[0][1] * matOther.arrData[1][1] + arrData[0][2] * matOther.arrData[2][1] + arrData[0][3] * matOther.arrData[3][1],
arrData[0][0] * matOther.arrData[0][2] + arrData[0][1] * matOther.arrData[1][2] + arrData[0][2] * matOther.arrData[2][2] + arrData[0][3] * matOther.arrData[3][2],
arrData[0][0] * matOther.arrData[0][3] + arrData[0][1] * matOther.arrData[1][3] + arrData[0][2] * matOther.arrData[2][3] + arrData[0][3] * matOther.arrData[3][3],
arrData[1][0] * matOther.arrData[0][0] + arrData[1][1] * matOther.arrData[1][0] + arrData[1][2] * matOther.arrData[2][0] + arrData[1][3] * matOther.arrData[3][0],
arrData[1][0] * matOther.arrData[0][1] + arrData[1][1] * matOther.arrData[1][1] + arrData[1][2] * matOther.arrData[2][1] + arrData[1][3] * matOther.arrData[3][1],
arrData[1][0] * matOther.arrData[0][2] + arrData[1][1] * matOther.arrData[1][2] + arrData[1][2] * matOther.arrData[2][2] + arrData[1][3] * matOther.arrData[3][2],
arrData[1][0] * matOther.arrData[0][3] + arrData[1][1] * matOther.arrData[1][3] + arrData[1][2] * matOther.arrData[2][3] + arrData[1][3] * matOther.arrData[3][3],
arrData[2][0] * matOther.arrData[0][0] + arrData[2][1] * matOther.arrData[1][0] + arrData[2][2] * matOther.arrData[2][0] + arrData[2][3] * matOther.arrData[3][0],
arrData[2][0] * matOther.arrData[0][1] + arrData[2][1] * matOther.arrData[1][1] + arrData[2][2] * matOther.arrData[2][1] + arrData[2][3] * matOther.arrData[3][1],
arrData[2][0] * matOther.arrData[0][2] + arrData[2][1] * matOther.arrData[1][2] + arrData[2][2] * matOther.arrData[2][2] + arrData[2][3] * matOther.arrData[3][2],
arrData[2][0] * matOther.arrData[0][3] + arrData[2][1] * matOther.arrData[1][3] + arrData[2][2] * matOther.arrData[2][3] + arrData[2][3] * matOther.arrData[3][3],
arrData[3][0] * matOther.arrData[0][0] + arrData[3][1] * matOther.arrData[1][0] + arrData[3][2] * matOther.arrData[2][0] + arrData[3][3] * matOther.arrData[3][0],
arrData[3][0] * matOther.arrData[0][1] + arrData[3][1] * matOther.arrData[1][1] + arrData[3][2] * matOther.arrData[2][1] + arrData[3][3] * matOther.arrData[3][1],
arrData[3][0] * matOther.arrData[0][2] + arrData[3][1] * matOther.arrData[1][2] + arrData[3][2] * matOther.arrData[2][2] + arrData[3][3] * matOther.arrData[3][2],
arrData[3][0] * matOther.arrData[0][3] + arrData[3][1] * matOther.arrData[1][3] + arrData[3][2] * matOther.arrData[2][3] + arrData[3][3] * matOther.arrData[3][3]
};
}
float arrData[4][4] = {};
};
#pragma pack(pop)
struct Matrix2x4_t
{
public:
Matrix3x4_t TranslateToMatrix3x4()
{
Matrix3x4_t matrix = Matrix3x4_t();
Vector4D_t vecRotation = Vector4D_t();
Vector_t vecPosition = Vector_t();
vecRotation.x = this->_21; //rot.x
vecRotation.y = this->_22; //rot.y
vecRotation.z = this->_23; //rot.z
vecRotation.w = this->_24; //rot.w
vecPosition.x = this->_11; //bonepos.x
vecPosition.y = this->_12; //bonepos.y
vecPosition.z = this->_13; //bonepos.z
matrix[0][0] = 1.0f - 2.0f * vecRotation.y * vecRotation.y - 2.0f * vecRotation.z * vecRotation.z;
matrix[1][0] = 2.0f * vecRotation.x * vecRotation.y + 2.0f * vecRotation.w * vecRotation.z;
matrix[2][0] = 2.0f * vecRotation.x * vecRotation.z - 2.0f * vecRotation.w * vecRotation.y;
matrix[0][1] = 2.0f * vecRotation.x * vecRotation.y - 2.0f * vecRotation.w * vecRotation.z;
matrix[1][1] = 1.0f - 2.0f * vecRotation.x * vecRotation.x - 2.0f * vecRotation.z * vecRotation.z;
matrix[2][1] = 2.0f * vecRotation.y * vecRotation.z + 2.0f * vecRotation.w * vecRotation.x;
matrix[0][2] = 2.0f * vecRotation.x * vecRotation.z + 2.0f * vecRotation.w * vecRotation.y;
matrix[1][2] = 2.0f * vecRotation.y * vecRotation.z - 2.0f * vecRotation.w * vecRotation.x;
matrix[2][2] = 1.0f - 2.0f * vecRotation.x * vecRotation.x - 2.0f * vecRotation.y * vecRotation.y;
matrix[0][3] = vecPosition.x;
matrix[1][3] = vecPosition.y;
matrix[2][3] = vecPosition.z;
return matrix;
}
[[nodiscard]] const Vector_t GetOrigin(int nIndex)
{
return Vector_t(this[nIndex]._11, this[nIndex]._12, this[nIndex]._13);
}
const void SetOrigin(int nIndex, Vector_t vecValue)
{
this[nIndex]._11 = vecValue.x;
this[nIndex]._12 = vecValue.y;
this[nIndex]._13 = vecValue.z;
}
[[nodiscard]] const Vector4D_t GetRotation(int nIndex)
{
return Vector4D_t(this[nIndex]._21, this[nIndex]._22, this[nIndex]._23, this[nIndex]._24);
}
union
{
struct
{
float _11, _12, _13, _14;
float _21, _22, _23, _24;
};
};
};

View File

@@ -0,0 +1,52 @@
#include "qangle.h"
// used: [d3d] xmscalarsincos
#include <directxmath.h>
#include "matrix.h"
// used: m_deg2rad
#include "../../utilities/math.h"
void QAngle_t::ToDirections(Vector_t* pvecForward, Vector_t* pvecRight, Vector_t* pvecUp) const
{
float flPitchSin, flPitchCos, flYawSin, flYawCos, flRollSin, flRollCos;
DirectX::XMScalarSinCos(&flPitchSin, &flPitchCos, M_DEG2RAD(this->x));
DirectX::XMScalarSinCos(&flYawSin, &flYawCos, M_DEG2RAD(this->y));
DirectX::XMScalarSinCos(&flRollSin, &flRollCos, M_DEG2RAD(this->z));
if (pvecForward != nullptr)
{
pvecForward->x = flPitchCos * flYawCos;
pvecForward->y = flPitchCos * flYawSin;
pvecForward->z = -flPitchSin;
}
if (pvecRight != nullptr)
{
pvecRight->x = (-flRollSin * flPitchSin * flYawCos) + (-flRollCos * -flYawSin);
pvecRight->y = (-flRollSin * flPitchSin * flYawSin) + (-flRollCos * flYawCos);
pvecRight->z = (-flRollSin * flPitchCos);
}
if (pvecUp != nullptr)
{
pvecUp->x = (flRollCos * flPitchSin * flYawCos) + (-flRollSin * -flYawSin);
pvecUp->y = (flRollCos * flPitchSin * flYawSin) + (-flRollSin * flYawCos);
pvecUp->z = (flRollCos * flPitchCos);
}
}
Matrix3x4_t QAngle_t::ToMatrix(const Vector_t& vecOrigin) const
{
float flPitchSin, flPitchCos, flYawSin, flYawCos, flRollSin, flRollCos;
DirectX::XMScalarSinCos(&flPitchSin, &flPitchCos, M_DEG2RAD(this->x));
DirectX::XMScalarSinCos(&flYawSin, &flYawCos, M_DEG2RAD(this->y));
DirectX::XMScalarSinCos(&flRollSin, &flRollCos, M_DEG2RAD(this->z));
return {
(flPitchCos * flYawCos), (flRollSin * flPitchSin * flYawCos + flRollCos * -flYawSin), (flRollCos * flPitchSin * flYawCos + -flRollSin * -flYawSin), vecOrigin.x,
(flPitchCos * flYawSin), (flRollSin * flPitchSin * flYawSin + flRollCos * flYawCos), (flRollCos * flPitchSin * flYawSin + -flRollSin * flYawCos), vecOrigin.y,
(-flPitchSin), (flRollSin * flPitchCos), (flRollCos * flPitchCos), vecOrigin.z
};
}

View File

@@ -0,0 +1,247 @@
#pragma once
// used: [crt] isfinite, fmodf, remainderf
#include <cmath>
#include "vector.h"
// used: clamp
#include "../../utilities/crt.h"
// forward declarations
struct Matrix3x4_t;
struct QAngle_t
{
constexpr QAngle_t(float x = 0.f, float y = 0.f, float z = 0.f) :
x(x), y(y), z(z) { }
constexpr QAngle_t(const float* arrAngles) :
x(arrAngles[0]), y(arrAngles[1]), z(arrAngles[2]) { }
#pragma region qangle_array_operators
[[nodiscard]] float& operator[](const int nIndex)
{
return reinterpret_cast<float*>(this)[nIndex];
}
[[nodiscard]] const float& operator[](const int nIndex) const
{
return reinterpret_cast<const float*>(this)[nIndex];
}
#pragma endregion
#pragma region qangle_relational_operators
bool operator==(const QAngle_t& angBase) const
{
return this->IsEqual(angBase);
}
bool operator!=(const QAngle_t& angBase) const
{
return !this->IsEqual(angBase);
}
#pragma endregion
#pragma region qangle_assignment_operators
constexpr QAngle_t& operator=(const QAngle_t& angBase)
{
this->x = angBase.x;
this->y = angBase.y;
this->z = angBase.z;
return *this;
}
#pragma endregion
#pragma region qangle_arithmetic_assignment_operators
constexpr QAngle_t& operator+=(const QAngle_t& angBase)
{
this->x += angBase.x;
this->y += angBase.y;
this->z += angBase.z;
return *this;
}
constexpr QAngle_t& operator-=(const QAngle_t& angBase)
{
this->x -= angBase.x;
this->y -= angBase.y;
this->z -= angBase.z;
return *this;
}
constexpr QAngle_t& operator*=(const QAngle_t& angBase)
{
this->x *= angBase.x;
this->y *= angBase.y;
this->z *= angBase.z;
return *this;
}
constexpr QAngle_t& operator/=(const QAngle_t& angBase)
{
this->x /= angBase.x;
this->y /= angBase.y;
this->z /= angBase.z;
return *this;
}
constexpr QAngle_t& operator+=(const float flAdd)
{
this->x += flAdd;
this->y += flAdd;
this->z += flAdd;
return *this;
}
constexpr QAngle_t& operator-=(const float flSubtract)
{
this->x -= flSubtract;
this->y -= flSubtract;
this->z -= flSubtract;
return *this;
}
constexpr QAngle_t& operator*=(const float flMultiply)
{
this->x *= flMultiply;
this->y *= flMultiply;
this->z *= flMultiply;
return *this;
}
constexpr QAngle_t& operator/=(const float flDivide)
{
this->x /= flDivide;
this->y /= flDivide;
this->z /= flDivide;
return *this;
}
#pragma endregion
#pragma region qangle_arithmetic_unary_operators
constexpr QAngle_t& operator-()
{
this->x = -this->x;
this->y = -this->y;
this->z = -this->z;
return *this;
}
constexpr QAngle_t operator-() const
{
return { -this->x, -this->y, -this->z };
}
#pragma endregion
#pragma region qangle_arithmetic_ternary_operators
constexpr QAngle_t operator+(const QAngle_t& angAdd) const
{
return { this->x + angAdd.x, this->y + angAdd.y, this->z + angAdd.z };
}
constexpr QAngle_t operator-(const QAngle_t& angSubtract) const
{
return { this->x - angSubtract.x, this->y - angSubtract.y, this->z - angSubtract.z };
}
constexpr QAngle_t operator*(const QAngle_t& angMultiply) const
{
return { this->x * angMultiply.x, this->y * angMultiply.y, this->z * angMultiply.z };
}
constexpr QAngle_t operator/(const QAngle_t& angDivide) const
{
return { this->x / angDivide.x, this->y / angDivide.y, this->z / angDivide.z };
}
constexpr QAngle_t operator+(const float flAdd) const
{
return { this->x + flAdd, this->y + flAdd, this->z + flAdd };
}
constexpr QAngle_t operator-(const float flSubtract) const
{
return { this->x - flSubtract, this->y - flSubtract, this->z - flSubtract };
}
constexpr QAngle_t operator*(const float flMultiply) const
{
return { this->x * flMultiply, this->y * flMultiply, this->z * flMultiply };
}
constexpr QAngle_t operator/(const float flDivide) const
{
return { this->x / flDivide, this->y / flDivide, this->z / flDivide };
}
#pragma endregion
// @returns : true if each component of angle is finite, false otherwise
[[nodiscard]] bool IsValid() const
{
return (std::isfinite(this->x) && std::isfinite(this->y) && std::isfinite(this->z));
}
/// @returns: true if each component of angle equals to another, false otherwise
[[nodiscard]] bool IsEqual(const QAngle_t& angEqual, const float flErrorMargin = std::numeric_limits<float>::epsilon()) const
{
return (std::fabsf(this->x - angEqual.x) < flErrorMargin && std::fabsf(this->y - angEqual.y) < flErrorMargin && std::fabsf(this->z - angEqual.z) < flErrorMargin);
}
/// @returns: true if each component of angle equals zero, false otherwise
[[nodiscard]] bool IsZero() const
{
// @test: to make this implementation right, we should use fpclassify here, but game aren't doing same, probably it's better to keep this same, just ensure that it will be compiled same
return (this->x == 0.0f && this->y == 0.0f && this->z == 0.0f);
}
/// @returns: length of hypotenuse
[[nodiscard]] float Length2D() const
{
return std::sqrtf(x * x + y * y);
}
/// clamp each angle component by minimal/maximal allowed value for source sdk games
/// @returns: clamped angle
constexpr QAngle_t& Clamp()
{
this->x = MATH::Clamp(this->x, -89.f, 89.f);
this->y = MATH::Clamp(this->y, -180.f, 180.f);
this->z = MATH::Clamp(this->z, -45.f, 45.f);
return *this;
}
/// map polar angles to the range of [-180, 180] degrees
/// @returns: normalized angle
QAngle_t& Normalize()
{
this->x = std::remainderf(this->x, 360.f);
this->y = std::remainderf(this->y, 360.f);
this->z = std::remainderf(this->z, 360.f);
return *this;
}
/// convert angle to direction vectors
/// @param[out] pvecForward [optional] output for converted forward vector
/// @param[out] pvecRight [optional] output for converted right vector
/// @param[out] pvecUp [optional] output for converted up vector
void ToDirections(Vector_t* pvecForward, Vector_t* pvecRight = nullptr, Vector_t* pvecUp = nullptr) const;
/// @param[in] vecOrigin [optional] origin for converted matrix
/// @returns: matrix converted from angle
[[nodiscard]] Matrix3x4_t ToMatrix(const Vector_t& vecOrigin = {}) const;
public:
float x = 0.0f, y = 0.0f, z = 0.0f;
};

View File

@@ -0,0 +1,74 @@
#pragma once
struct Quaternion_t
{
constexpr Quaternion_t(const float x = 0.0f, const float y = 0.0f, const float z = 0.0f, const float w = 0.0f) :
x(x), y(y), z(z), w(w) { }
[[nodiscard]] bool IsValid() const
{
return (std::isfinite(x) && std::isfinite(y) && std::isfinite(z) && std::isfinite(w));
}
/// @param[in] vecOrigin [optional] translation for converted matrix
/// @returns: matrix converted from quaternion
[[nodiscard]] Matrix3x4_t ToMatrix(const Vector_t& vecOrigin = {}) const
{
CS_ASSERT(this->IsValid());
Matrix3x4_t matOut;
#ifdef _DEBUG // precalculate common multiplications
const float x2 = this->x + this->x, y2 = this->y + this->y, z2 = this->z + this->z;
const float xx = this->x * x2, xy = this->x * y2, xz = this->x * z2;
const float yy = this->y * y2, yz = this->y * z2;
const float zz = this->z * z2;
const float wx = this->w * x2, wy = this->w * y2, wz = this->w * z2;
matOut[0][0] = 1.0f - (yy + zz);
matOut[1][0] = xy + wz;
matOut[2][0] = xz - wy;
matOut[0][1] = xy - wz;
matOut[1][1] = 1.0f - (xx + zz);
matOut[2][1] = yz + wx;
matOut[0][2] = xz + wy;
matOut[1][2] = yz - wx;
matOut[2][2] = 1.0f - (xx + yy);
#else // let the compiler optimize calculations itself
matOut[0][0] = 1.0f - 2.0f * this->y * this->y - 2.0f * this->z * this->z;
matOut[1][0] = 2.0f * this->x * this->y + 2.0f * this->w * this->z;
matOut[2][0] = 2.0f * this->x * this->z - 2.0f * this->w * this->y;
matOut[0][1] = 2.0f * this->x * this->y - 2.0f * this->w * this->z;
matOut[1][1] = 1.0f - 2.0f * this->x * this->x - 2.0f * this->z * this->z;
matOut[2][1] = 2.0f * this->y * this->z + 2.0f * this->w * this->x;
matOut[0][2] = 2.0f * this->x * this->z + 2.0f * this->w * this->y;
matOut[1][2] = 2.0f * this->y * this->z - 2.0f * this->w * this->x;
matOut[2][2] = 1.0f - 2.0f * this->x * this->x - 2.0f * this->y * this->y;
#endif
matOut[0][3] = vecOrigin.x;
matOut[1][3] = vecOrigin.y;
matOut[2][3] = vecOrigin.z;
return matOut;
}
float x, y, z, w;
};
struct alignas(16) QuaternionAligned_t : Quaternion_t
{
QuaternionAligned_t& operator=(const Quaternion_t& quatOther)
{
this->x = quatOther.x;
this->y = quatOther.y;
this->z = quatOther.z;
this->w = quatOther.w;
return *this;
}
};
static_assert(alignof(QuaternionAligned_t) == 16);

View File

@@ -0,0 +1,30 @@
#pragma once
struct ResourceBinding_t
{
void* pData;
};
template <typename T>
class CStrongHandle
{
public:
operator T* () const
{
if (pBinding == nullptr)
return nullptr;
return static_cast<T*>(pBinding->pData);
}
T* operator->() const
{
if (pBinding == nullptr)
return nullptr;
return static_cast<T*>(pBinding->pData);
}
const ResourceBinding_t* pBinding;
};

View File

@@ -0,0 +1,15 @@
#pragma once
// used: matResult
#include "matrix.h"
// used: quaternion
#include "quaternion.h"
class CTransform
{
public:
VectorAligned_t vecPosition;
QuaternionAligned_t quatOrientation;
};
static_assert(alignof(CTransform) == 16);

View File

@@ -0,0 +1,288 @@
#pragma once
// used: QAngle_t
#include "qangle.h"
// used: MEM_PAD
#include "../../utilities/memory.h"
// used: memalloc
#include "../../core/interfaces.h"
#include "../interfaces/imemalloc.h"
// @source: server.dll
enum ECommandButtons : std::uint64_t
{
IN_ATTACK = 1 << 0,
IN_JUMP = 1 << 1,
IN_DUCK = 1 << 2,
IN_FORWARD = 1 << 3,
IN_BACK = 1 << 4,
IN_USE = 1 << 5,
IN_LEFT = 1 << 7,
IN_RIGHT = 1 << 8,
IN_MOVELEFT = 1 << 9,
IN_MOVERIGHT = 1 << 10,
IN_SECOND_ATTACK = 1 << 11,
IN_RELOAD = 1 << 13,
IN_SPRINT = 1 << 16,
IN_JOYAUTOSPRINT = 1 << 17,
IN_SHOWSCORES = 1ULL << 33,
IN_ZOOM = 1ULL << 34,
IN_LOOKATWEAPON = 1ULL << 35
};
// compiled protobuf messages and looked at what bits are used in them
enum ESubtickMoveStepBits : std::uint32_t
{
MOVESTEP_BITS_BUTTON = 0x1U,
MOVESTEP_BITS_PRESSED = 0x2U,
MOVESTEP_BITS_WHEN = 0x4U,
MOVESTEP_BITS_ANALOG_FORWARD_DELTA = 0x8U,
MOVESTEP_BITS_ANALOG_LEFT_DELTA = 0x10U
};
enum EInputHistoryBits : std::uint32_t
{
INPUT_HISTORY_BITS_VIEWANGLES = 0x1U,
INPUT_HISTORY_BITS_SHOOTPOSITION = 0x2U,
INPUT_HISTORY_BITS_TARGETHEADPOSITIONCHECK = 0x4U,
INPUT_HISTORY_BITS_TARGETABSPOSITIONCHECK = 0x8U,
INPUT_HISTORY_BITS_TARGETANGCHECK = 0x10U,
INPUT_HISTORY_BITS_CL_INTERP = 0x20U,
INPUT_HISTORY_BITS_SV_INTERP0 = 0x40U,
INPUT_HISTORY_BITS_SV_INTERP1 = 0x80U,
INPUT_HISTORY_BITS_PLAYER_INTERP = 0x100U,
INPUT_HISTORY_BITS_RENDERTICKCOUNT = 0x200U,
INPUT_HISTORY_BITS_RENDERTICKFRACTION = 0x400U,
INPUT_HISTORY_BITS_PLAYERTICKCOUNT = 0x800U,
INPUT_HISTORY_BITS_PLAYERTICKFRACTION = 0x1000U,
INPUT_HISTORY_BITS_FRAMENUMBER = 0x2000U,
INPUT_HISTORY_BITS_TARGETENTINDEX = 0x4000U
};
enum EButtonStatePBBits : uint32_t
{
BUTTON_STATE_PB_BITS_BUTTONSTATE1 = 0x1U,
BUTTON_STATE_PB_BITS_BUTTONSTATE2 = 0x2U,
BUTTON_STATE_PB_BITS_BUTTONSTATE3 = 0x4U
};
enum EBaseCmdBits : std::uint32_t
{
BASE_BITS_MOVE_CRC = 0x1U,
BASE_BITS_BUTTONPB = 0x2U,
BASE_BITS_VIEWANGLES = 0x4U,
BASE_BITS_COMMAND_NUMBER = 0x8U,
BASE_BITS_CLIENT_TICK = 0x10U,
BASE_BITS_FORWARDMOVE = 0x20U,
BASE_BITS_LEFTMOVE = 0x40U,
BASE_BITS_UPMOVE = 0x80U,
BASE_BITS_IMPULSE = 0x100U,
BASE_BITS_WEAPON_SELECT = 0x200U,
BASE_BITS_RANDOM_SEED = 0x400U,
BASE_BITS_MOUSEDX = 0x800U,
BASE_BITS_MOUSEDY = 0x1000U,
BASE_BITS_CONSUMED_SERVER_ANGLE = 0x2000U,
BASE_BITS_CMD_FLAGS = 0x4000U,
BASE_BITS_ENTITY_HANDLE = 0x8000U
};
enum ECSGOUserCmdBits : std::uint32_t
{
CSGOUSERCMD_BITS_BASECMD = 0x1U,
CSGOUSERCMD_BITS_LEFTHAND = 0x2U,
CSGOUSERCMD_BITS_ATTACK3START = 0x4U,
CSGOUSERCMD_BITS_ATTACK1START = 0x8U,
CSGOUSERCMD_BITS_ATTACK2START = 0x10U
};
template <typename T>
struct RepeatedPtrField_t
{
struct Rep_t
{
int nAllocatedSize;
T* tElements[(std::numeric_limits<int>::max() - 2 * sizeof(int)) / sizeof(void*)];
};
void* pArena;
int nCurrentSize;
int nTotalSize;
Rep_t* pRep;
};
class CBasePB
{
public:
MEM_PAD(0x8) // 0x0 VTABLE
std::uint32_t nHasBits; // 0x8
std::uint64_t nCachedBits; // 0xC
void SetBits(std::uint64_t nBits)
{
// @note: you don't need to check if the bits are already set as bitwise OR will not change the value if the bit is already set
nCachedBits |= nBits;
}
};
static_assert(sizeof(CBasePB) == 0x18);
class CMsgQAngle : public CBasePB
{
public:
QAngle_t angValue; // 0x18
};
static_assert(sizeof(CMsgQAngle) == 0x28);
class CMsgVector : public CBasePB
{
public:
Vector4D_t vecValue; // 0x18
};
static_assert(sizeof(CMsgVector) == 0x28);
class CCSGOInterpolationInfoPB : public CBasePB
{
public:
float flFraction; // 0x18
int nSrcTick; // 0x1C
int nDstTick; // 0x20
};
static_assert(sizeof(CCSGOInterpolationInfoPB) == 0x28);
class CCSGOInputHistoryEntryPB : public CBasePB
{
public:
CMsgQAngle* pViewAngles; // 0x18
CMsgVector* pShootPosition; // 0x20
CMsgVector* pTargetHeadPositionCheck; // 0x28
CMsgVector* pTargetAbsPositionCheck; // 0x30
CMsgQAngle* pTargetAngPositionCheck; // 0x38
CCSGOInterpolationInfoPB* cl_interp; // 0x40
CCSGOInterpolationInfoPB* sv_interp0; // 0x48
CCSGOInterpolationInfoPB* sv_interp1; // 0x50
CCSGOInterpolationInfoPB* player_interp; // 0x58
int nRenderTickCount; // 0x60
float flRenderTickFraction; // 0x64
int nPlayerTickCount; // 0x68
float flPlayerTickFraction; // 0x6C
int nFrameNumber; // 0x70
int nTargetEntIndex; // 0x74
};
static_assert(sizeof(CCSGOInputHistoryEntryPB) == 0x78);
struct CInButtonStatePB : CBasePB
{
std::uint64_t nValue;
std::uint64_t nValueChanged;
std::uint64_t nValueScroll;
};
static_assert(sizeof(CInButtonStatePB) == 0x30);
struct CSubtickMoveStep : CBasePB
{
public:
std::uint64_t nButton;
bool bPressed;
float flWhen;
float flAnalogForwardDelta;
float flAnalogLeftDelta;
};
static_assert(sizeof(CSubtickMoveStep) == 0x30);
class CBaseUserCmdPB : public CBasePB
{
public:
RepeatedPtrField_t<CSubtickMoveStep> subtickMovesField;
std::string* strMoveCrc;
CInButtonStatePB* pInButtonState;
CMsgQAngle* pViewAngles;
std::int32_t nLegacyCommandNumber;
std::int32_t nClientTick;
float flForwardMove;
float flSideMove;
float flUpMove;
std::int32_t nImpulse;
std::int32_t nWeaponSelect;
std::int32_t nRandomSeed;
std::int32_t nMousedX;
std::int32_t nMousedY;
std::uint32_t nConsumedServerAngleChanges;
std::int32_t nCmdFlags;
std::uint32_t nPawnEntityHandle;
int CalculateCmdCRCSize()
{
return MEM::CallVFunc<int, 7U>(this);
}
};
static_assert(sizeof(CBaseUserCmdPB) == 0x80);
class CCSGOUserCmdPB
{
public:
std::uint32_t nHasBits;
std::uint64_t nCachedSize;
RepeatedPtrField_t<CCSGOInputHistoryEntryPB> inputHistoryField;
CBaseUserCmdPB* pBaseCmd;
bool bLeftHandDesired;
std::int32_t nAttack3StartHistoryIndex;
std::int32_t nAttack1StartHistoryIndex;
std::int32_t nAttack2StartHistoryIndex;
// @note: this function is used to check if the bits are set and set them if they are not
void CheckAndSetBits(std::uint32_t nBits)
{
if (!(nHasBits & nBits))
nHasBits |= nBits;
}
};
static_assert(sizeof(CCSGOUserCmdPB) == 0x40);
struct CInButtonState
{
public:
MEM_PAD(0x8) // 0x0 VTABLE
std::uint64_t nValue; // 0x8
std::uint64_t nValueChanged; // 0x10
std::uint64_t nValueScroll; // 0x18
};
static_assert(sizeof(CInButtonState) == 0x20);
class CUserCmd
{
public:
MEM_PAD(0x8); // 0x0 VTABLE
MEM_PAD(0x10); // TODO: find out what this is, added 14.08.2024
CCSGOUserCmdPB csgoUserCmd; // 0x18
CInButtonState nButtons; // 0x58
MEM_PAD(0x20); // 0x78
CCSGOInputHistoryEntryPB* GetInputHistoryEntry(int nIndex)
{
if (nIndex >= csgoUserCmd.inputHistoryField.pRep->nAllocatedSize || nIndex >= csgoUserCmd.inputHistoryField.nCurrentSize)
return nullptr;
return csgoUserCmd.inputHistoryField.pRep->tElements[nIndex];
}
void SetSubTickAngle(const QAngle_t& angView)
{
for (int i = 0; i < this->csgoUserCmd.inputHistoryField.pRep->nAllocatedSize; i++)
{
CCSGOInputHistoryEntryPB* pInputEntry = this->GetInputHistoryEntry(i);
if (!pInputEntry || !pInputEntry->pViewAngles)
continue;
pInputEntry->pViewAngles->angValue = angView;
pInputEntry->SetBits(EInputHistoryBits::INPUT_HISTORY_BITS_VIEWANGLES);
}
}
};
static_assert(sizeof(CUserCmd) == 0x98);

View File

@@ -0,0 +1,36 @@
#pragma once
// used: MEM_PAD
#include "../../utilities/memory.h"
class CUtlBuffer
{
public:
MEM_PAD(0x80);
CUtlBuffer(int a1, int nSize, int a3)
{
#ifdef CS_PARANOID
CS_ASSERT(MEM::fnUtlBufferInit != nullptr);
#endif
MEM::fnUtlBufferInit(this, a1, nSize, a3);
}
void PutString(const char* szString)
{
#ifdef CS_PARANOID
CS_ASSERT(MEM::fnUtlBufferPutString != nullptr);
#endif
MEM::fnUtlBufferPutString(this, szString);
}
void EnsureCapacity(int nSize)
{
#ifdef CS_PARANOID
CS_ASSERT(MEM::fnUtlBufferEnsureCapacity != nullptr);
#endif
MEM::fnUtlBufferEnsureCapacity(this, nSize);
}
};

View File

@@ -0,0 +1,234 @@
#pragma once
#include "../../common.h"
// @test: using interfaces in the header | not critical but could blow up someday with thousands of errors or affect to compilation time etc
// used: interface handles
#include "../../core/interfaces.h"
// used: interface declarations
#include "../interfaces/imemalloc.h"
// @source: master/public/tier1/utlfixedmemory.h
template <class T>
class CUtlFixedMemory
{
protected:
struct BlockHeader_t
{
BlockHeader_t* pNext;
std::intptr_t nBlockSize;
};
public:
class Iterator_t
{
public:
Iterator_t(BlockHeader_t* pBlockHeader, const std::intptr_t nIndex) :
pBlockHeader(pBlockHeader), nIndex(nIndex) { }
bool operator==(const Iterator_t it) const
{
return pBlockHeader == it.pBlockHeader && nIndex == it.nIndex;
}
bool operator!=(const Iterator_t it) const
{
return pBlockHeader != it.pBlockHeader || nIndex != it.nIndex;
}
BlockHeader_t* pBlockHeader;
std::intptr_t nIndex;
};
CUtlFixedMemory(const int nGrowSize = 0, const int nInitAllocationCount = 0) :
pBlocks(nullptr), nAllocationCount(0), nGrowSize(nGrowSize)
{
Purge();
Grow(nInitAllocationCount);
}
~CUtlFixedMemory()
{
Purge();
}
CS_CLASS_NO_ASSIGNMENT(CUtlFixedMemory)
[[nodiscard]] T* Base()
{
return nullptr;
}
[[nodiscard]] const T* Base() const
{
return nullptr;
}
T& operator[](std::intptr_t nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return *reinterpret_cast<T*>(nIndex);
}
const T& operator[](std::intptr_t nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return *reinterpret_cast<T*>(nIndex);
}
[[nodiscard]] T& Element(const std::intptr_t nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return *reinterpret_cast<T*>(nIndex);
}
[[nodiscard]] const T& Element(const std::intptr_t nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return *reinterpret_cast<T*>(nIndex);
}
[[nodiscard]] Iterator_t First() const
{
return (pBlocks != nullptr ? Iterator_t(pBlocks, InvalidIndex()) : InvalidIterator());
}
[[nodiscard]] Iterator_t Next(const Iterator_t& it) const
{
if (!IsValidIterator(it))
return InvalidIterator();
BlockHeader_t* pHeader = it.pBlockHeader;
if (it.nIndex + 1 < pHeader->nBlockSize)
return Iterator_t(pHeader, it.nIndex + 1);
return (pHeader->pNext != nullptr ? Iterator_t(pHeader->pNext, InvalidIndex()) : InvalidIterator());
}
[[nodiscard]] std::intptr_t GetIndex(const Iterator_t& it) const
{
if (!IsValidIterator(it))
return InvalidIndex();
return reinterpret_cast<std::intptr_t>(HeaderToBlock(it.pBlockHeader) + it.nIndex);
}
[[nodiscard]] bool IsIndexAfter(std::intptr_t nIndex, const Iterator_t& it) const
{
if (!IsValidIterator(it))
return false;
if (IsInBlock(nIndex, it.pBlockHeader))
return nIndex > GetIndex(it);
for (BlockHeader_t* pBlockHeader = it.pBlockHeader->pNext; pBlockHeader != nullptr; pBlockHeader = pBlockHeader->pNext)
{
if (IsInBlock(nIndex, pBlockHeader))
return true;
}
return false;
}
[[nodiscard]] bool IsValidIterator(const Iterator_t& it) const
{
return it.pBlockHeader != nullptr && it.nIndex >= 0 && it.nIndex < it.pBlockHeader->nBlockSize;
}
[[nodiscard]] Iterator_t InvalidIterator() const
{
return Iterator_t(nullptr, InvalidIndex());
}
[[nodiscard]] bool IsValidIndex(const std::intptr_t nIndex) const
{
return nIndex != InvalidIndex();
}
[[nodiscard]] static std::intptr_t InvalidIndex()
{
return 0;
}
[[nodiscard]] int Count() const
{
return nAllocationCount;
}
void EnsureCapacity(const int nCapacity)
{
Grow(nCapacity - Count());
}
void Grow(const int nCount = 1)
{
if (nCount <= 0)
return;
int nBlockSize = (nGrowSize == 0 ? (nAllocationCount > 0 ? nAllocationCount : (31 + sizeof(T)) / sizeof(T)) : nGrowSize);
if (nBlockSize < nCount)
nBlockSize *= (nCount + nBlockSize - 1) / nBlockSize;
nAllocationCount += nBlockSize;
BlockHeader_t* pNewBlockHeader = static_cast<BlockHeader_t*>(I::MemAlloc->Alloc(sizeof(BlockHeader_t) + nBlockSize * sizeof(T)));
CS_ASSERT(pNewBlockHeader != nullptr); // container overflow
pNewBlockHeader->pNext = nullptr;
pNewBlockHeader->nBlockSize = nBlockSize;
if (pBlocks == nullptr)
pBlocks = pNewBlockHeader;
else
{
BlockHeader_t* pBlockHeader = pBlocks;
while (pBlockHeader->pNext != nullptr)
pBlockHeader = pBlockHeader->pNext;
pBlockHeader->pNext = pNewBlockHeader;
}
}
void Purge()
{
if (pBlocks == nullptr)
return;
for (BlockHeader_t* pBlockHeader = pBlocks; pBlockHeader != nullptr;)
{
BlockHeader_t* pFree = pBlockHeader;
pBlockHeader = pBlockHeader->pNext;
I::MemAlloc->Free(pFree);
}
pBlocks = nullptr;
nAllocationCount = 0;
}
protected:
[[nodiscard]] bool IsInBlock(std::intptr_t nIndex, BlockHeader_t* pBlockHeader) const
{
T* pCurrent = reinterpret_cast<T*>(nIndex);
const T* pStart = HeaderToBlock(pBlockHeader);
const T* pEnd = pStart + pBlockHeader->nBlockSize;
return (pCurrent >= pStart && pCurrent < pEnd);
}
[[nodiscard]] const T* HeaderToBlock(const BlockHeader_t* pHeader) const
{
return reinterpret_cast<const T*>(pHeader + 1);
}
[[nodiscard]] const BlockHeader_t* BlockToHeader(const T* pBlock) const
{
return reinterpret_cast<const BlockHeader_t*>(pBlock) - 1;
}
BlockHeader_t* pBlocks;
int nAllocationCount;
int nGrowSize;
};

View File

@@ -0,0 +1,347 @@
#pragma once
#include "utlmemory.h"
#include "utlfixedmemory.h"
// @source: master/public/tier1/utllinkedlist.h
template <class T, class I>
struct UtlLinkedListElement_t
{
UtlLinkedListElement_t(const UtlLinkedListElement_t&) = delete;
T element;
I iPrevious;
I iNext;
};
template <class T, class S = unsigned short, bool ML = false, class I = S, class M = CUtlMemory<UtlLinkedListElement_t<T, S>, I>>
class CUtlLinkedList
{
public:
using ElemType_t = T;
using IndexType_t = S;
using IndexLocalType_t = I;
using MemoryAllocator_t = M;
template <typename List_t>
class ConstIterator_t
{
public:
typedef typename List_t::ElemType_t ElemType_t;
typedef typename List_t::IndexType_t IndexType_t;
ConstIterator_t() :
pList(nullptr), nIndex(List_t::InvalidIndex()) { }
ConstIterator_t(const List_t& list, IndexType_t nIndex) :
pList(&list), nIndex(nIndex) { }
ConstIterator_t& operator++()
{
nIndex = pList->Next(nIndex);
return *this;
}
ConstIterator_t operator++(int)
{
ConstIterator_t pCopy = *this;
++(*this);
return pCopy;
}
ConstIterator_t& operator--()
{
CS_ASSERT(nIndex != pList->Head());
nIndex = (nIndex == pList->InvalidIndex() ? pList->Tail() : pList->Previous(nIndex));
return *this;
}
ConstIterator_t operator--(int)
{
ConstIterator_t pCopy = *this;
--(*this);
return pCopy;
}
bool operator==(const ConstIterator_t& other) const
{
CS_ASSERT(pList == other.pList);
return nIndex == other.nIndex;
}
bool operator!=(const ConstIterator_t& other) const
{
CS_ASSERT(pList == other.pList);
return nIndex != other.nIndex;
}
const ElemType_t& operator*() const
{
return pList->Element(nIndex);
}
const ElemType_t* operator->() const
{
return (&**this);
}
protected:
const List_t* pList;
IndexType_t nIndex;
};
template <typename List_t>
class Iterator_t : public ConstIterator_t<List_t>
{
public:
using ElemType_t = typename List_t::ElemType_t;
using IndexType_t = typename List_t::IndexType_t;
using Base_t = ConstIterator_t<List_t>;
Iterator_t() { }
Iterator_t(const List_t& list, IndexType_t nIndex) :
ConstIterator_t<List_t>(list, nIndex) { }
Iterator_t& operator++()
{
Base_t::nIndex = Base_t::pList->Next(Base_t::nIndex);
return *this;
}
Iterator_t operator++(int)
{
Iterator_t pCopy = *this;
++(*this);
return pCopy;
}
Iterator_t& operator--()
{
Base_t::nIndex = (Base_t::nIndex == Base_t::pList->InvalidIndex() ? Base_t::pList->Tail() : Base_t::pList->Previous(Base_t::nIndex));
return *this;
}
Iterator_t operator--(int)
{
Iterator_t pCopy = *this;
--(*this);
return pCopy;
}
ElemType_t& operator*() const
{
List_t* pMutableList = const_cast<List_t*>(Base_t::pList);
return pMutableList->Element(Base_t::nIndex);
}
ElemType_t* operator->() const
{
return (&**this);
}
};
CUtlLinkedList(int nGrowSize = 0, int nSize = 0) :
memory(nGrowSize, nSize), iHead(InvalidIndex()), iTail(InvalidIndex()), iFirstFree(InvalidIndex()), nElementCount(0), nAllocated(0), itLastAlloc(memory.InvalidIterator()), pElements(memory.Base()) { }
~CUtlLinkedList()
{
RemoveAll();
}
CUtlLinkedList(const CUtlLinkedList&) = delete;
CUtlLinkedList& operator=(const CUtlLinkedList&) = delete;
T& operator[](const I nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].element;
}
const T& operator[](const I nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].element;
}
[[nodiscard]] T& Element(const I nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].element;
}
[[nodiscard]] const T& Element(const I nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].element;
}
[[nodiscard]] I Head() const
{
return iHead;
}
[[nodiscard]] I Tail() const
{
return iTail;
}
[[nodiscard]] I Previous(const I nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return InternalElement(nIndex).iPrevious;
}
[[nodiscard]] I Next(const I nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return InternalElement(nIndex).iNext;
}
[[nodiscard]] static S InvalidIndex()
{
return static_cast<S>(M::InvalidIndex());
}
[[nodiscard]] bool IsValidIndex(const I nIndex) const
{
if (!memory.IsValidIndex(nIndex))
return false;
if (memory.IsIndexAfter(nIndex, itLastAlloc))
return false; // don't read values that have been allocated, but not constructed
return (memory[nIndex].iPrevious != nIndex) || (memory[nIndex].iNext == nIndex);
}
[[nodiscard]] static bool IsIndexInRange(I nIndex)
{
static_assert(sizeof(I) >= sizeof(S));
static_assert(sizeof(S) > 2 || static_cast<S>(-1) > 0);
static_assert(M::InvalidIndex() == -1 || M::InvalidIndex() == static_cast<S>(M::InvalidIndex()));
return (static_cast<S>(nIndex) == nIndex && static_cast<S>(nIndex) != InvalidIndex());
}
[[nodiscard]] I Find(const T& source) const
{
for (I i = iHead; i != InvalidIndex(); i = Next(i))
{
if (Element(i) == source)
return i;
}
return InvalidIndex();
}
void RemoveAll()
{
if (itLastAlloc == memory.InvalidIterator())
{
CS_ASSERT(iHead == InvalidIndex() && iTail == InvalidIndex() && iFirstFree == InvalidIndex() && nElementCount == 0);
return;
}
if constexpr (ML)
{
for (typename M::Iterator_t it = memory.First(); it != memory.InvalidIterator(); it = memory.Next(it))
{
I i = memory.GetIndex(it);
// skip elements already in the free list
if (IsValidIndex(i))
{
ListElement_t& internalElement = InternalElement(i);
(&internalElement.element)->~T();
internalElement.iPrevious = i;
internalElement.iNext = iFirstFree;
iFirstFree = i;
}
// don't destruct elements that haven't ever been constructed
if (it == itLastAlloc)
break;
}
}
else
{
I i = iHead, iNext;
while (i != InvalidIndex())
{
ListElement_t& internalElement = InternalElement(i);
(&internalElement.element)->~T();
internalElement.iPrevious = i;
iNext = Next(i);
internalElement.iNext = iNext == InvalidIndex() ? iFirstFree : iNext;
i = iNext;
}
if (iHead != InvalidIndex())
iFirstFree = iHead;
}
// clear everything else out
iHead = InvalidIndex();
iTail = InvalidIndex();
nElementCount = 0;
}
[[nodiscard]] auto begin() const
{
return ConstIterator_t<CUtlLinkedList<T, S, ML, I, M>>(*this, Head());
}
[[nodiscard]] auto begin()
{
return Iterator_t<CUtlLinkedList<T, S, ML, I, M>>(*this, Head());
}
[[nodiscard]] auto end() const
{
return ConstIterator_t<CUtlLinkedList<T, S, ML, I, M>>(*this, InvalidIndex());
}
[[nodiscard]] auto end()
{
return Iterator_t<CUtlLinkedList<T, S, ML, I, M>>(*this, InvalidIndex());
}
protected:
using ListElement_t = UtlLinkedListElement_t<T, S>;
[[nodiscard]] ListElement_t& InternalElement(const I nIndex)
{
return memory[nIndex];
}
[[nodiscard]] const ListElement_t& InternalElement(const I nIndex) const
{
return memory[nIndex];
}
M memory;
I iHead;
I iTail;
I iFirstFree;
I nElementCount;
I nAllocated;
typename M::Iterator_t itLastAlloc;
ListElement_t* pElements;
};
template <class T>
class CUtlFixedLinkedList : public CUtlLinkedList<T, std::intptr_t, true, std::intptr_t, CUtlFixedMemory<UtlLinkedListElement_t<T, std::intptr_t>>>
{
public:
CUtlFixedLinkedList(int nGrowSize = 0, int nInitAllocationCount = 0) :
CUtlLinkedList<T, std::intptr_t, true, std::intptr_t, CUtlFixedMemory<UtlLinkedListElement_t<T, std::intptr_t>>>(nGrowSize, nInitAllocationCount) { }
[[nodiscard]] bool IsValidIndex(std::intptr_t nIndex) const
{
if (!this->memory.IsIndexValid(nIndex))
return false;
return (this->memory[nIndex].iPrevious != nIndex) || (this->memory[nIndex].iNext == nIndex);
}
};

View File

@@ -0,0 +1,135 @@
#pragma once
#include "utlrbtree.h"
// @source: master/public/tier1/utlmap.h
template <typename K, typename T, typename I = unsigned short, typename LessCallbackFn_t = bool(CS_CDECL*)(const K&, const K&)>
class CUtlMap
{
public:
using KeyType_t = K;
using ElementType_t = T;
using IndexType_t = I;
CUtlMap(int nGrowSize = 0, int nInitialSize = 0, const LessCallbackFn_t& fnLessCallback = nullptr) :
tree(nGrowSize, nInitialSize, CKeyLess(fnLessCallback)) { }
CUtlMap(LessCallbackFn_t fnLessCallback) :
tree(CKeyLess(fnLessCallback)) { }
[[nodiscard]] ElementType_t& operator[](IndexType_t nIndex)
{
return tree.Element(nIndex).nElement;
}
[[nodiscard]] const ElementType_t& operator[](IndexType_t nIndex) const
{
return tree.Element(nIndex).nElement;
}
[[nodiscard]] ElementType_t& Element(IndexType_t nIndex)
{
return tree.Element(nIndex).nElement;
}
[[nodiscard]] const ElementType_t& Element(IndexType_t nIndex) const
{
return tree.Element(nIndex).nElement;
}
[[nodiscard]] KeyType_t& Key(IndexType_t nIndex)
{
return tree.Element(nIndex).key;
}
[[nodiscard]] const KeyType_t& Key(IndexType_t nIndex) const
{
return tree.Element(nIndex).key;
}
[[nodiscard]] unsigned int Count() const
{
return tree.Count();
}
[[nodiscard]] IndexType_t MaxElement() const
{
return tree.MaxElement();
}
[[nodiscard]] bool IsValidIndex(IndexType_t nIndex) const
{
return tree.IsValidIndex(nIndex);
}
[[nodiscard]] bool IsValid() const
{
return tree.IsValid();
}
[[nodiscard]] static IndexType_t InvalidIndex()
{
return CUtlRBTree<Node_t, I, CKeyLess>::InvalidIndex();
}
void EnsureCapacity(const int nCapacity)
{
tree.EnsureCapacity(nCapacity);
}
[[nodiscard]] IndexType_t Find(const KeyType_t& key) const
{
Node_t dummyNode;
dummyNode.key = key;
return tree.Find(dummyNode);
}
void RemoveAt(IndexType_t nIndex)
{
tree.RemoveAt(nIndex);
}
bool Remove(const KeyType_t& key)
{
Node_t dummyNode = { key };
return tree.Remove(dummyNode);
}
void RemoveAll()
{
tree.RemoveAll();
}
void Purge()
{
tree.Purge();
}
struct Node_t
{
KeyType_t key;
ElementType_t nElement;
};
class CKeyLess
{
public:
CKeyLess(const LessCallbackFn_t& fnLessCallback) :
fnLessCallback(fnLessCallback) { }
bool operator!() const
{
return !fnLessCallback;
}
bool operator()(const Node_t& left, const Node_t& right) const
{
return fnLessCallback(left.key, right.key);
}
LessCallbackFn_t fnLessCallback;
};
protected:
CUtlRBTree<Node_t, I, CKeyLess> tree; // 0x00
};

View File

@@ -0,0 +1,516 @@
#pragma once
// used: memorycopy
#include "../../utilities/crt.h"
// @test: using interfaces in the header | not critical but could blow up someday with thousands of errors or affect to compilation time etc
// used: interface handles
#include "../../core/interfaces.h"
// used: interface declarations
#include "../interfaces/imemalloc.h"
// @source: master/public/tier1/utlmemory.h
template <class T, class N = int>
class CUtlMemory
{
enum
{
EXTERNAL_BUFFER_MARKER = -1,
EXTERNAL_CONST_BUFFER_MARKER = -2,
};
public:
class Iterator_t
{
public:
Iterator_t(const N nIndex) :
nIndex(nIndex) { }
bool operator==(const Iterator_t it) const
{
return nIndex == it.nIndex;
}
bool operator!=(const Iterator_t it) const
{
return nIndex != it.nIndex;
}
N nIndex;
};
CUtlMemory(const int nInitialGrowSize, const int nAllocationCount) :
pMemory(nullptr), nAllocationCount(nAllocationCount), nGrowSize(nInitialGrowSize)
{
CS_ASSERT(nInitialGrowSize >= 0);
if (nAllocationCount > 0)
pMemory = static_cast<T*>(I::MemAlloc->Alloc(nAllocationCount * sizeof(T)));
}
CUtlMemory(T* pMemory, const int nElements) :
pMemory(pMemory), nAllocationCount(nElements), nGrowSize(EXTERNAL_BUFFER_MARKER) { }
CUtlMemory(const T* pMemory, const int nElements) :
pMemory(pMemory), nAllocationCount(nElements), nGrowSize(EXTERNAL_CONST_BUFFER_MARKER) { }
~CUtlMemory()
{
Purge();
}
CUtlMemory(const CUtlMemory&) = delete;
CUtlMemory(CUtlMemory&& moveFrom) noexcept :
pMemory(moveFrom.pMemory), nAllocationCount(moveFrom.nAllocationCount), nGrowSize(moveFrom.nGrowSize)
{
moveFrom.pMemory = nullptr;
moveFrom.nAllocationCount = 0;
moveFrom.nGrowSize = 0;
}
void* operator new(const std::size_t nSize)
{
return I::MemAlloc->Alloc(nSize);
}
void operator delete(void* pMemory)
{
I::MemAlloc->Free(pMemory);
}
CUtlMemory& operator=(const CUtlMemory&) = delete;
CUtlMemory& operator=(CUtlMemory&& moveFrom) noexcept
{
// copy member variables to locals before purge to handle self-assignment
T* pMemoryTemp = moveFrom.pMemory;
const int nAllocationCountTemp = moveFrom.nAllocationCount;
const int nGrowSizeTemp = moveFrom.nGrowSize;
moveFrom.pMemory = nullptr;
moveFrom.nAllocationCount = 0;
moveFrom.nGrowSize = 0;
// if this is a self-assignment, Purge() is a no-op here
Purge();
pMemory = pMemoryTemp;
nAllocationCount = nAllocationCountTemp;
nGrowSize = nGrowSizeTemp;
return *this;
}
[[nodiscard]] T& operator[](const N nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return pMemory[nIndex];
}
[[nodiscard]] const T& operator[](const N nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return pMemory[nIndex];
}
[[nodiscard]] T& Element(const N nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return pMemory[nIndex];
}
[[nodiscard]] const T& Element(const N nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return pMemory[nIndex];
}
[[nodiscard]] T* Base()
{
return pMemory;
}
[[nodiscard]] const T* Base() const
{
return pMemory;
}
[[nodiscard]] int AllocationCount() const
{
return nAllocationCount;
}
[[nodiscard]] bool IsExternallyAllocated() const
{
return nGrowSize <= EXTERNAL_BUFFER_MARKER;
}
[[nodiscard]] static N InvalidIndex()
{
return static_cast<N>(-1);
}
[[nodiscard]] bool IsValidIndex(N nIndex) const
{
return (nIndex >= 0) && (nIndex < nAllocationCount);
}
[[nodiscard]] Iterator_t First() const
{
return Iterator_t(IsValidIndex(0) ? 0 : InvalidIndex());
}
[[nodiscard]] Iterator_t Next(const Iterator_t& it) const
{
return Iterator_t(IsValidIndex(it.nIndex + 1) ? it.nIndex + 1 : InvalidIndex());
}
[[nodiscard]] N GetIndex(const Iterator_t& it) const
{
return it.nIndex;
}
[[nodiscard]] bool IsIndexAfter(N nIndex, const Iterator_t& it) const
{
return nIndex > it.nIndex;
}
[[nodiscard]] bool IsValidIterator(const Iterator_t& it) const
{
return IsValidIndex(it.index);
}
[[nodiscard]] Iterator_t InvalidIterator() const
{
return Iterator_t(InvalidIndex());
}
void Grow(const int nCount = 1)
{
if (IsExternallyAllocated())
return;
int nAllocationRequested = nAllocationCount + nCount;
int nNewAllocationCount = 0;
if (nGrowSize)
nAllocationCount = ((1 + ((nAllocationRequested - 1) / nGrowSize)) * nGrowSize);
else
{
if (nAllocationCount == 0)
nAllocationCount = (31 + sizeof(T)) / sizeof(T);
while (nAllocationCount < nAllocationRequested)
nAllocationCount <<= 1;
}
if (static_cast<int>(static_cast<N>(nNewAllocationCount)) < nAllocationRequested)
{
if (static_cast<int>(static_cast<N>(nNewAllocationCount)) == 0 && static_cast<int>(static_cast<N>(nNewAllocationCount - 1)) >= nAllocationRequested)
--nNewAllocationCount;
else
{
if (static_cast<int>(static_cast<N>(nAllocationRequested)) != nAllocationRequested)
return;
while (static_cast<int>(static_cast<N>(nNewAllocationCount)) < nAllocationRequested)
nNewAllocationCount = (nNewAllocationCount + nAllocationRequested) / 2;
}
}
nAllocationCount = nNewAllocationCount;
// @test: we can always call realloc, since it must allocate instead when passed null ptr
if (pMemory != nullptr)
pMemory = static_cast<T*>(I::MemAlloc->ReAlloc(pMemory, nAllocationCount * sizeof(T)));
else
pMemory = static_cast<T*>(I::MemAlloc->Alloc(nAllocationCount * sizeof(T)));
}
void EnsureCapacity(const int nCapacity)
{
if (nAllocationCount >= nCapacity)
return;
if (IsExternallyAllocated())
{
// can't grow a buffer whose memory was externally allocated
CS_ASSERT(false);
return;
}
nAllocationCount = nCapacity;
// @test: we can always call realloc, since it must allocate instead when passed null ptr
if (pMemory != nullptr)
pMemory = static_cast<T*>(I::MemAlloc->ReAlloc(pMemory, nAllocationCount * sizeof(T)));
else
pMemory = static_cast<T*>(I::MemAlloc->Alloc(nAllocationCount * sizeof(T)));
}
void ConvertToGrowableMemory(int nInitialGrowSize)
{
if (!IsExternallyAllocated())
return;
nGrowSize = nInitialGrowSize;
if (nAllocationCount > 0)
{
const int nByteCount = nAllocationCount * sizeof(T);
T* pGrowableMemory = static_cast<T*>(I::MemAlloc->Alloc(nByteCount));
CRT::MemoryCopy(pGrowableMemory, pMemory, nByteCount);
pMemory = pGrowableMemory;
}
else
pMemory = nullptr;
}
void Purge()
{
if (IsExternallyAllocated())
return;
if (pMemory != nullptr)
{
I::MemAlloc->Free(static_cast<void*>(pMemory));
pMemory = nullptr;
}
nAllocationCount = 0;
}
void Purge(const int nElements)
{
CS_ASSERT(nElements >= 0);
if (nElements > nAllocationCount)
{
// ensure this isn't a grow request in disguise
CS_ASSERT(nElements <= nAllocationCount);
return;
}
if (nElements == 0)
{
Purge();
return;
}
if (IsExternallyAllocated() || nElements == nAllocationCount)
return;
if (pMemory == nullptr)
{
// allocation count is non zero, but memory is null
CS_ASSERT(false);
return;
}
nAllocationCount = nElements;
pMemory = static_cast<T*>(I::MemAlloc->ReAlloc(pMemory, nAllocationCount * sizeof(T)));
}
protected:
T* pMemory; // 0x00
int nAllocationCount; // 0x04
int nGrowSize; // 0x08
};
template <class T, int nAlignment>
class CUtlMemoryAligned : public CUtlMemory<T>
{
public:
// @note: not implemented
CS_CLASS_NO_INITIALIZER(CUtlMemoryAligned);
};
template <class T, std::size_t SIZE, class I = int>
class CUtlMemoryFixedGrowable : public CUtlMemory<T, I>
{
typedef CUtlMemory<T, I> BaseClass;
public:
CUtlMemoryFixedGrowable(int nInitialGrowSize = 0, int nInitialSize = SIZE) :
BaseClass(arrFixedMemory, SIZE)
{
CS_ASSERT(nInitialSize == 0 || nInitialSize == SIZE);
nMallocGrowSize = nInitialGrowSize;
}
void Grow(int nCount = 1)
{
if (this->IsExternallyAllocated())
this->ConvertToGrowableMemory(nMallocGrowSize);
BaseClass::Grow(nCount);
}
void EnsureCapacity(int nCapacity)
{
if (CUtlMemory<T>::nAllocationCount >= nCapacity)
return;
if (this->IsExternallyAllocated())
// can't grow a buffer whose memory was externally allocated
this->ConvertToGrowableMemory(nMallocGrowSize);
BaseClass::EnsureCapacity(nCapacity);
}
private:
int nMallocGrowSize;
T arrFixedMemory[SIZE];
};
template <typename T, std::size_t SIZE, int nAlignment = 0>
class CUtlMemoryFixed
{
public:
CUtlMemoryFixed(const int nGrowSize = 0, const int nInitialCapacity = 0)
{
CS_ASSERT(nInitialCapacity == 0 || nInitialCapacity == SIZE);
}
CUtlMemoryFixed(const T* pMemory, const int nElements)
{
CS_ASSERT(false);
}
[[nodiscard]] static constexpr bool IsValidIndex(const int nIndex)
{
return (nIndex >= 0) && (nIndex < SIZE);
}
// specify the invalid ('null') index that we'll only return on failure
static constexpr int INVALID_INDEX = -1;
[[nodiscard]] static constexpr int InvalidIndex()
{
return INVALID_INDEX;
}
[[nodiscard]] T* Base()
{
if (nAlignment == 0)
return reinterpret_cast<T*>(&pMemory[0]);
return reinterpret_cast<T*>((reinterpret_cast<std::uintptr_t>(&pMemory[0]) + nAlignment - 1) & ~(nAlignment - 1));
}
[[nodiscard]] const T* Base() const
{
if (nAlignment == 0)
return reinterpret_cast<T*>(&pMemory[0]);
return reinterpret_cast<T*>((reinterpret_cast<std::uintptr_t>(&pMemory[0]) + nAlignment - 1) & ~(nAlignment - 1));
}
[[nodiscard]] T& operator[](int nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] const T& operator[](int nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] T& Element(int nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] const T& Element(int nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] int AllocationCount() const
{
return SIZE;
}
[[nodiscard]] int Count() const
{
return SIZE;
}
void Grow(int nCount = 1)
{
CS_ASSERT(false);
}
void EnsureCapacity(const int nCapacity)
{
CS_ASSERT(nCapacity <= SIZE);
}
void Purge() { }
void Purge(const int nElements)
{
CS_ASSERT(false);
}
[[nodiscard]] bool IsExternallyAllocated() const
{
return false;
}
class Iterator_t
{
public:
Iterator_t(const int nIndex) :
nIndex(nIndex) { }
bool operator==(const Iterator_t it) const
{
return nIndex == it.nIndex;
}
bool operator!=(const Iterator_t it) const
{
return nIndex != it.nIndex;
}
int nIndex;
};
[[nodiscard]] Iterator_t First() const
{
return Iterator_t(IsValidIndex(0) ? 0 : InvalidIndex());
}
[[nodiscard]] Iterator_t Next(const Iterator_t& it) const
{
return Iterator_t(IsValidIndex(it.nIndex + 1) ? it.nIndex + 1 : InvalidIndex());
}
[[nodiscard]] int GetIndex(const Iterator_t& it) const
{
return it.nIndex;
}
[[nodiscard]] bool IsIndexAfter(int i, const Iterator_t& it) const
{
return i > it.nIndex;
}
[[nodiscard]] bool IsValidIterator(const Iterator_t& it) const
{
return IsValidIndex(it.nIndex);
}
[[nodiscard]] Iterator_t InvalidIterator() const
{
return Iterator_t(InvalidIndex());
}
private:
char pMemory[SIZE * sizeof(T) + nAlignment];
};

View File

@@ -0,0 +1,244 @@
#pragma once
#include "utlmemory.h"
// @source: master/public/tier1/utlrbtree.h
template <typename T>
class CDefLess
{
public:
CDefLess() { }
CDefLess(int) { }
CS_INLINE bool operator()(const T& left, const T& right) const
{
return (left < right);
}
CS_INLINE bool operator!() const
{
return false;
}
};
template <class I>
struct UtlRBTreeLinks_t
{
I iLeft;
I iRight;
I iParent;
I iTag;
};
template <class T, class I>
struct UtlRBTreeNode_t : public UtlRBTreeLinks_t<I>
{
T data;
};
template <class T, class I = unsigned short, typename L = bool(CS_CDECL*)(const T&, const T&), class M = CUtlMemory<UtlRBTreeNode_t<T, I>, I>>
class CUtlRBTree
{
public:
using KeyType_t = T;
using ElementType_t = T;
using IndexType_t = I;
using LessCallbackFn_t = L;
enum NodeColor_t
{
RED = 0,
BLACK
};
explicit CUtlRBTree(int nGrowSize = 0, int nInitialSize = 0, const LessCallbackFn_t& fnLessCallback = nullptr) :
fnLessCallback(fnLessCallback), memory(nGrowSize, nInitialSize), iRoot(InvalidIndex()), nElements(0), iFirstFree(InvalidIndex()), itLastAlloc(memory.InvalidIterator()), pElements(memory.Base()) { }
explicit CUtlRBTree(const LessCallbackFn_t& fnLessCallback) :
fnLessCallback(fnLessCallback), memory(0, 0), iRoot(InvalidIndex()), nElements(0), iFirstFree(InvalidIndex()), itLastAlloc(memory.InvalidIterator()), pElements(memory.Base()) { }
~CUtlRBTree()
{
Purge();
}
[[nodiscard]] T& operator[](I nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].data;
}
[[nodiscard]] const T& operator[](I nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].data;
}
[[nodiscard]] T& Element(I nIndex)
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].data;
}
[[nodiscard]] const T& Element(I nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex));
return memory[nIndex].data;
}
[[nodiscard]] const UtlRBTreeLinks_t<I>& Links(I nIndex) const
{
constexpr UtlRBTreeLinks_t<I> linksSentinel = {
M::INVALID_INDEX, M::INVALID_INDEX, M::INVALID_INDEX, BLACK
};
return (nIndex != InvalidIndex()) ? memory[nIndex] : linksSentinel;
}
[[nodiscard]] UtlRBTreeLinks_t<I>& Links(I nIndex)
{
CS_ASSERT(nIndex != InvalidIndex());
return memory[nIndex];
}
[[nodiscard]] I Parent(I nIndex) const
{
return (nIndex != InvalidIndex() ? memory[nIndex].iParent : InvalidIndex());
}
[[nodiscard]] I LeftChild(I nIndex) const
{
return (nIndex != InvalidIndex() ? memory[nIndex].iLeft : InvalidIndex());
}
[[nodiscard]] I RightChild(I nIndex) const
{
return (nIndex != InvalidIndex() ? memory[nIndex].iRight : InvalidIndex());
}
void SetParent(I nIndex, I iParent)
{
Links(nIndex).iParent = iParent;
}
void SetLeftChild(I nIndex, I iChild)
{
Links(nIndex).iLeft = iChild;
}
void SetRightChild(I nIndex, I iChild)
{
Links(nIndex).iRight = iChild;
}
[[nodiscard]] bool IsRoot(I nIndex) const
{
return nIndex == iRoot;
}
[[nodiscard]] bool IsLeaf(I nIndex) const
{
return (LeftChild(nIndex) == InvalidIndex()) && (RightChild(nIndex) == InvalidIndex());
}
[[nodiscard]] unsigned int Count() const
{
return nElements;
}
[[nodiscard]] I MaxElement() const
{
return static_cast<I>(memory.NumAllocated());
}
[[nodiscard]] bool IsValidIndex(I nIndex) const
{
if (!memory.IsValidIndex(nIndex))
return false;
// don't read values that have been allocated, but not constructed
if (memory.IsIndexAfter(nIndex, itLastAlloc))
return false;
return LeftChild(nIndex) != nIndex;
}
[[nodiscard]] static I InvalidIndex()
{
return static_cast<I>(M::InvalidIndex());
}
void EnsureCapacity(const int nCapacity)
{
memory.EnsureCapacity(nCapacity);
}
[[nodiscard]] I Find(const T& search) const
{
CS_ASSERT(!!fnLessCallback);
I iCurrent = iRoot;
while (iCurrent != InvalidIndex())
{
if (fnLessCallback(search, Element(iCurrent)))
iCurrent = LeftChild(iCurrent);
else if (fnLessCallback(Element(iCurrent), search))
iCurrent = RightChild(iCurrent);
else
break;
}
return iCurrent;
}
void RemoveAll()
{
if (itLastAlloc == memory.InvalidIterator())
{
CS_ASSERT(iRoot == InvalidIndex());
CS_ASSERT(iFirstFree == InvalidIndex());
CS_ASSERT(nElements == 0);
return;
}
for (typename M::Iterator_t it = memory.First(); it != memory.InvalidIterator(); it = memory.Next(it))
{
// skip elements in the free list
if (I nIndex = memory.GetIndex(it); IsValidIndex(nIndex))
{
(&Element(nIndex))->~T();
SetRightChild(nIndex, iFirstFree);
SetLeftChild(nIndex, nIndex);
iFirstFree = nIndex;
}
// don't destruct elements that haven't ever been constucted
if (it == itLastAlloc)
break;
}
// clear everything else out
iRoot = InvalidIndex();
nElements = 0;
//CS_ASSERT(IsValid());
}
void Purge()
{
RemoveAll();
iFirstFree = InvalidIndex();
memory.Purge();
itLastAlloc = memory.InvalidIterator();
}
public:
LessCallbackFn_t fnLessCallback; // 0x00
M memory; // 0x04
I iRoot; // 0x10
I nElements;
I iFirstFree;
typename M::Iterator_t itLastAlloc;
UtlRBTreeNode_t<T, I>* pElements;
};

View File

@@ -0,0 +1,63 @@
#pragma once
#include "utlmemory.h"
class CUtlBinaryBlock
{
public:
CUtlBinaryBlock(const int nInitialGrowSize = 0, const int nInitialSize = 0) :
memory(nInitialGrowSize, nInitialSize), nLength(0) { }
CUtlMemory<unsigned char> memory;
int nLength;
};
class CUtlString
{
public:
CUtlString() { }
[[nodiscard]] const char* Get() const
{
if (storage.nLength == 0)
return "";
return reinterpret_cast<const char*>(storage.memory.Base());
}
[[nodiscard]] int Length() const
{
return storage.nLength;
}
private:
CUtlBinaryBlock storage;
};
template <typename T = char>
class CUtlConstStringBase
{
public:
CUtlConstStringBase() :
pString(nullptr) { }
[[nodiscard]] const T* Get() const
{
return (pString != nullptr ? pString : static_cast<T*>(""));
}
[[nodiscard]] operator const T*() const
{
return (pString != nullptr ? pString : static_cast<T*>(""));
}
[[nodiscard]] bool Empty() const
{
return (pString == nullptr);
}
protected:
const T* pString;
};
using CUtlConstString = CUtlConstStringBase<char>;
using CUtlConstWideString = CUtlConstStringBase<wchar_t>;

View File

@@ -0,0 +1,196 @@
#pragma once
#include <cstdint>
#include <limits>
#include <cstdint>
class CUtlMemoryPool
{
public:
int Count() const
{
return nBlocksAllocated;
}
int PeakCount() const
{
return nPeakAlloc;
}
int BlockSize() const
{
return nBlockSize;
}
protected:
class CBlob
{
public:
CBlob* pPrev;
CBlob* pNext;
int nNumBytes;
char Data[1];
char Padding[3];
};
int nBlockSize;
int nBlocksPerBlob;
int nGrowMode;
int nBlocksAllocated;
int nPeakAlloc;
unsigned short nAlignment;
unsigned short nNumBlobs;
void* pHeadOfFreeList;
void* pAllocOwner;
CBlob BlobHead;
};
using UtlTSHashHandle_t = std::uintptr_t;
inline unsigned HashIntConventional(const int n)
{
unsigned hash = 0xAAAAAAAA + (n & 0xFF);
hash = (hash << 5) + hash + ((n >> 8) & 0xFF);
hash = (hash << 5) + hash + ((n >> 16) & 0xFF);
hash = (hash << 5) + hash + ((n >> 24) & 0xFF);
return hash;
}
template <int nBucketCount, class tKey = std::uintptr_t>
class CUtlTSHashGenericHash
{
public:
static int Hash(const tKey& Key, int nBucketMask)
{
int nHash = HashIntConventional(std::uintptr_t(Key));
if (nBucketCount <= UINT16_MAX)
{
nHash ^= (nHash >> 16);
}
if (nBucketCount <= UINT8_MAX)
{
nHash ^= (nHash >> 8);
}
return (nHash & nBucketMask);
}
static bool Compare(const tKey& lhs, const tKey& rhs)
{
return lhs == rhs;
}
};
template <class tElement, int nBucketCount, class tKey = std::uintptr_t, class tHashFuncs = CUtlTSHashGenericHash<nBucketCount, tKey>, int nAlignment = 0>
class CUtlTSHash
{
static constexpr int nBucketMask = nBucketCount - 1;
public:
static constexpr UtlTSHashHandle_t InvalidHandle()
{
return static_cast<UtlTSHashHandle_t>(0);
}
UtlTSHashHandle_t Find(tKey uiKey)
{
int iBucket = tHashFuncs::Hash(uiKey, nBucketCount);
const HashBucket_t& hashBucket = aBuckets[iBucket];
const UtlTSHashHandle_t hHash = Find(uiKey, hashBucket.pFirst, nullptr);
return hHash ? hHash : Find(uiKey, hashBucket.pFirstUncommited, hashBucket.pFirst);
}
int Count() const
{
return EntryMemory.Count();
}
int GetElements(int nFirstElement, int nCount, UtlTSHashHandle_t* pHandles) const
{
int nIndex = 0;
for (int nBucketIndex = 0; nBucketIndex < nBucketCount; nBucketIndex++)
{
const HashBucket_t& hashBucket = aBuckets[nBucketIndex];
HashFixedData_t* pElement = hashBucket.pFirstUncommited;
for (; pElement; pElement = pElement->pNext)
{
if (--nFirstElement >= 0)
continue;
pHandles[nIndex++] = reinterpret_cast<UtlTSHashHandle_t>(pElement);
if (nIndex >= nCount)
return nIndex;
}
}
return nIndex;
}
tElement Element(UtlTSHashHandle_t hHash)
{
return ((HashFixedData_t*)(hHash))->Data;
}
const tElement& Element(UtlTSHashHandle_t hHash) const
{
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
}
tElement& operator[](UtlTSHashHandle_t hHash)
{
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
}
const tElement& operator[](UtlTSHashHandle_t hHash) const
{
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
}
tKey GetID(UtlTSHashHandle_t hHash) const
{
return reinterpret_cast<HashFixedData_t*>(hHash)->uiKey;
}
private:
template <typename tData>
struct HashFixedDataInternal_t
{
tKey uiKey;
HashFixedDataInternal_t<tData>* pNext;
tData Data;
};
using HashFixedData_t = HashFixedDataInternal_t<tElement>;
struct HashBucket_t
{
private:
[[maybe_unused]] std::byte pad0[0x18];
public:
HashFixedData_t* pFirst;
HashFixedData_t* pFirstUncommited;
};
UtlTSHashHandle_t Find(tKey uiKey, HashFixedData_t* pFirstElement, HashFixedData_t* pLastElement)
{
for (HashFixedData_t* pElement = pFirstElement; pElement != pLastElement; pElement = pElement->pNext)
{
if (tHashFuncs::Compare(pElement->uiKey, uiKey))
return reinterpret_cast<UtlTSHashHandle_t>(pElement);
}
return InvalidHandle();
}
CUtlMemoryPool EntryMemory;
MEM_PAD(0x40);
HashBucket_t aBuckets[nBucketCount];
bool bNeedsCommit;
};

View File

@@ -0,0 +1,346 @@
#pragma once
#include "utlmemory.h"
// used: memorymove
#include "../../utilities/crt.h"
// @source: master/public/tier1/utlvector.h
/*
* a growable array class which doubles in size by default.
* it will always keep all elements consecutive in memory, and may move the
* elements around in memory (via a realloc) when elements are inserted or removed.
* clients should therefore refer to the elements of the vector by index and not pointers
*
* @note: if variable that uses it intend to call any method that needs to allocate/deallocate should have overloaded constructor/destructor and/or new/delete operators respectively
*/
template <class T, class A = CUtlMemory<T>>
class CUtlVector
{
using CAllocator = A;
public:
explicit CUtlVector(const int nGrowSize = 0, const int nInitialCapacity = 0) :
memory(nGrowSize, nInitialCapacity), nSize(0), pElements(memory.Base()) { }
CUtlVector(T* pMemory, const int nInitialCapacity, const int nInitialCount = 0) :
memory(pMemory, nInitialCapacity), nSize(nInitialCount), pElements(memory.Base()) { }
CUtlVector(const CUtlVector&) = delete;
~CUtlVector()
{
Purge();
}
CUtlVector& operator=(const CUtlVector& vecOther)
{
CS_ASSERT(&vecOther != this); // self-assignment isn't allowed
const int nSourceCount = vecOther.Count();
SetCount(nSourceCount);
for (int i = 0; i < nSourceCount; i++)
(*this)[i] = vecOther[i];
return *this;
}
[[nodiscard]] T& operator[](const int nIndex)
{
CS_ASSERT(IsValidIndex(nIndex)); // given index is out of range
return memory[nIndex];
}
[[nodiscard]] const T& operator[](const int nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex)); // given index is out of range
return memory[nIndex];
}
[[nodiscard]] T& Element(const int nIndex)
{
CS_ASSERT(IsValidIndex(nIndex)); // given index is out of range
return memory[nIndex];
}
[[nodiscard]] const T& Element(const int nIndex) const
{
CS_ASSERT(IsValidIndex(nIndex)); // given index is out of range
return memory[nIndex];
}
[[nodiscard]] T* Base()
{
return memory.Base();
}
[[nodiscard]] const T* Base() const
{
return memory.Base();
}
[[nodiscard]] int Count() const
{
return nSize;
}
[[nodiscard]] int& Size()
{
return nSize;
}
[[nodiscard]] bool IsValidIndex(const int nIndex) const
{
return (nIndex >= 0) && (nIndex < nSize);
}
void CopyFromArray(const T* pArraySource, int nArraySize)
{
// can't insert something that's in the list. reallocation may hose us
CS_ASSERT(memory.Base() == nullptr || pArraySource == nullptr || begin() >= (pArraySource + nArraySize) || pArraySource >= end());
// resize to accommodate array
SetCount(nArraySize);
for (int i = 0; i < nArraySize; i++)
(*this)[i] = pArraySource[i];
}
void GrowVector(const int nCount = 1)
{
if (nSize + nCount > memory.AllocationCount())
memory.Grow(nSize + nCount - memory.AllocationCount());
nSize += nCount;
pElements = memory.Base();
}
void EnsureCapacity(int nCapacity)
{
memory.EnsureCapacity(nCapacity);
pElements = memory.Base();
}
void Purge()
{
RemoveAll();
memory.Purge();
pElements = memory.Base();
}
void ShiftElementsRight(const int nElement, const int nShift = 1)
{
CS_ASSERT(IsValidIndex(nElement) || nSize == 0 || nShift == 0);
if (const int nToMove = nSize - nElement - nShift; nToMove > 0 && nShift > 0)
CRT::MemoryMove(&Element(nElement + nShift), &Element(nElement), nToMove * sizeof(T));
}
void ShiftElementsLeft(const int nElement, const int nShift = 1)
{
CS_ASSERT(IsValidIndex(nElement) || nSize == 0 || nShift == 0);
if (const int nToMove = nSize - nElement - nShift; nToMove > 0 && nShift > 0)
CRT::MemoryMove(&Element(nElement), &Element(nElement + nShift), nToMove * sizeof(T));
}
int AddToHead()
{
return InsertBefore(0);
}
int AddToHead(const T& source)
{
// can't insert something that's in the list. reallocation may hose us
CS_ASSERT(memory.Base() == nullptr || &source < begin() || &source >= end());
return InsertBefore(0, source);
}
int AddMultipleToHead(const int nCount)
{
return InsertMultipleBefore(0, nCount);
}
int AddToTail()
{
return InsertBefore(nSize);
}
int AddToTail(const T& source)
{
// can't insert something that's in the list. reallocation may hose us
CS_ASSERT(memory.Base() == nullptr || &source < begin() || &source >= end());
return InsertBefore(nSize, source);
}
int AddMultipleToTail(const int nCount)
{
return InsertMultipleBefore(nSize, nCount);
}
void SetCount(const int nCount)
{
RemoveAll();
AddMultipleToTail(nCount);
}
int InsertBefore(const int nElement)
{
// can insert at the end
CS_ASSERT(nElement == nSize || IsValidIndex(nElement));
GrowVector();
ShiftElementsRight(nElement);
new (&Element(nElement)) T; // @todo: all functions of game classes that using this should be wrapped with constraints 'requires (std::is_pointer_v<T> || have_constructor_overload<T> || have_new_overload<T>)'
return nElement;
}
int InsertMultipleBefore(const int nElement, const int nCount)
{
if (nCount == 0)
return nElement;
// can insert at the end
CS_ASSERT(nElement == nSize || IsValidIndex(nElement));
GrowVector(nCount);
ShiftElementsRight(nElement, nCount);
// invoke default constructors
for (int i = 0; i < nElement; ++i)
new (&Element(nElement + i)) T;
return nElement;
}
int InsertBefore(const int nElement, const T& source)
{
// can't insert something that's in the list. reallocation may hose us
CS_ASSERT(memory.Base() == nullptr || &source < begin() || &source >= end());
// can insert at the end
CS_ASSERT(nElement == nSize || IsValidIndex(nElement));
// reallocate if can't insert something that's in the list
GrowVector();
ShiftElementsRight(nElement);
new (&Element(nElement)) T(source);
return nElement;
}
int InsertMultipleBefore(const int nElement, const int nCount, const T* pSource)
{
if (nCount == 0)
return nElement;
// can insert at the end
CS_ASSERT(nElement == nSize || IsValidIndex(nElement));
GrowVector(nCount);
ShiftElementsRight(nElement, nCount);
// invoke default constructors
if (pSource == nullptr)
{
for (int i = 0; i < nCount; ++i)
new (&Element(nElement + i)) T;
}
else
{
for (int i = 0; i < nCount; i++)
new (&Element(nElement)) T(pSource[i]);
}
return nElement;
}
[[nodiscard]] int Find(const T& source) const
{
for (int i = 0; i < nSize; ++i)
{
if (Element(i) == source)
return i;
}
return -1;
}
bool FindAndRemove(const T& source)
{
if (const int nElement = Find(source); nElement != -1)
{
Remove(nElement);
return true;
}
return false;
}
void Remove(const int nElement)
{
(&Element(nElement))->~T();
ShiftElementsLeft(nElement);
--nSize;
}
void RemoveAll()
{
for (int i = nSize; --i >= 0;)
(&Element(i))->~T();
nSize = 0;
}
[[nodiscard]] auto begin() noexcept
{
return memory.Base();
}
[[nodiscard]] auto end() noexcept
{
return memory.Base() + nSize;
}
[[nodiscard]] auto begin() const noexcept
{
return memory.Base();
}
[[nodiscard]] auto end() const noexcept
{
return memory.Base() + nSize;
}
protected:
int nSize;
CAllocator memory;
T* pElements;
};
template <class T>
class CUtlVectorAligned : public CUtlVector<T, CUtlMemoryAligned<T, alignof(T)>>
{
};
//a array class with a fixed allocation scheme
template <class T, std::size_t MAX_SIZE>
class CUtlVectorFixed : public CUtlVector<T, CUtlMemoryFixed<T, MAX_SIZE>>
{
using CBaseClass = CUtlVector<T, CUtlMemoryFixed<T, MAX_SIZE>>;
public:
explicit CUtlVectorFixed(int nGrowSize = 0, int nInitialCapacity = 0) :
CBaseClass(nGrowSize, nInitialCapacity) { }
CUtlVectorFixed(T* pMemory, int nElements) :
CBaseClass(pMemory, nElements) { }
};
template <typename T>
class C_NetworkUtlVectorBase
{
public:
std::uint32_t nSize;
T* pElements;
};

View File

@@ -0,0 +1,52 @@
#include "vector.h"
#include "matrix.h"
#include "qangle.h"
// used: m_rad2deg
#include "../../utilities/math.h"
[[nodiscard]] Vector_t Vector_t::Transform(const Matrix3x4_t& matTransform) const
{
return {
this->DotProduct(matTransform[0]) + matTransform[0][3],
this->DotProduct(matTransform[1]) + matTransform[1][3],
this->DotProduct(matTransform[2]) + matTransform[2][3]
};
}
[[nodiscard]] QAngle_t Vector_t::ToAngles() const
{
float flPitch, flYaw;
if (this->x == 0.0f && this->y == 0.0f)
{
flPitch = (this->z > 0.0f) ? 270.f : 90.f;
flYaw = 0.0f;
}
else
{
flPitch = M_RAD2DEG(std::atan2f(-this->z, this->Length2D()));
if (flPitch < 0.f)
flPitch += 360.f;
flYaw = M_RAD2DEG(std::atan2f(this->y, this->x));
if (flYaw < 0.f)
flYaw += 360.f;
}
return { flPitch, flYaw, 0.0f };
}
[[nodiscard]] Matrix3x4_t Vector_t::ToMatrix() const
{
Vector_t vecRight = {}, vecUp = {};
this->ToDirections(&vecRight, &vecUp);
Matrix3x4a_t matOutput = {};
matOutput.SetForward(*this);
matOutput.SetLeft(-vecRight);
matOutput.SetUp(vecUp);
return matOutput;
}

View File

@@ -0,0 +1,393 @@
#pragma once
// used: [stl] numeric_limits
#include <limits>
// used: [crt] isfinite, fmodf, sqrtf
#include <cmath>
// forward declarations
struct QAngle_t;
struct Matrix3x4_t;
// @source: master/public/mathlib/vector.h
struct Vector2D_t
{
constexpr Vector2D_t(const float x = 0.0f, const float y = 0.0f) :
x(x), y(y) { }
[[nodiscard]] bool IsZero() const
{
// @note: to make this implementation right, we should use fpclassify here, but game aren't doing same, probably it's better to keep this same, just ensure that it will be compiled same
return (this->x == 0.0f && this->y == 0.0f);
}
float x = 0.0f, y = 0.0f;
};
struct Vector_t
{
constexpr Vector_t(const float x = 0.0f, const float y = 0.0f, const float z = 0.0f) :
x(x), y(y), z(z) { }
constexpr Vector_t(const float* arrVector) :
x(arrVector[0]), y(arrVector[1]), z(arrVector[2]) { }
constexpr Vector_t(const Vector2D_t& vecBase2D) :
x(vecBase2D.x), y(vecBase2D.y) { }
#pragma region vector_array_operators
[[nodiscard]] float& operator[](const int nIndex)
{
return reinterpret_cast<float*>(this)[nIndex];
}
[[nodiscard]] const float& operator[](const int nIndex) const
{
return reinterpret_cast<const float*>(this)[nIndex];
}
#pragma endregion
#pragma region vector_relational_operators
bool operator==(const Vector_t& vecBase) const
{
return this->IsEqual(vecBase);
}
bool operator!=(const Vector_t& vecBase) const
{
return !this->IsEqual(vecBase);
}
#pragma endregion
#pragma region vector_assignment_operators
constexpr Vector_t& operator=(const Vector_t& vecBase)
{
this->x = vecBase.x;
this->y = vecBase.y;
this->z = vecBase.z;
return *this;
}
constexpr Vector_t& operator=(const Vector2D_t& vecBase2D)
{
this->x = vecBase2D.x;
this->y = vecBase2D.y;
this->z = 0.0f;
return *this;
}
#pragma endregion
#pragma region vector_arithmetic_assignment_operators
constexpr Vector_t& operator+=(const Vector_t& vecBase)
{
this->x += vecBase.x;
this->y += vecBase.y;
this->z += vecBase.z;
return *this;
}
constexpr Vector_t& operator-=(const Vector_t& vecBase)
{
this->x -= vecBase.x;
this->y -= vecBase.y;
this->z -= vecBase.z;
return *this;
}
constexpr Vector_t& operator*=(const Vector_t& vecBase)
{
this->x *= vecBase.x;
this->y *= vecBase.y;
this->z *= vecBase.z;
return *this;
}
constexpr Vector_t& operator/=(const Vector_t& vecBase)
{
this->x /= vecBase.x;
this->y /= vecBase.y;
this->z /= vecBase.z;
return *this;
}
constexpr Vector_t& operator+=(const float flAdd)
{
this->x += flAdd;
this->y += flAdd;
this->z += flAdd;
return *this;
}
constexpr Vector_t& operator-=(const float flSubtract)
{
this->x -= flSubtract;
this->y -= flSubtract;
this->z -= flSubtract;
return *this;
}
constexpr Vector_t& operator*=(const float flMultiply)
{
this->x *= flMultiply;
this->y *= flMultiply;
this->z *= flMultiply;
return *this;
}
constexpr Vector_t& operator/=(const float flDivide)
{
this->x /= flDivide;
this->y /= flDivide;
this->z /= flDivide;
return *this;
}
#pragma endregion
#pragma region vector_arithmetic_unary_operators
constexpr Vector_t& operator-()
{
this->x = -this->x;
this->y = -this->y;
this->z = -this->z;
return *this;
}
constexpr Vector_t operator-() const
{
return { -this->x, -this->y, -this->z };
}
#pragma endregion
#pragma region vector_arithmetic_ternary_operators
Vector_t operator+(const Vector_t& vecAdd) const
{
return { this->x + vecAdd.x, this->y + vecAdd.y, this->z + vecAdd.z };
}
Vector_t operator-(const Vector_t& vecSubtract) const
{
return { this->x - vecSubtract.x, this->y - vecSubtract.y, this->z - vecSubtract.z };
}
Vector_t operator*(const Vector_t& vecMultiply) const
{
return { this->x * vecMultiply.x, this->y * vecMultiply.y, this->z * vecMultiply.z };
}
Vector_t operator/(const Vector_t& vecDivide) const
{
return { this->x / vecDivide.x, this->y / vecDivide.y, this->z / vecDivide.z };
}
Vector_t operator+(const float flAdd) const
{
return { this->x + flAdd, this->y + flAdd, this->z + flAdd };
}
Vector_t operator-(const float flSubtract) const
{
return { this->x - flSubtract, this->y - flSubtract, this->z - flSubtract };
}
Vector_t operator*(const float flMultiply) const
{
return { this->x * flMultiply, this->y * flMultiply, this->z * flMultiply };
}
Vector_t operator/(const float flDivide) const
{
return { this->x / flDivide, this->y / flDivide, this->z / flDivide };
}
#pragma endregion
/// @returns: true if each component of the vector is finite, false otherwise
[[nodiscard]] bool IsValid() const
{
return std::isfinite(this->x) && std::isfinite(this->y) && std::isfinite(this->z);
}
constexpr void Invalidate()
{
this->x = this->y = this->z = std::numeric_limits<float>::infinity();
}
/// @returns: true if each component of the vector equals to another, false otherwise
[[nodiscard]] bool IsEqual(const Vector_t& vecEqual, const float flErrorMargin = std::numeric_limits<float>::epsilon()) const
{
return (std::fabsf(this->x - vecEqual.x) < flErrorMargin && std::fabsf(this->y - vecEqual.y) < flErrorMargin && std::fabsf(this->z - vecEqual.z) < flErrorMargin);
}
/// @returns: true if each component of the vector equals to zero, false otherwise
[[nodiscard]] bool IsZero() const
{
// @note: to make this implementation right, we should use fpclassify here, but game aren't doing same, probably it's better to keep this same, just ensure that it will be compiled same
return (this->x == 0.0f && this->y == 0.0f && this->z == 0.0f);
}
[[nodiscard]] float Length() const
{
return std::sqrtf(this->LengthSqr());
}
[[nodiscard]] constexpr float LengthSqr() const
{
return DotProduct(*this);
}
[[nodiscard]] float Length2D() const
{
return std::sqrtf(this->Length2DSqr());
}
[[nodiscard]] constexpr float Length2DSqr() const
{
return (this->x * this->x + this->y * this->y);
}
[[nodiscard]] float DistTo(const Vector_t& vecEnd) const
{
return (*this - vecEnd).Length();
}
[[nodiscard]] constexpr float DistToSqr(const Vector_t& vecEnd) const
{
return (*this - vecEnd).LengthSqr();
}
/// normalize magnitude of each component of the vector
/// @returns: length of the vector
float NormalizeInPlace()
{
const float flLength = this->Length();
const float flRadius = 1.0f / (flLength + std::numeric_limits<float>::epsilon());
this->x *= flRadius;
this->y *= flRadius;
this->z *= flRadius;
return flLength;
}
/// normalize magnitude of each component of the vector
/// @returns: copy of the vector with normalized components
[[nodiscard]] Vector_t Normalized() const
{
Vector_t vecOut = *this;
vecOut.NormalizeInPlace();
return vecOut;
}
[[nodiscard]] constexpr float DotProduct(const Vector_t& vecDot) const
{
return (this->x * vecDot.x + this->y * vecDot.y + this->z * vecDot.z);
}
[[nodiscard]] constexpr Vector_t CrossProduct(const Vector_t& vecCross) const
{
return { this->y * vecCross.z - this->z * vecCross.y, this->z * vecCross.x - this->x * vecCross.z, this->x * vecCross.y - this->y * vecCross.x };
}
/// @returns: transformed vector by given transformation matrix
[[nodiscard]] Vector_t Transform(const Matrix3x4_t& matTransform) const;
[[nodiscard]] Vector2D_t ToVector2D() const
{
return { this->x, this->y };
}
/// convert forward direction vector to other direction vectors
/// @param[out] pvecRight [optional] output for converted right vector
/// @param[out] pvecUp [optional] output for converted up vector
void ToDirections(Vector_t* pvecRight, Vector_t* pvecUp) const
{
if (std::fabsf(this->x) < 1e-6f && std::fabsf(this->y) < 1e-6f)
{
// pitch 90 degrees up/down from identity
if (pvecRight != nullptr)
{
pvecRight->x = 0.0f;
pvecRight->y = -1.0f;
pvecRight->z = 0.0f;
}
if (pvecUp != nullptr)
{
pvecUp->x = -this->z;
pvecUp->y = 0.0f;
pvecUp->z = 0.0f;
}
}
else
{
if (pvecRight != nullptr)
{
pvecRight->x = this->y;
pvecRight->y = -this->x;
pvecRight->z = 0.0f;
pvecRight->NormalizeInPlace();
}
if (pvecUp != nullptr)
{
pvecUp->x = (-this->x) * this->z;
pvecUp->y = -(this->y * this->z);
pvecUp->z = this->y * this->y - (-this->x) * this->x;
pvecUp->NormalizeInPlace();
}
}
}
/// @returns: 2D angles converted from direction vector
[[nodiscard]] QAngle_t ToAngles() const;
/// @returns: matrix converted from forward direction vector
[[nodiscard]] Matrix3x4_t ToMatrix() const;
float x = 0.0f, y = 0.0f, z = 0.0f;
};
struct Vector4D_t
{
constexpr Vector4D_t(const float x = 0.0f, const float y = 0.0f, const float z = 0.0f, const float w = 0.0f) :
x(x), y(y), z(z), w(w) { }
float x = 0.0f, y = 0.0f, z = 0.0f, w = 0.0f;
};
struct alignas(16) VectorAligned_t : Vector_t
{
VectorAligned_t() = default;
explicit VectorAligned_t(const Vector_t& vecBase)
{
this->x = vecBase.x;
this->y = vecBase.y;
this->z = vecBase.z;
this->w = 0.0f;
}
constexpr VectorAligned_t& operator=(const Vector_t& vecBase)
{
this->x = vecBase.x;
this->y = vecBase.y;
this->z = vecBase.z;
this->w = 0.0f;
return *this;
}
float w = 0.0f;
};
static_assert(alignof(VectorAligned_t) == 16);

View File

@@ -0,0 +1,27 @@
#pragma once
// used: mem_pad
#include "../../utilities/memory.h"
// used: vector_t
#include "vector.h"
// used: qangle_t
#include "qangle.h"
class CViewSetup
{
public:
MEM_PAD(0x490);
float flOrthoLeft; // 0x0494
float flOrthoTop; // 0x0498
float flOrthoRight; // 0x049C
float flOrthoBottom; // 0x04A0
MEM_PAD(0x38);
float flFov; // 0x04D8
float flFovViewmodel; // 0x04DC
Vector_t vecOrigin; // 0x04E0
MEM_PAD(0xC); // 0x04EC
QAngle_t angView; // 0x04F8
MEM_PAD(0x14); // 0x0504
float flAspectRatio; // 0x0518
};

View File

@@ -0,0 +1,154 @@
#include "entity.h"
// used: convars
#include "../core/convars.h"
#include "interfaces/cgameentitysystem.h"
#include "interfaces/ienginecvar.h"
#include "interfaces/iengineclient.h"
// used: game's definitions, enums
#include "const.h"
// global empty vector for when we can't get the origin
static Vector_t vecEmpty = Vector_t(0, 0, 0);
CCSPlayerController* CCSPlayerController::GetLocalPlayerController()
{
const int nIndex = I::Engine->GetLocalPlayer();
return I::GameResourceService->pGameEntitySystem->Get<CCSPlayerController>(nIndex);
}
const Vector_t& CCSPlayerController::GetPawnOrigin()
{
CBaseHandle hPawnHandle = this->GetPawnHandle();
if (!hPawnHandle.IsValid())
return vecEmpty;
C_CSPlayerPawn* pPlayerPawn = I::GameResourceService->pGameEntitySystem->Get<C_CSPlayerPawn>(hPawnHandle);
if (pPlayerPawn == nullptr)
return vecEmpty;
return pPlayerPawn->GetSceneOrigin();
}
C_BaseEntity* C_BaseEntity::GetLocalPlayer()
{
const int nIndex = I::Engine->GetLocalPlayer();
return I::GameResourceService->pGameEntitySystem->Get(nIndex);
}
const Vector_t& C_BaseEntity::GetSceneOrigin()
{
if (this->GetGameSceneNode())
return GetGameSceneNode()->GetAbsOrigin();
return vecEmpty;
}
bool C_CSPlayerPawn::IsOtherEnemy(C_CSPlayerPawn* pOther)
{
// check are other player is invalid or we're comparing against ourselves
if (pOther == nullptr || this == pOther)
return false;
if (CONVAR::game_type->value.i32 == GAMETYPE_FREEFORALL && CONVAR::game_mode->value.i32 == GAMEMODE_FREEFORALL_SURVIVAL)
// check is not teammate
return (this->GetSurvivalTeam() != pOther->GetSurvivalTeam());
// @todo: check is deathmatch
if (CONVAR::mp_teammates_are_enemies->value.i1)
return true;
return this->GetAssociatedTeam() != pOther->GetAssociatedTeam();
}
int C_CSPlayerPawn::GetAssociatedTeam()
{
const int nTeam = this->GetTeam();
// @todo: check is coaching, currently cs2 doesnt have sv_coaching_enabled, so just let it be for now...
//if (CONVAR::sv_coaching_enabled->GetBool() && nTeam == TEAM_SPECTATOR)
// return this->GetCoachingTeam();
return nTeam;
}
bool C_CSPlayerPawn::CanAttack(const float flServerTime)
{
// check is player ready to attack
if (CCSPlayer_WeaponServices* pWeaponServices = this->GetWeaponServices(); pWeaponServices != nullptr)
if (this->IsWaitForNoAttack() || pWeaponServices->GetNextAttack() > flServerTime)
return false;
return true;
}
std::uint32_t C_CSPlayerPawn::GetOwnerHandleIndex()
{
std::uint32_t Result = -1;
if (this && GetCollision() && !(GetCollision()->GetSolidFlags() & 4))
Result = this->GetOwnerHandle().GetEntryIndex();
return Result;
}
std::uint16_t C_CSPlayerPawn::GetCollisionMask()
{
if (this && GetCollision())
return GetCollision()->CollisionMask(); // Collision + 0x38
return 0;
}
bool C_CSWeaponBaseGun::CanPrimaryAttack(const int nWeaponType, const float flServerTime)
{
// check are weapon support burst mode and it's ready to attack
if (this->IsBurstMode())
{
// check is it ready to attack
if (this->GetBurstShotsRemaining() > 0 /*&& this->GetNextBurstShotTime() <= flServerTime*/)
return true;
}
// check is weapon ready to attack
if (this->GetNextPrimaryAttackTick() > TIME_TO_TICKS(flServerTime))
return false;
// we doesn't need additional checks for knives
if (nWeaponType == WEAPONTYPE_KNIFE)
return true;
// check do weapon have ammo
if (this->GetClip1() <= 0)
return false;
const ItemDefinitionIndex_t nDefinitionIndex = this->GetAttributeManager()->GetItem()->GetItemDefinitionIndex();
// check for revolver cocking ready
if (nDefinitionIndex == WEAPON_R8_REVOLVER && this->GetPostponeFireReadyFrac() > flServerTime)
return false;
return true;
}
bool C_CSWeaponBaseGun::CanSecondaryAttack(const int nWeaponType, const float flServerTime)
{
// check is weapon ready to attack
if (this->GetNextSecondaryAttackTick() > TIME_TO_TICKS(flServerTime))
return false;
// we doesn't need additional checks for knives
if (nWeaponType == WEAPONTYPE_KNIFE)
return true;
// check do weapon have ammo
if (this->GetClip1() <= 0)
return false;
// only revolver is allowed weapon for secondary attack
if (this->GetAttributeManager()->GetItem()->GetItemDefinitionIndex() != WEAPON_R8_REVOLVER)
return false;
return true;
}

View File

@@ -0,0 +1,432 @@
#pragma once
// @test: using interfaces in the header | not critical but could blow up someday with thousands of errors or affect to compilation time etc
// used: cgameentitysystem, ischemasystem
#include "../core/interfaces.h"
#include "interfaces/igameresourceservice.h"
#include "interfaces/ischemasystem.h"
// used: schema field
#include "../core/schema.h"
// used: l_print
#include "../utilities/log.h"
// used: vector_t
#include "datatypes/vector.h"
// used: qangle_t
#include "datatypes/qangle.h"
// used: ctransform
#include "datatypes/transform.h"
// used: cbasehandle
#include "entity_handle.h"
// used: game's definitions
#include "const.h"
// used: entity vdata
#include "vdata.h"
using GameTime_t = std::float_t;
using GameTick_t = std::int32_t;
class CEntityInstance;
class CEntityIdentity
{
public:
CS_CLASS_NO_INITIALIZER(CEntityIdentity);
// @note: handle index is not entity index
SCHEMA_ADD_OFFSET(std::uint32_t, GetIndex, 0x10);
SCHEMA_ADD_FIELD(const char*, GetDesignerName, "CEntityIdentity->m_designerName");
SCHEMA_ADD_FIELD(std::uint32_t, GetFlags, "CEntityIdentity->m_flags");
[[nodiscard]] bool IsValid()
{
return GetIndex() != INVALID_EHANDLE_INDEX;
}
[[nodiscard]] int GetEntryIndex()
{
if (!IsValid())
return ENT_ENTRY_MASK;
return GetIndex() & ENT_ENTRY_MASK;
}
[[nodiscard]] int GetSerialNumber()
{
return GetIndex() >> NUM_SERIAL_NUM_SHIFT_BITS;
}
CEntityInstance* pInstance; // 0x00
};
class CEntityInstance
{
public:
CS_CLASS_NO_INITIALIZER(CEntityInstance);
void GetSchemaClassInfo(SchemaClassInfoData_t** pReturn)
{
return MEM::CallVFunc<void, 38U>(this, pReturn);
}
[[nodiscard]] CBaseHandle GetRefEHandle()
{
CEntityIdentity* pIdentity = GetIdentity();
if (pIdentity == nullptr)
return CBaseHandle();
return CBaseHandle(pIdentity->GetEntryIndex(), pIdentity->GetSerialNumber() - (pIdentity->GetFlags() & 1));
}
SCHEMA_ADD_FIELD(CEntityIdentity*, GetIdentity, "CEntityInstance->m_pEntity");
};
class CCollisionProperty
{
public:
std::uint16_t CollisionMask()
{
return *reinterpret_cast<std::uint16_t*>(reinterpret_cast<std::uintptr_t>(this) + 0x38);
}
CS_CLASS_NO_INITIALIZER(CCollisionProperty);
SCHEMA_ADD_FIELD(Vector_t, GetMins, "CCollisionProperty->m_vecMins");
SCHEMA_ADD_FIELD(Vector_t, GetMaxs, "CCollisionProperty->m_vecMaxs");
SCHEMA_ADD_FIELD(std::uint8_t, GetSolidFlags, "CCollisionProperty->m_usSolidFlags");
SCHEMA_ADD_FIELD(std::uint8_t, GetCollisionGroup, "CCollisionProperty->m_CollisionGroup");
};
class CSkeletonInstance;
class CGameSceneNode
{
public:
CS_CLASS_NO_INITIALIZER(CGameSceneNode);
SCHEMA_ADD_FIELD(CTransform, GetNodeToWorld, "CGameSceneNode->m_nodeToWorld");
SCHEMA_ADD_FIELD(CEntityInstance*, GetOwner, "CGameSceneNode->m_pOwner");
SCHEMA_ADD_FIELD(Vector_t, GetAbsOrigin, "CGameSceneNode->m_vecAbsOrigin");
SCHEMA_ADD_FIELD(Vector_t, GetRenderOrigin, "CGameSceneNode->m_vRenderOrigin");
SCHEMA_ADD_FIELD(QAngle_t, GetAngleRotation, "CGameSceneNode->m_angRotation");
SCHEMA_ADD_FIELD(QAngle_t, GetAbsAngleRotation, "CGameSceneNode->m_angAbsRotation");
SCHEMA_ADD_FIELD(bool, IsDormant, "CGameSceneNode->m_bDormant");
CSkeletonInstance* GetSkeletonInstance()
{
return MEM::CallVFunc<CSkeletonInstance*, 8U>(this);
}
};
class C_BaseEntity : public CEntityInstance
{
public:
CS_CLASS_NO_INITIALIZER(C_BaseEntity);
[[nodiscard]] bool IsBasePlayerController()
{
SchemaClassInfoData_t* pClassInfo;
GetSchemaClassInfo(&pClassInfo);
if (pClassInfo == nullptr)
return false;
return FNV1A::Hash(pClassInfo->szName) == FNV1A::HashConst("C_CSPlayerController");
}
[[nodiscard]] bool IsWeapon()
{
static SchemaClassInfoData_t* pWeaponBaseClass = nullptr;
if (pWeaponBaseClass == nullptr)
I::SchemaSystem->FindTypeScopeForModule(CS_XOR("client.dll"))->FindDeclaredClass(&pWeaponBaseClass, CS_XOR("C_CSWeaponBase"));
SchemaClassInfoData_t* pClassInfo;
GetSchemaClassInfo(&pClassInfo);
if (pClassInfo == nullptr)
return false;
return (pClassInfo->InheritsFrom(pWeaponBaseClass));
}
static C_BaseEntity* GetLocalPlayer();
// get entity origin on scene
[[nodiscard]] const Vector_t& GetSceneOrigin();
SCHEMA_ADD_FIELD(CGameSceneNode*, GetGameSceneNode, "C_BaseEntity->m_pGameSceneNode");
SCHEMA_ADD_FIELD(CCollisionProperty*, GetCollision, "C_BaseEntity->m_pCollision");
SCHEMA_ADD_FIELD(std::uint8_t, GetTeam, "C_BaseEntity->m_iTeamNum");
SCHEMA_ADD_FIELD(CBaseHandle, GetOwnerHandle, "C_BaseEntity->m_hOwnerEntity");
SCHEMA_ADD_FIELD(Vector_t, GetBaseVelocity, "C_BaseEntity->m_vecBaseVelocity");
SCHEMA_ADD_FIELD(Vector_t, GetAbsVelocity, "C_BaseEntity->m_vecAbsVelocity");
SCHEMA_ADD_FIELD(bool, IsTakingDamage, "C_BaseEntity->m_bTakesDamage");
SCHEMA_ADD_FIELD(std::uint32_t, GetFlags, "C_BaseEntity->m_fFlags");
SCHEMA_ADD_FIELD(std::int32_t, GetEflags, "C_BaseEntity->m_iEFlags");
SCHEMA_ADD_FIELD(std::uint8_t, GetMoveType, "C_BaseEntity->m_nActualMoveType"); // m_nActualMoveType returns CSGO style movetype, m_nMoveType returns bitwise shifted move type
SCHEMA_ADD_FIELD(std::uint8_t, GetLifeState, "C_BaseEntity->m_lifeState");
SCHEMA_ADD_FIELD(std::int32_t, GetHealth, "C_BaseEntity->m_iHealth");
SCHEMA_ADD_FIELD(std::int32_t, GetMaxHealth, "C_BaseEntity->m_iMaxHealth");
SCHEMA_ADD_FIELD(float, GetWaterLevel, "C_BaseEntity->m_flWaterLevel");
SCHEMA_ADD_FIELD_OFFSET(void*, GetVData, "C_BaseEntity->m_nSubclassID", 0x8);
};
class CGlowProperty;
class C_BaseModelEntity : public C_BaseEntity
{
public:
CS_CLASS_NO_INITIALIZER(C_BaseModelEntity);
SCHEMA_ADD_FIELD(CCollisionProperty, GetCollisionInstance, "C_BaseModelEntity->m_Collision");
SCHEMA_ADD_FIELD(CGlowProperty, GetGlowProperty, "C_BaseModelEntity->m_Glow");
SCHEMA_ADD_FIELD(Vector_t, GetViewOffset, "C_BaseModelEntity->m_vecViewOffset");
SCHEMA_ADD_FIELD(GameTime_t, GetCreationTime, "C_BaseModelEntity->m_flCreateTime");
SCHEMA_ADD_FIELD(GameTick_t, GetCreationTick, "C_BaseModelEntity->m_nCreationTick");
SCHEMA_ADD_FIELD(CBaseHandle, GetMoveParent, "C_BaseModelEntity->m_hOldMoveParent");
SCHEMA_ADD_FIELD(std::float_t, GetAnimTime, "C_BaseModelEntity->m_flAnimTime");
SCHEMA_ADD_FIELD(std::float_t, GetSimulationTime, "C_BaseModelEntity->m_flSimulationTime");
};
class CPlayer_ItemServices;
class CPlayer_CameraServices;
class CPlayer_WeaponServices
{
public:
SCHEMA_ADD_FIELD(CBaseHandle, GetActiveWeapon, "CPlayer_WeaponServices->m_hActiveWeapon");
};
class CCSPlayer_WeaponServices : public CPlayer_WeaponServices
{
public:
SCHEMA_ADD_FIELD(GameTime_t, GetNextAttack, "CCSPlayer_WeaponServices->m_flNextAttack");
};
class C_BasePlayerPawn : public C_BaseModelEntity
{
public:
CS_CLASS_NO_INITIALIZER(C_BasePlayerPawn);
SCHEMA_ADD_FIELD(CBaseHandle, GetControllerHandle, "C_BasePlayerPawn->m_hController");
SCHEMA_ADD_FIELD(CCSPlayer_WeaponServices*, GetWeaponServices, "C_BasePlayerPawn->m_pWeaponServices");
SCHEMA_ADD_FIELD(CPlayer_ItemServices*, GetItemServices, "C_BasePlayerPawn->m_pItemServices");
SCHEMA_ADD_FIELD(CPlayer_CameraServices*, GetCameraServices, "C_BasePlayerPawn->m_pCameraServices");
[[nodiscard]] Vector_t GetEyePosition()
{
Vector_t vecEyePosition = Vector_t(0.0f, 0.0f, 0.0f);
// Credit: https://www.unknowncheats.me/forum/4258133-post6228.html
MEM::CallVFunc<void, 169U>(this, &vecEyePosition);
return vecEyePosition;
}
};
class CCSPlayer_ViewModelServices;
class C_CSPlayerPawnBase : public C_BasePlayerPawn
{
public:
CS_CLASS_NO_INITIALIZER(C_CSPlayerPawnBase);
SCHEMA_ADD_FIELD(CCSPlayer_ViewModelServices*, GetViewModelServices, "C_CSPlayerPawnBase->m_pViewModelServices");
SCHEMA_ADD_FIELD(float, GetLowerBodyYawTarget, "C_CSPlayerPawnBase->m_flLowerBodyYawTarget");
SCHEMA_ADD_FIELD(float, GetFlashMaxAlpha, "C_CSPlayerPawnBase->m_flFlashMaxAlpha");
SCHEMA_ADD_FIELD(float, GetFlashDuration, "C_CSPlayerPawnBase->m_flFlashDuration");
SCHEMA_ADD_FIELD(Vector_t, GetLastSmokeOverlayColor, "C_CSPlayerPawnBase->m_vLastSmokeOverlayColor");
SCHEMA_ADD_FIELD(int, GetSurvivalTeam, "C_CSPlayerPawnBase->m_nSurvivalTeam"); // danger zone
};
class C_CSPlayerPawn : public C_CSPlayerPawnBase
{
public:
CS_CLASS_NO_INITIALIZER(C_CSPlayerPawn);
[[nodiscard]] bool IsOtherEnemy(C_CSPlayerPawn* pOther);
[[nodiscard]] int GetAssociatedTeam();
[[nodiscard]] bool CanAttack(const float flServerTime);
[[nodiscard]] std::uint32_t GetOwnerHandleIndex();
[[nodiscard]] std::uint16_t GetCollisionMask();
SCHEMA_ADD_FIELD(bool, IsScoped, "C_CSPlayerPawn->m_bIsScoped");
SCHEMA_ADD_FIELD(bool, IsDefusing, "C_CSPlayerPawn->m_bIsDefusing");
SCHEMA_ADD_FIELD(bool, IsGrabbingHostage, "C_CSPlayerPawn->m_bIsGrabbingHostage");
SCHEMA_ADD_FIELD(bool, IsWaitForNoAttack, "C_CSPlayerPawn->m_bWaitForNoAttack");
SCHEMA_ADD_FIELD(int, GetShotsFired, "C_CSPlayerPawn->m_iShotsFired");
SCHEMA_ADD_FIELD(std::int32_t, GetArmorValue, "C_CSPlayerPawn->m_ArmorValue");
SCHEMA_ADD_FIELD(QAngle_t, GetAimPuchAngle, "C_CSPlayerPawn->m_aimPunchAngle");
};
class CBasePlayerController : public C_BaseModelEntity
{
public:
CS_CLASS_NO_INITIALIZER(CBasePlayerController);
SCHEMA_ADD_FIELD(std::uint64_t, GetSteamId, "CBasePlayerController->m_steamID");
SCHEMA_ADD_FIELD(std::uint32_t, GetTickBase, "CBasePlayerController->m_nTickBase");
SCHEMA_ADD_FIELD(CBaseHandle, GetPawnHandle, "CBasePlayerController->m_hPawn");
SCHEMA_ADD_FIELD(bool, IsLocalPlayerController, "CBasePlayerController->m_bIsLocalPlayerController");
};
// forward decleration
class C_CSWeaponBaseGun;
class C_BasePlayerWeapon;
class CCSPlayerController : public CBasePlayerController
{
public:
CS_CLASS_NO_INITIALIZER(CCSPlayerController);
[[nodiscard]] static CCSPlayerController* GetLocalPlayerController();
// @note: always get origin from pawn not controller
[[nodiscard]] const Vector_t& GetPawnOrigin();
SCHEMA_ADD_FIELD(std::uint32_t, GetPing, "CCSPlayerController->m_iPing");
SCHEMA_ADD_FIELD(const char*, GetPlayerName, "CCSPlayerController->m_sSanitizedPlayerName");
SCHEMA_ADD_FIELD(std::int32_t, GetPawnHealth, "CCSPlayerController->m_iPawnHealth");
SCHEMA_ADD_FIELD(std::int32_t, GetPawnArmor, "CCSPlayerController->m_iPawnArmor");
SCHEMA_ADD_FIELD(bool, IsPawnHasDefuser, "CCSPlayerController->m_bPawnHasDefuser");
SCHEMA_ADD_FIELD(bool, IsPawnHasHelmet, "CCSPlayerController->m_bPawnHasHelmet");
SCHEMA_ADD_FIELD(bool, IsPawnAlive, "CCSPlayerController->m_bPawnIsAlive");
SCHEMA_ADD_FIELD(CBaseHandle, GetPlayerPawnHandle, "CCSPlayerController->m_hPlayerPawn");
};
class CBaseAnimGraph : public C_BaseModelEntity
{
public:
CS_CLASS_NO_INITIALIZER(CBaseAnimGraph);
SCHEMA_ADD_FIELD(bool, IsClientRagdoll, "CBaseAnimGraph->m_bClientRagdoll");
};
class C_BaseFlex : public CBaseAnimGraph
{
public:
CS_CLASS_NO_INITIALIZER(C_BaseFlex);
/* not implemented */
};
class C_EconItemView
{
public:
CS_CLASS_NO_INITIALIZER(C_EconItemView);
SCHEMA_ADD_FIELD(std::uint16_t, GetItemDefinitionIndex, "C_EconItemView->m_iItemDefinitionIndex");
SCHEMA_ADD_FIELD(std::uint64_t, GetItemID, "C_EconItemView->m_iItemID");
SCHEMA_ADD_FIELD(std::uint32_t, GetItemIDHigh, "C_EconItemView->m_iItemIDHigh");
SCHEMA_ADD_FIELD(std::uint32_t, GetItemIDLow, "C_EconItemView->m_iItemIDLow");
SCHEMA_ADD_FIELD(std::uint32_t, GetAccountID, "C_EconItemView->m_iAccountID");
SCHEMA_ADD_FIELD(char[161], GetCustomName, "C_EconItemView->m_szCustomName");
SCHEMA_ADD_FIELD(char[161], GetCustomNameOverride, "C_EconItemView->m_szCustomNameOverride");
};
class CAttributeManager
{
public:
CS_CLASS_NO_INITIALIZER(CAttributeManager);
virtual ~CAttributeManager() = 0;
};
static_assert(sizeof(CAttributeManager) == 0x8);
class C_AttributeContainer : public CAttributeManager
{
public:
CS_CLASS_NO_INITIALIZER(C_AttributeContainer);
SCHEMA_ADD_PFIELD(C_EconItemView, GetItem, "C_AttributeContainer->m_Item");
};
class C_EconEntity : public C_BaseFlex
{
public:
CS_CLASS_NO_INITIALIZER(C_EconEntity);
SCHEMA_ADD_PFIELD(C_AttributeContainer, GetAttributeManager, "C_EconEntity->m_AttributeManager");
SCHEMA_ADD_FIELD(std::uint32_t, GetOriginalOwnerXuidLow, "C_EconEntity->m_OriginalOwnerXuidLow");
SCHEMA_ADD_FIELD(std::uint32_t, GetOriginalOwnerXuidHigh, "C_EconEntity->m_OriginalOwnerXuidHigh");
SCHEMA_ADD_FIELD(std::int32_t, GetFallbackPaintKit, "C_EconEntity->m_nFallbackPaintKit");
SCHEMA_ADD_FIELD(std::int32_t, GetFallbackSeed, "C_EconEntity->m_nFallbackSeed");
SCHEMA_ADD_FIELD(std::int32_t, GetFallbackWear, "C_EconEntity->m_flFallbackWear");
SCHEMA_ADD_FIELD(std::int32_t, GetFallbackStatTrak, "C_EconEntity->m_nFallbackStatTrak");
SCHEMA_ADD_FIELD(CBaseHandle, GetViewModelAttachmentHandle, "C_EconEntity->m_hViewmodelAttachment");
};
class C_EconWearable : public C_EconEntity
{
public:
CS_CLASS_NO_INITIALIZER(C_EconWearable);
SCHEMA_ADD_FIELD(std::int32_t, GetForceSkin, "C_EconWearable->m_nForceSkin");
SCHEMA_ADD_FIELD(bool, IsAlwaysAllow, "C_EconWearable->m_bAlwaysAllow");
};
class C_BasePlayerWeapon : public C_EconEntity
{
public:
CS_CLASS_NO_INITIALIZER(C_BasePlayerWeapon);
SCHEMA_ADD_FIELD(GameTick_t, GetNextPrimaryAttackTick, "C_BasePlayerWeapon->m_nNextPrimaryAttackTick");
SCHEMA_ADD_FIELD(float, GetNextPrimaryAttackTickRatio, "C_BasePlayerWeapon->m_flNextPrimaryAttackTickRatio");
SCHEMA_ADD_FIELD(GameTick_t, GetNextSecondaryAttackTick, "C_BasePlayerWeapon->m_nNextSecondaryAttackTick");
SCHEMA_ADD_FIELD(float, GetNextSecondaryAttackTickRatio, "C_BasePlayerWeapon->m_flNextSecondaryAttackTickRatio");
SCHEMA_ADD_FIELD(std::int32_t, GetClip1, "C_BasePlayerWeapon->m_iClip1");
SCHEMA_ADD_FIELD(std::int32_t, GetClip2, "C_BasePlayerWeapon->m_iClip2");
SCHEMA_ADD_FIELD(std::int32_t[2], GetReserveAmmo, "C_BasePlayerWeapon->m_pReserveAmmo");
};
class C_CSWeaponBase : public C_BasePlayerWeapon
{
public:
CS_CLASS_NO_INITIALIZER(C_CSWeaponBase);
SCHEMA_ADD_FIELD(bool, IsInReload, "C_CSWeaponBase->m_bInReload");
CCSWeaponBaseVData* GetWeaponVData()
{
return static_cast<CCSWeaponBaseVData*>(GetVData());
}
};
class C_CSWeaponBaseGun : public C_CSWeaponBase
{
public:
CS_CLASS_NO_INITIALIZER(C_CSWeaponBaseGun);
SCHEMA_ADD_FIELD(std::int32_t, GetZoomLevel, "C_CSWeaponBaseGun->m_zoomLevel");
SCHEMA_ADD_FIELD(std::int32_t, GetBurstShotsRemaining, "C_CSWeaponBaseGun->m_iBurstShotsRemaining");
SCHEMA_ADD_FIELD(bool, IsBurstMode, "C_CSWeaponBase->m_bBurstMode");
SCHEMA_ADD_FIELD(float, GetPostponeFireReadyFrac, "C_CSWeaponBase->m_flPostponeFireReadyFrac");
[[nodiscard]] bool CanPrimaryAttack(const int nWeaponType, const float flServerTime);
[[nodiscard]] bool CanSecondaryAttack(const int nWeaponType, const float flServerTime);
};
class C_BaseCSGrenade : public C_CSWeaponBase
{
public:
SCHEMA_ADD_FIELD(bool, IsHeldByPlayer, "C_BaseCSGrenade->m_bIsHeldByPlayer");
SCHEMA_ADD_FIELD(bool, IsPinPulled, "C_BaseCSGrenade->m_bPinPulled");
SCHEMA_ADD_FIELD(GameTime_t, GetThrowTime, "C_BaseCSGrenade->m_fThrowTime");
SCHEMA_ADD_FIELD(float, GetThrowStrength, "C_BaseCSGrenade->m_flThrowStrength");
};
class C_BaseGrenade : public C_BaseFlex
{
public:
CS_CLASS_NO_INITIALIZER(C_BaseGrenade);
};
class CSkeletonInstance : public CGameSceneNode
{
public:
MEM_PAD(0x1CC); //0x0000
int nBoneCount; //0x01CC
MEM_PAD(0x18); //0x01D0
int nMask; //0x01E8
MEM_PAD(0x4); //0x01EC
Matrix2x4_t* pBoneCache; //0x01F0
};

View File

@@ -0,0 +1,57 @@
#pragma once
#include "../common.h"
#define INVALID_EHANDLE_INDEX 0xFFFFFFFF
#define ENT_ENTRY_MASK 0x7FFF
#define NUM_SERIAL_NUM_SHIFT_BITS 15
// @source: https://developer.valvesoftware.com/wiki/Entity_limit#Source_2_limits
#define ENT_MAX_NETWORKED_ENTRY 16384
class CBaseHandle
{
public:
CBaseHandle() noexcept :
nIndex(INVALID_EHANDLE_INDEX) { }
CBaseHandle(const int nEntry, const int nSerial) noexcept
{
CS_ASSERT(nEntry >= 0 && (nEntry & ENT_ENTRY_MASK) == nEntry);
CS_ASSERT(nSerial >= 0 && nSerial < (1 << NUM_SERIAL_NUM_SHIFT_BITS));
nIndex = nEntry | (nSerial << NUM_SERIAL_NUM_SHIFT_BITS);
}
bool operator!=(const CBaseHandle& other) const noexcept
{
return nIndex != other.nIndex;
}
bool operator==(const CBaseHandle& other) const noexcept
{
return nIndex == other.nIndex;
}
bool operator<(const CBaseHandle& other) const noexcept
{
return nIndex < other.nIndex;
}
[[nodiscard]] bool IsValid() const noexcept
{
return nIndex != INVALID_EHANDLE_INDEX;
}
[[nodiscard]] int GetEntryIndex() const noexcept
{
return static_cast<int>(nIndex & ENT_ENTRY_MASK);
}
[[nodiscard]] int GetSerialNumber() const noexcept
{
return static_cast<int>(nIndex >> NUM_SERIAL_NUM_SHIFT_BITS);
}
private:
std::uint32_t nIndex;
};

View File

@@ -0,0 +1,95 @@
#pragma once
// used: mem_pad
#include "../../utilities/memory.h"
// used: cusercmd
#include "../datatypes/usercmd.h"
#define MULTIPLAYER_BACKUP 150
class CTinyMoveStepData
{
public:
float flWhen; //0x0000
MEM_PAD(0x4); //0x0004
std::uint64_t nButton; //0x0008
bool bPressed; //0x0010
MEM_PAD(0x7); //0x0011
}; //Size: 0x0018
class CMoveStepButtons
{
public:
std::uint64_t nKeyboardPressed; //0x0000
std::uint64_t nMouseWheelheelPressed; //0x0008
std::uint64_t nUnPressed; //0x0010
std::uint64_t nKeyboardCopy; //0x0018
}; //Size: 0x0020
// @credits: www.unknowncheats.me/forum/members/2943409.html
class CExtendedMoveData : public CMoveStepButtons
{
public:
float flForwardMove; //0x0020
float flSideMove; //0x0024
float flUpMove; //0x0028
std::int32_t nMouseDeltaX; //0x002C
std::int32_t nMouseDeltaY; //0x0030
std::int32_t nAdditionalStepMovesCount; //0x0034
CTinyMoveStepData tinyMoveStepData[12]; //0x0038
Vector_t vecViewAngle; //0x0158
std::int32_t nTargetHandle; //0x0164
}; //Size:0x0168
class CCSGOInput
{
public:
MEM_PAD(0x250);
CUserCmd arrCommands[MULTIPLAYER_BACKUP];
MEM_PAD(0x99)
bool bInThirdPerson;
MEM_PAD(0x6);
QAngle_t angThirdPersonAngles;
MEM_PAD(0xE);
std::int32_t nSequenceNumber;
double dbSomeTimer;
CExtendedMoveData currentMoveData;
std::int32_t nWeaponSwitchTick;
MEM_PAD(0x1C4);
CExtendedMoveData* pExtendedMoveData;
MEM_PAD(0x48);
int32_t nAttackStartHistoryIndex1;
int32_t nAttackStartHistoryIndex2;
int32_t nAttackStartHistoryIndex3;
CUserCmd* GetUserCmd()
{
return &arrCommands[nSequenceNumber % MULTIPLAYER_BACKUP];
}
void SetViewAngle(QAngle_t& angView)
{
// @ida: this got called before GetMatricesForView
using fnSetViewAngle = std::int64_t(CS_FASTCALL*)(void*, std::int32_t, QAngle_t&);
static auto oSetViewAngle = reinterpret_cast<fnSetViewAngle>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 75 3F 48")));
#ifdef CS_PARANOID
CS_ASSERT(oSetViewAngle != nullptr);
#endif
oSetViewAngle(this, 0, std::ref(angView));
}
QAngle_t GetViewAngles()
{
using fnGetViewAngles = std::int64_t(CS_FASTCALL*)(CCSGOInput*, std::int32_t);
static auto oGetViewAngles = reinterpret_cast<fnGetViewAngles>(MEM::FindPattern(CLIENT_DLL, CS_XOR("4C 8B C1 85 D2 74 08 48 8D 05 ? ? ? ? C3")));
#ifdef CS_PARANOID
CS_ASSERT(oGetViewAngles != nullptr);
#endif
return *reinterpret_cast<QAngle_t*>(oGetViewAngles(this, 0));
}
};

View File

@@ -0,0 +1,48 @@
#pragma once
// used: schema field
#include "../../utilities/memory.h"
#include "../entity_handle.h"
#define MAX_ENTITIES_IN_LIST 512
#define MAX_ENTITY_LISTS 64 // 0x3F
#define MAX_TOTAL_ENTITIES MAX_ENTITIES_IN_LIST* MAX_ENTITY_LISTS
class C_BaseEntity;
class CGameEntitySystem
{
public:
/// GetClientEntity
template <typename T = C_BaseEntity>
T* Get(int nIndex)
{
return reinterpret_cast<T*>(this->GetEntityByIndex(nIndex));
}
/// GetClientEntityFromHandle
template <typename T = C_BaseEntity>
T* Get(const CBaseHandle hHandle)
{
if (!hHandle.IsValid())
return nullptr;
return reinterpret_cast<T*>(this->GetEntityByIndex(hHandle.GetEntryIndex()));
}
int GetHighestEntityIndex()
{
return *reinterpret_cast<int*>(reinterpret_cast<std::uintptr_t>(this) + 0x1510);
}
private:
void* GetEntityByIndex(int nIndex)
{
//@ida: #STR: "(missing),", "(missing)", "Ent %3d: %s class %s name %s\n" | or find "cl_showents" cvar -> look for callback
// do { pEntity = GetBaseEntityByIndex(g_pGameEntitySystem, nCurrentIndex); ... }
using fnGetBaseEntity = void*(CS_THISCALL*)(void*, int);
static auto GetBaseEntity = reinterpret_cast<fnGetBaseEntity>(MEM::FindPattern(CLIENT_DLL, CS_XOR("81 FA ? ? ? ? 77 ? 8B C2 C1 F8 ? 83 F8 ? 77 ? 48 98 48 8B 4C C1 ? 48 85 C9 74 ? 8B C2 25 ? ? ? ? 48 6B C0 ? 48 03 C8 74 ? 8B 41 ? 25 ? ? ? ? 3B C2 75 ? 48 8B 01")));
return GetBaseEntity(this, nIndex);
}
};

View File

@@ -0,0 +1,59 @@
// used: game trace manager
#include "cgametracemanager.h"
// used: c_csplayerpawn
#include "../../sdk/entity.h"
SurfaceData_t* GameTrace_t::GetSurfaceData()
{
using fnGetSurfaceData = std::uint64_t(__fastcall*)(void*);
static fnGetSurfaceData oGetSurfaceData = reinterpret_cast<fnGetSurfaceData>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 48 85 C0 74 ? 44 38 60")), 0x1, 0x0));
#ifdef CS_PARANOID
CS_ASSERT(oGetSurfaceData != nullptr);
#endif
return reinterpret_cast<SurfaceData_t*>(oGetSurfaceData(m_pSurface));
}
int GameTrace_t::GetHitboxId()
{
if (m_pHitboxData)
return m_pHitboxData->m_nHitboxId;
return 0;
}
int GameTrace_t::GetHitgroup()
{
if (m_pHitboxData)
return m_pHitboxData->m_nHitGroup;
return 0;
}
bool GameTrace_t::IsVisible() const
{
return (m_flFraction > 0.97f);
}
TraceFilter_t::TraceFilter_t(std::uint64_t uMask, C_CSPlayerPawn* pSkip1, C_CSPlayerPawn* pSkip2, int nLayer)
{
m_uTraceMask = uMask;
m_v1[0] = m_v1[1] = 0;
m_v2 = 7;
m_v3 = nLayer;
m_v4 = 0x49;
m_v5 = 0;
if (pSkip1 != nullptr)
{
m_arrSkipHandles[0] = pSkip1->GetRefEHandle().GetEntryIndex();
m_arrSkipHandles[2] = pSkip1->GetOwnerHandleIndex();
m_arrCollisions[0] = pSkip1->GetCollisionMask();
}
if (pSkip2 != nullptr)
{
m_arrSkipHandles[0] = pSkip2->GetRefEHandle().GetEntryIndex();
m_arrSkipHandles[2] = pSkip2->GetOwnerHandleIndex();
m_arrCollisions[0] = pSkip2->GetCollisionMask();
}
}

View File

@@ -0,0 +1,118 @@
#pragma once
// used: pad and findpattern
#include "../../utilities/memory.h"
// used: vector
#include "../../sdk/datatypes/vector.h"
// used: array
#include <array>
struct Ray_t
{
public:
Vector_t m_vecStart;
Vector_t m_vecEnd;
Vector_t m_vecMins;
Vector_t m_vecMaxs;
MEM_PAD(0x4);
std::uint8_t UnkType;
};
static_assert(sizeof(Ray_t) == 0x38);
struct SurfaceData_t
{
public:
MEM_PAD(0x8)
float m_flPenetrationModifier;
float m_flDamageModifier;
MEM_PAD(0x4)
int m_iMaterial;
};
static_assert(sizeof(SurfaceData_t) == 0x18);
struct TraceHitboxData_t
{
public:
MEM_PAD(0x38);
int m_nHitGroup;
MEM_PAD(0x4);
int m_nHitboxId;
};
static_assert(sizeof(TraceHitboxData_t) == 0x44);
class C_CSPlayerPawn;
struct GameTrace_t
{
public:
GameTrace_t() = default;
SurfaceData_t* GetSurfaceData();
int GetHitboxId();
int GetHitgroup();
bool IsVisible() const;
void* m_pSurface;
C_CSPlayerPawn* m_pHitEntity;
TraceHitboxData_t* m_pHitboxData;
MEM_PAD(0x38);
std::uint32_t m_uContents;
MEM_PAD(0x24);
Vector_t m_vecStartPos;
Vector_t m_vecEndPos;
Vector_t m_vecNormal;
Vector_t m_vecPosition;
MEM_PAD(0x4);
float m_flFraction;
MEM_PAD(0x6);
bool m_bAllSolid;
MEM_PAD(0x4D)
}; // Size: 0x108
static_assert(sizeof(GameTrace_t) == 0x108);
struct TraceFilter_t
{
public:
MEM_PAD(0x8);
std::int64_t m_uTraceMask;
std::array<std::int64_t, 2> m_v1;
std::array<std::int32_t, 4> m_arrSkipHandles;
std::array<std::int16_t, 2> m_arrCollisions;
std::int16_t m_v2;
std::uint8_t m_v3;
std::uint8_t m_v4;
std::uint8_t m_v5;
TraceFilter_t() = default;
TraceFilter_t(std::uint64_t uMask, C_CSPlayerPawn* pSkip1, C_CSPlayerPawn* pSkip2, int nLayer);
};
static_assert(sizeof(TraceFilter_t) == 0x40);
class CGameTraceManager
{
public:
bool TraceShape(Ray_t* pRay, Vector_t vecStart, Vector_t vecEnd, TraceFilter_t* pFilter, GameTrace_t* pGameTrace)
{
using fnTraceShape = bool(__fastcall*)(CGameTraceManager*, Ray_t*, Vector_t*, Vector_t*, TraceFilter_t*, GameTrace_t*);
// Credit: https://www.unknowncheats.me/forum/4265752-post6333.html
static fnTraceShape oTraceShape = reinterpret_cast<fnTraceShape>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 20 48 89 4C 24 08 55 56 41")));
#ifdef CS_PARANOID
CS_ASSERT(oTraceShape != nullptr);
#endif
return oTraceShape(this, pRay, &vecStart, &vecEnd, pFilter, pGameTrace);
}
bool ClipRayToEntity(Ray_t* pRay, Vector_t vecStart, Vector_t vecEnd, C_CSPlayerPawn* pPawn, TraceFilter_t* pFilter, GameTrace_t* pGameTrace)
{
using fnClipRayToEntity = bool(__fastcall*)(CGameTraceManager*, Ray_t*, Vector_t*, Vector_t*, C_CSPlayerPawn*, TraceFilter_t*, GameTrace_t*);
static fnClipRayToEntity oClipRayToEntity = reinterpret_cast<fnClipRayToEntity>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 81 EC C0 00 00 00 48 8B 9C")));
#ifdef CS_PARANOID
CS_ASSERT(oClipRayToEntity != nullptr);
#endif
return oClipRayToEntity(this, pRay, &vecStart, &vecEnd, pPawn, pFilter, pGameTrace);
}
};

View File

@@ -0,0 +1,15 @@
#pragma once
// used: find pattern, call virtual function
#include "../../utilities/memory.h"
// used: vertor_t
#include "../datatypes/vector.h"
// used: color_t
#include "../datatypes/color.h"
class IDebugOverlayGameSystem
{
public:
// @todo: reverse this
};

View File

@@ -0,0 +1,67 @@
#pragma once
// used: callvfunc
#include "../../utilities/memory.h"
enum EClientFrameStage : int
{
FRAME_UNDEFINED = -1,
FRAME_START,
// a network packet is being received
FRAME_NET_UPDATE_START,
// data has been received and we are going to start calling postdataupdate
FRAME_NET_UPDATE_POSTDATAUPDATE_START,
// data has been received and called postdataupdate on all data recipients
FRAME_NET_UPDATE_POSTDATAUPDATE_END,
// received all packets, we can now do interpolation, prediction, etc
FRAME_NET_UPDATE_END,
// start rendering the scene
FRAME_RENDER_START,
// finished rendering the scene
FRAME_RENDER_END,
FRAME_NET_FULL_FRAME_UPDATE_ON_REMOVE
};
class IEngineClient
{
public:
int GetMaxClients()
{
return MEM::CallVFunc<int, 34U>(this);
}
bool IsInGame()
{
return MEM::CallVFunc<bool, 35U>(this);
}
bool IsConnected()
{
return MEM::CallVFunc<bool, 36U>(this);
}
// return CBaseHandle index
int GetLocalPlayer()
{
int nIndex = -1;
MEM::CallVFunc<void, 47U>(this, std::ref(nIndex), 0);
return nIndex + 1;
}
[[nodiscard]] const char* GetLevelName()
{
return MEM::CallVFunc<const char*, 56U>(this);
}
[[nodiscard]] const char* GetLevelNameShort()
{
return MEM::CallVFunc<const char*, 57U>(this);
}
[[nodiscard]] const char* GetProductVersionString()
{
return MEM::CallVFunc<const char*, 82U>(this);
}
};

View File

@@ -0,0 +1,150 @@
#pragma once
// used: cutllinkedlist
#include "../datatypes/utllinkedlist.h"
// used: fnv1a hashing
#include "../../utilities/fnv1a.h"
// used: sdk datatypes
#include "../datatypes/color.h"
#include "../datatypes/vector.h"
#include "../datatypes/qangle.h"
#pragma region convar_enumerations
// command to convars and concommands
enum EConVarFlag : int
{
// convar systems
FCVAR_NONE = 0,
FCVAR_UNREGISTERED = (1 << 0), // if this is set, don't add to linked list, etc
FCVAR_DEVELOPMENTONLY = (1 << 1), // hidden in released products. flag is removed automatically if allow_development_cvars is defined
FCVAR_GAMEDLL = (1 << 2), // defined by the game dll
FCVAR_CLIENTDLL = (1 << 3), // defined by the client dll
FCVAR_HIDDEN = (1 << 4), // hidden. doesn't appear in find or autocomplete. like developmentonly, but can't be compiled out
// convar only
FCVAR_PROTECTED = (1 << 5), // it's a server cvar, but we don't send the data since it's a password, etc. sends 1 if it's not bland/zero, 0 otherwise as value
FCVAR_SPONLY = (1 << 6), // this cvar cannot be changed by clients connected to a multiplayer server
FCVAR_ARCHIVE = (1 << 7), // set to cause it to be saved to vars.rc
FCVAR_NOTIFY = (1 << 8), // notifies players when changed
FCVAR_USERINFO = (1 << 9), // changes the client's info string
FCVAR_CHEAT = (1 << 14), // only useable in singleplayer/debug/multiplayer & sv_cheats
FCVAR_PRINTABLEONLY = (1 << 10), // this cvar's string cannot contain unprintable characters (e.g., used for player name etc)
FCVAR_UNLOGGED = (1 << 11), // if this is a fcvar_server, don't log changes to the log file / console if we are creating a log
FCVAR_NEVER_AS_STRING = (1 << 12), // never try to print that cvar
// it's a convar that's shared between the client and the server.
// at signon, the values of all such convars are sent from the server to the client (skipped for local client, ofc)
// if a change is requested it must come from the console (i.e., no remote client changes)
// if a value is changed while a server is active, it's replicated to all connected clients
FCVAR_REPLICATED = (1 << 13), // server setting enforced on clients, replicated
// @todo: (1 << 14) used by the game, probably used as modification detection
FCVAR_DEMO = (1 << 16), // record this cvar when starting a demo file
FCVAR_DONTRECORD = (1 << 17), // don't record these command in demofiles
FCVAR_RELOAD_MATERIALS = (1 << 20), // if this cvar changes, it forces a material reload
FCVAR_RELOAD_TEXTURES = (1 << 21), // if this cvar changes, if forces a texture reload
FCVAR_NOT_CONNECTED = (1 << 22), // cvar cannot be changed by a client that is connected to a server
FCVAR_MATERIAL_SYSTEM_THREAD = (1 << 23), // indicates this cvar is read from the material system thread
FCVAR_ARCHIVE_XBOX = (1 << 24), // cvar written to config.cfg on the xbox
FCVAR_ACCESSIBLE_FROM_THREADS = (1 << 25), // used as a debugging tool necessary to check material system thread convars
FCVAR_SERVER_CAN_EXECUTE = (1 << 28), // the server is allowed to execute this command on clients via clientcommand/net_stringcmd/cbaseclientstate::processstringcmd
FCVAR_SERVER_CANNOT_QUERY = (1 << 29), // if this is set, then the server is not allowed to query this cvar's value (via iserverpluginhelpers::startquerycvarvalue)
FCVAR_CLIENTCMD_CAN_EXECUTE = (1 << 30), // ivengineclient::clientcmd is allowed to execute this command
FCVAR_MATERIAL_THREAD_MASK = (FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD)
};
enum EConVarType : short
{
EConVarType_Invalid = -1,
EConVarType_Bool,
EConVarType_Int16,
EConVarType_UInt16,
EConVarType_Int32,
EConVarType_UInt32,
EConVarType_Int64,
EConVarType_UInt64,
EConVarType_Float32,
EConVarType_Float64,
EConVarType_String,
EConVarType_Color,
EConVarType_Vector2,
EConVarType_Vector3,
EConVarType_Vector4,
EConVarType_Qangle,
EConVarType_MAX
};
#pragma endregion
union CVValue_t
{
bool i1;
short i16;
uint16_t u16;
int i32;
uint32_t u32;
int64_t i64;
uint64_t u64;
float fl;
double db;
const char* sz;
Color_t clr;
Vector2D_t vec2;
Vector_t vec3;
Vector4D_t vec4;
QAngle_t ang;
};
class CConVar
{
public:
const char* szName; // 0x0000
CConVar* m_pNext; // 0x0008
MEM_PAD(0x10); // 0x0010
const char* szDescription; // 0x0020
uint32_t nType; // 0x28
uint32_t nRegistered; // 0x2C
uint32_t nFlags; // 0x30
MEM_PAD(0x8); // 0x34
// @note: read-only, mofify with caution
CVValue_t value; // 0x40
};
class IEngineCVar
{
public:
MEM_PAD(0x40);
CUtlLinkedList<CConVar*> listConvars;
CConVar* Find(FNV1A_t uHashedName)
{
for (int i = I::Cvar->listConvars.Head(); i != I::Cvar->listConvars.InvalidIndex(); i = I::Cvar->listConvars.Next(i))
{
CConVar* pConVar = I::Cvar->listConvars.Element(i);
if (pConVar == nullptr)
continue;
if (FNV1A::Hash(pConVar->szName) == uHashedName)
return pConVar;
}
CS_ASSERT(false); // invalid convar name
return nullptr;
}
void UnlockHiddenCVars()
{
for (int i = I::Cvar->listConvars.Head(); i != I::Cvar->listConvars.InvalidIndex(); i = I::Cvar->listConvars.Next(i))
{
CConVar* pConVar = I::Cvar->listConvars.Element(i);
if (pConVar == nullptr)
continue;
if (pConVar->nFlags & FCVAR_HIDDEN)
pConVar->nFlags &= ~FCVAR_HIDDEN;
if (pConVar->nFlags & FCVAR_DEVELOPMENTONLY)
pConVar->nFlags &= ~FCVAR_DEVELOPMENTONLY;
}
}
};

View File

@@ -0,0 +1,13 @@
#pragma once
// used: mem_pad
#include "../../utilities/memory.h"
class CGameEntitySystem;
class IGameResourceService
{
public:
MEM_PAD(0x58);
CGameEntitySystem* pGameEntitySystem;
};

View File

@@ -0,0 +1,20 @@
#pragma once
// used: mem_pad
#include "../../utilities/memory.h"
class IGlobalVars
{
public:
float flRealTime; //0x0000
int32_t nFrameCount; //0x0004
float flFrameTime; //0x0008
float flFrameTime2; //0x000C
int32_t nMaxClients; //0x0010
MEM_PAD(0x1C);
float flFrameTime3; //0x0030
float flCurrentTime; //0x0034
float flCurrentTime2; //0x0038
MEM_PAD(0xC);
int32_t nTickCount; //0x0048
};

View File

@@ -0,0 +1,20 @@
#pragma once
// used: getexportaddress
#include "../../utilities/memory.h"
class IInputSystem
{
public:
bool IsRelativeMouseMode()
{
// @ida: 'IInputSystem::SetRelativeMouseMode'.
return *reinterpret_cast<bool*>(reinterpret_cast<std::uintptr_t>(this) + 0x4D);
}
void* GetSDLWindow()
{
// @ida: IInputSystem::DebugSpew -> #STR: "Current coordinate bias %s: %g,%g scale %g,%g\n"
return *reinterpret_cast<void**>(reinterpret_cast<std::uintptr_t>(this) + 0x26A8);
}
};

View File

@@ -0,0 +1,126 @@
#pragma once
// used: call virtual function
#include "../../utilities/memory.h"
// used: color_t
#include "../datatypes/color.h"
// used: stronghandle
#include "../datatypes/stronghandle.h"
// used: keyvalue3
#include "../datatypes/keyvalue3.h"
// used vector4d_t
#include "../datatypes/vector.h"
// used: cbasehandle
#include "../entity_handle.h"
class CMaterial2
{
public:
virtual const char* GetName() = 0;
virtual const char* GetShareName() = 0;
};
// idk
struct MaterialKeyVar_t
{
std::uint64_t uKey;
const char* szName;
MaterialKeyVar_t(std::uint64_t uKey, const char* szName) :
uKey(uKey), szName(szName) { }
MaterialKeyVar_t(const char* szName, bool bShouldFindKey = false) :
szName(szName)
{
uKey = bShouldFindKey ? FindKey(szName) : 0x0;
}
std::uint64_t FindKey(const char* szName)
{
using fnFindKeyVar = std::uint64_t(CS_FASTCALL*)(const char*, unsigned int, int);
static auto oFindKeyVar = reinterpret_cast<fnFindKeyVar>(MEM::FindPattern(PARTICLES_DLL, CS_XOR("48 89 5C 24 ? 57 48 81 EC ? ? ? ? 33 C0 8B DA")));
#ifdef CS_PARANOID
CS_ASSERT(oFindKeyVar != nullptr);
#endif
// idk those enum flags, just saw it called like that soooo yea
return oFindKeyVar(szName, 0x12, 0x31415926);
}
};
class CObjectInfo
{
MEM_PAD(0xB0);
int nId;
};
class CSceneAnimatableObject
{
MEM_PAD(0xB8);
CBaseHandle hOwner;
};
// the naming is incorrect but i dont care atm
class CMeshData
{
public:
void SetShaderType(const char* szShaderName)
{
// @ida: #STR: shader, spritecard.vfx
using fnSetMaterialShaderType = void(CS_FASTCALL*)(void*, MaterialKeyVar_t, const char*, int);
static auto oSetMaterialShaderType = reinterpret_cast<fnSetMaterialShaderType>(MEM::FindPattern(PARTICLES_DLL, CS_XOR("48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 54 41 56 41 57 48 83 EC ? 0F B6 01 45 0F B6 F9 8B 2A 4D 8B E0 4C 8B 72 ? 48 8B F9 C0 E8 ? 24 ? 3C ? 74 ? 41 B0 ? B2 ? E8 ? ? ? ? 0F B6 07 33 DB C0 E8 ? 24 ? 3C ? 75 ? 48 8B 77 ? EB ? 48 8B F3 4C 8D 44 24 ? C7 44 24 ? ? ? ? ? 48 8D 54 24 ? 89 6C 24 ? 48 8B CE 4C 89 74 24 ? E8 ? ? ? ? 8B D0 83 F8 ? 75 ? 45 33 C9 89 6C 24 ? 4C 8D 44 24 ? 4C 89 74 24 ? 48 8B D7 48 8B CE E8 ? ? ? ? 8B D0 0F B6 0F C0 E9 ? 80 E1 ? 80 F9 ? 75 ? 48 8B 4F ? EB ? 48 8B CB 8B 41 ? 85 C0 74 ? 48 8D 59 ? 83 F8 ? 76 ? 48 8B 1B 48 63 C2 4D 85 E4")));
#ifdef CS_PARANOID
CS_ASSERT(oSetMaterialShaderType != nullptr);
#endif
MaterialKeyVar_t shaderVar(0x162C1777, CS_XOR("shader"));
oSetMaterialShaderType(this, shaderVar, szShaderName, 0x18);
}
void SetMaterialFunction(const char* szFunctionName, int nValue)
{
using fnSetMaterialFunction = void(__fastcall*)(void*, MaterialKeyVar_t, int, int);
static auto oSetMaterialFunction = reinterpret_cast<fnSetMaterialFunction>(MEM::FindPattern(PARTICLES_DLL, CS_XOR("48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 54 41 56 41 57 48 83 EC ? 0F B6 01 45 0F B6 F9 8B 2A 48 8B F9")));
#ifdef CS_PARANOID
CS_ASSERT(oSetMaterialFunction != nullptr);
#endif
MaterialKeyVar_t functionVar(szFunctionName, true);
oSetMaterialFunction(this, functionVar, nValue, 0x18);
}
// Credit: https://www.unknowncheats.me/forum/4270816-post6392.html
MEM_PAD(0x18); // 0x0
CSceneAnimatableObject* pSceneAnimatableObject; // 0x18
CMaterial2* pMaterial; // 0x20
CMaterial2* pMaterialCpy; // 0x28
MEM_PAD(0x10);
CObjectInfo* pObjectInfo;
MEM_PAD(0x8);
Color_t colValue;
};
class IMaterialSystem2
{
public:
CMaterial2*** FindOrCreateFromResource(CMaterial2*** pOutMaterial, const char* szMaterialName)
{
return MEM::CallVFunc<CMaterial2***, 14U>(this, pOutMaterial, szMaterialName);
}
CMaterial2** CreateMaterial(CMaterial2*** pOutMaterial, const char* szMaterialName, CMeshData* pData)
{
return MEM::CallVFunc<CMaterial2**, 29U>(this, pOutMaterial, szMaterialName, pData, 0, 0, 0, 0, 0, 1);
}
void SetCreateDataByMaterial(const void* pData, CMaterial2*** const pInMaterial)
{
return MEM::CallVFunc<void, 37U>(this, pInMaterial, pData);
}
};

View File

@@ -0,0 +1,31 @@
#pragma once
// used: mem::CallVFunc
#include "../../utilities/memory.h"
#pragma warning(push)
#pragma warning(disable : 4191)
class IMemAlloc
{
public:
void* Alloc(std::size_t nSize)
{
return MEM::CallVFunc<void*, 1>(this, nSize);
}
void* ReAlloc(const void* pMemory, std::size_t nSize)
{
return MEM::CallVFunc<void*, 2>(this, pMemory, nSize);
}
void Free(const void* pMemory)
{
return MEM::CallVFunc<void, 3>(this, pMemory);
}
std::size_t GetSize(const void* pMemory)
{
return MEM::CallVFunc<std::size_t, 21>(this, pMemory);
}
};
#pragma warning(pop)

View File

@@ -0,0 +1,34 @@
#pragma once
#include "../../utilities/memory.h"
class CNetworkGameClient
{
public:
bool IsConnected()
{
return MEM::CallVFunc<bool, 12U>(this);
}
// force game to clear cache and reset delta tick
void FullUpdate()
{
// @ida: #STR: "Requesting full game update (%s)...\n"
MEM::CallVFunc<void, 28U>(this, CS_XOR("unk"));
}
int GetDeltaTick()
{
// @ida: offset in FullUpdate();
// (nDeltaTick = -1) == FullUpdate() called
return *reinterpret_cast<int*>(reinterpret_cast<std::uintptr_t>(this) + 0x25C);
}
};
class INetworkClientService
{
public:
[[nodiscard]] CNetworkGameClient* GetNetworkGameClient()
{
return MEM::CallVFunc<CNetworkGameClient*, 23U>(this);
}
};

View File

@@ -0,0 +1,13 @@
#pragma once
// used: MEM::CallVFunc
#include "../../utilities/memory.h"
class CPVS
{
public:
void Set(bool bState)
{
MEM::CallVFunc<void*, 7U>(this, bState);
}
};

View File

@@ -0,0 +1,24 @@
#pragma once
// used: callvfunc
#include "../../utilities/memory.h"
struct ResourceBinding_t;
class IResourceSystem
{
public:
void* QueryInterface(const char* szInterfaceName)
{
return MEM::CallVFunc<void*, 2U>(this, szInterfaceName);
}
};
class CResourceHandleUtils
{
public:
void DeleteResource(const ResourceBinding_t* pBinding)
{
MEM::CallVFunc<void, 2U>(this, pBinding);
}
};

View File

@@ -0,0 +1,208 @@
#pragma once
// used: utlthash
#include "../datatypes/utlthash.h"
// used: utlvector
#include "../datatypes/utlvector.h"
// used: callvfunc
#include "../../utilities/memory.h"
#define SCHEMASYSTEM_TYPE_SCOPES_OFFSET 0x188
#define SCHEMASYSTEMTYPESCOPE_OFF1 0x3F8
#define SCHEMASYSTEMTYPESCOPE_OFF2 0x8
using SchemaString_t = const char*;
struct SchemaMetadataEntryData_t;
class CSchemaSystemTypeScope;
class CSchemaType;
struct CSchemaClassBinding
{
CSchemaClassBinding* pParent;
const char* szBinaryName; // ex: C_World
const char* szModuleName; // ex: libclient.so
const char* szClassName; // ex: client
void* pClassInfoOldSynthesized;
void* pClassInfo;
void* pThisModuleBindingPointer;
CSchemaType* pSchemaType;
};
class CSchemaType
{
public:
bool GetSizes(int* pOutSize, uint8_t* unkPtr)
{
return MEM::CallVFunc<bool, 3U>(this, pOutSize, unkPtr);
}
public:
bool GetSize(int* out_size)
{
uint8_t smh = 0;
return GetSizes(out_size, &smh);
}
public:
void* pVtable; // 0x0000
const char* szName; // 0x0008
CSchemaSystemTypeScope* pSystemTypeScope; // 0x0010
uint8_t nTypeCategory; // ETypeCategory 0x0018
uint8_t nAatomicCategory; // EAtomicCategory 0x0019
};
struct SchemaClassFieldData_t
{
SchemaString_t szName; // 0x0000
CSchemaType* pSchemaType; // 0x0008
std::uint32_t nSingleInheritanceOffset; // 0x0010
std::int32_t nMetadataSize; // 0x0014
SchemaMetadataEntryData_t* pMetaData; // 0x0018
};
struct SchemaClassInfoData_t;
struct SchemaBaseClassInfoData_t
{
int32_t nOffset;
SchemaClassInfoData_t* pClass;
};
struct SchemaClassInfoData_t
{
private:
void* pVtable; // 0x0000
public:
const char* szName; // 0x0008
char* szDescription; // 0x0010
int m_nSize; // 0x0018
std::int16_t nFieldSize; // 0x001C
std::int16_t nStaticSize; // 0x001E
std::int16_t nMetadataSize; // 0x0020
std::uint8_t nAlignOf; // 0x0022
std::uint8_t nBaseClassesCount; // 0x0023
char pad2[0x4]; // 0x0024
SchemaClassFieldData_t* pFields; // 0x0028
char pad3[0x8]; // 0x0030
SchemaBaseClassInfoData_t* pBaseClasses; // 0x0038
char pad4[0x28]; // 0x0040
//public:
//SchemaClassFieldData_t* pFields; // 0x0028
bool InheritsFrom(SchemaClassInfoData_t* pClassInfo)
{
if (pClassInfo == this && pClassInfo != nullptr)
return true;
else if (pBaseClasses == nullptr || pClassInfo == nullptr)
return false;
for (int i = 0; i < nBaseClassesCount; i++)
{
auto& baseClass = pBaseClasses[i];
if (baseClass.pClass->InheritsFrom(pClassInfo))
return true;
}
return false;
}
};
struct SchemaEnumeratorInfoData_t
{
SchemaString_t szName;
union
{
unsigned char value_char;
unsigned short value_short;
unsigned int value_int;
unsigned long long value;
};
MEM_PAD(0x10); // 0x0010
};
class CSchemaEnumInfo
{
public:
SchemaEnumeratorInfoData_t enumInfoData;
};
class CSchemaEnumBinding
{
public:
virtual const char* GetBindingName() = 0;
virtual CSchemaClassBinding* AsClassBinding() = 0;
virtual CSchemaEnumBinding* AsEnumBinding() = 0;
virtual const char* GetBinaryName() = 0;
virtual const char* GetProjectName() = 0;
public:
char* szBindingName_; // 0x0008
char* szDllName_; // 0x0010
std::int8_t nAlign_; // 0x0018
MEM_PAD(0x3); // 0x0019
std::int16_t nSize_; // 0x001C
std::int16_t nFlags_; // 0x001E
SchemaEnumeratorInfoData_t* pEnumInfo_;
MEM_PAD(0x8); // 0x0028
CSchemaSystemTypeScope* pTypeScope_; // 0x0030
MEM_PAD(0x8); // 0x0038
std::int32_t unk1_; // 0x0040
};
class CSchemaSystemTypeScope
{
public:
void FindDeclaredClass(SchemaClassInfoData_t** pReturnClass, const char* szClassName)
{
return MEM::CallVFunc<void, 2U>(this, pReturnClass, szClassName);
}
CSchemaType* FindSchemaTypeByName(const char* szName, std::uintptr_t* pSchema)
{
return MEM::CallVFunc<CSchemaType*, 4U>(this, szName, pSchema);
}
CSchemaType* FindTypeDeclaredClass(const char* szName)
{
return MEM::CallVFunc<CSchemaType*, 5U>(this, szName);
}
CSchemaType* FindTypeDeclaredEnum(const char* szName)
{
return MEM::CallVFunc<CSchemaType*, 6U>(this, szName);
}
CSchemaClassBinding* FindRawClassBinding(const char* szName)
{
return MEM::CallVFunc<CSchemaClassBinding*, 7U>(this, szName);
}
void* pVtable; // 0x0000
char szName[256U]; // 0x0008
MEM_PAD(SCHEMASYSTEMTYPESCOPE_OFF1); // 0x0108
CUtlTSHash<CSchemaClassBinding*, 256, unsigned int> hashClasses; // 0x0588
MEM_PAD(SCHEMASYSTEMTYPESCOPE_OFF2); // 0x05C8
CUtlTSHash<CSchemaEnumBinding*, 256, unsigned int> hashEnumes; // 0x2DD0
};
class ISchemaSystem
{
public:
CSchemaSystemTypeScope* FindTypeScopeForModule(const char* m_module_name)
{
return MEM::CallVFunc<CSchemaSystemTypeScope*, 13U>(this, m_module_name, nullptr);
}
private:
MEM_PAD(SCHEMASYSTEM_TYPE_SCOPES_OFFSET); // 0x0000
public:
// table of type scopes
CUtlVector<CSchemaSystemTypeScope*> vecTypeScopes; // SCHEMASYSTEM_TYPE_SCOPES_OFFSET
};

View File

@@ -0,0 +1,13 @@
#pragma once
// used: call virtual function
#include "../../utilities/memory.h"
// forward declarations
struct IDXGISwapChain;
class ISwapChainDx11
{
MEM_PAD(0x170);
IDXGISwapChain* pDXGISwapChain;
};

View File

@@ -0,0 +1,19 @@
#pragma once
#include "../datatypes/qangle.h"
#include "../datatypes/matrix.h"
class IViewRender
{
public:
Vector_t vecOrigin; // 0x0000
QAngle_t vecAngles; // 0x000C
float flFov; // 0x0018
char pad_0x001C[0x14]; // 0x001C
ViewMatrix_t matUNK1; // 0x0030
char pad_0x0070[0x30]; // 0x0070
ViewMatrix_t matUNK2; // 0x00A0
char pad_0x00E0[0xC8]; // 0x00E0
ViewMatrix_t matUNK3; // 0x01A8
char pad_0x01E8[0x28]; // 0x01E8
};

View File

@@ -0,0 +1,48 @@
#pragma once
// used: schema field
#include "../core/schema.h"
// used: rop
#include "../utilities/memory.h"
using CFiringModeFloat = std::float_t[2];
using CSkillFloat = std::float_t[4];
class CBasePlayerVData
{
public:
CS_CLASS_NO_INITIALIZER(CBasePlayerVData);
//CResourceNameTyped< CWeakHandle< InfoForResourceTypeCModel > > m_sModelName = 0x28
//CSkillFloat m_flHeadDamageMultiplier = 0x108
//CSkillFloat m_flChestDamageMultiplier = 0x118
//CSkillFloat m_flStomachDamageMultiplier = 0x128
//CSkillFloat m_flArmDamageMultiplier = 0x138
//CSkillFloat m_flLegDamageMultiplier = 0x148
//float32 m_flHoldBreathTime = 0x158
//float32 m_flDrowningDamageInterval = 0x15C
//int32 m_nDrowningDamageInitial = 0x160
//int32 m_nDrowningDamageMax = 0x164
//int32 m_nWaterSpeed = 0x168
//float32 m_flUseRange = 0x16C
//float32 m_flUseAngleTolerance = 0x170
//float32 m_flCrouchTime = 0x174
};
class CBasePlayerWeaponVData
{
public:
CS_CLASS_NO_INITIALIZER(CBasePlayerWeaponVData);
SCHEMA_ADD_FIELD(bool, IsFullAuto, "CBasePlayerWeaponVData->m_bIsFullAuto");
SCHEMA_ADD_FIELD(std::int32_t, GetMaxClip1, "CBasePlayerWeaponVData->m_iMaxClip1");
};
class CCSWeaponBaseVData : public CBasePlayerWeaponVData
{
public:
CS_CLASS_NO_INITIALIZER(CCSWeaponBaseVData);
SCHEMA_ADD_FIELD(std::int32_t, GetWeaponType, "CCSWeaponBaseVData->m_WeaponType");
SCHEMA_ADD_FIELD(float, GetRange, "CCSWeaponBaseVData->m_flRange");
};