фыв
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
#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 : int
|
||||
{
|
||||
MOVETYPE_NONE = 0,
|
||||
MOVETYPE_ISOMETRIC,
|
||||
MOVETYPE_WALK,
|
||||
MOVETYPE_STEP,
|
||||
MOVETYPE_FLY, // no gravity, but still collides with stuff
|
||||
MOVETYPE_FLYGRAVITY, // flies through the air and is affected by gravity
|
||||
MOVETYPE_VPHYSICS,
|
||||
MOVETYPE_PUSH, // no clip to world, push and crush
|
||||
MOVETYPE_NOCLIP, // no gravity, no collisions, still do velocity/absvelocity
|
||||
MOVETYPE_LADDER,
|
||||
MOVETYPE_OBSERVER, // observer movement, depends on player's observer mode
|
||||
MOVETYPE_CUSTOM,
|
||||
MOVETYPE_LAST = MOVETYPE_CUSTOM,
|
||||
MOVETYPE_MAX_BITS = 4
|
||||
};
|
||||
|
||||
// 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
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#include "K3V.h"
|
||||
#include "../../utilities/memory.h"
|
||||
// sig 1:48 8B C4 55 48 8D A8 08 FD
|
||||
/*
|
||||
KeyValues3* KeyValues3::set_type(kv_basic_type a1, kv_basic_type a2)
|
||||
{
|
||||
using fnTypeData = KeyValues3*(__fastcall*)(uint8_t, uint8_t);
|
||||
static auto setType = *reinterpret_cast<fnTypeData*>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 8B C4 55 48 8D A8 08 FD")));
|
||||
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(setType != nullptr);
|
||||
#endif
|
||||
|
||||
return setType(a1, a2);
|
||||
}
|
||||
|
||||
//48 89 5C 24 08 48 89 74 24 10 57 48 81 EC E0 00 00 00 48
|
||||
KeyValues3* KeyValues3::create_object(const char* name, bool unk1)
|
||||
{
|
||||
|
||||
// Assuming that MEM::FindPattern returns the function address correctly
|
||||
using CreateObjectFn = KeyValues3*(__fastcall*)(const char*, bool);
|
||||
static CreateObjectFn createObjectFn = *reinterpret_cast<CreateObjectFn*>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 08 48 89 74 24 10 57 48 81 EC E0 00 00 00 48")));
|
||||
CS_ASSERT(createObjectFn != nullptr);
|
||||
|
||||
return createObjectFn(name, unk1);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
//client.dll 48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC 30 0F B6 01 45 0F B6 F9 8B 2A 4D 8B E0 4C 8B 72 08 48 8B F9
|
||||
void KeyValues3::set_data(const char* name, const char* value, kv_field_type_t field)
|
||||
{
|
||||
using fnSetData = void(__fastcall*)(void*, const char*, const char*, kv_field_type_t);
|
||||
static auto setData = reinterpret_cast<fnSetData>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC 30 0F B6 01 45 0F B6 F9 8B 2A 4D 8B E0 4C 8B 72 08 48 8B F9")));
|
||||
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(setData != nullptr);
|
||||
#endif
|
||||
|
||||
setData(this, name, value, field);
|
||||
}
|
||||
|
||||
void KeyValues3::set_data(const char* name, uint32_t color)
|
||||
{
|
||||
using fnSetData = void(__fastcall*)(void*, const char*, uint32_t);
|
||||
static auto setData = reinterpret_cast<fnSetData>(MEM::FindPattern(PARTICLES_DLL, CS_XOR("E8 ?? ?? ?? ?? 49 C1 E5 21")));
|
||||
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(setData != nullptr);
|
||||
#endif
|
||||
|
||||
setData(this, name, color);
|
||||
}
|
||||
|
||||
void KeyValues3::set_data(const char* name, int value)
|
||||
{
|
||||
using fnSetData = void(__fastcall*)(void*, const char*, int);
|
||||
static auto setData = reinterpret_cast<fnSetData>(MEM::FindPattern(CLIENT_DLL, CS_XOR("")));
|
||||
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(setData != nullptr);
|
||||
#endif
|
||||
|
||||
setData(this, name, value);
|
||||
}
|
||||
|
||||
bool KeyValues3::load_from_buffer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <tchar.h>
|
||||
#include <wchar.h>
|
||||
#include <stdint.h>
|
||||
#include "../cstrike/common.h"
|
||||
#include <cstddef>
|
||||
class CKeyValues3
|
||||
{
|
||||
public:
|
||||
uint64_t uKey;
|
||||
void* pValue;
|
||||
|
||||
std::byte pad[0x8];
|
||||
};
|
||||
|
||||
struct KV3IVD_t
|
||||
{
|
||||
const char* szName;
|
||||
uint64_t unk0;
|
||||
uint64_t unk1;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#define CORRECT_PATH_SEPARATOR '\\'
|
||||
#define CORRECT_PATH_SEPARATOR_S "\\"
|
||||
#define INCORRECT_PATH_SEPARATOR '/'
|
||||
#define INCORRECT_PATH_SEPARATOR_S "/"
|
||||
#define CHARACTERS_WHICH_SEPARATE_DIRECTORY_COMPONENTS_IN_PATHNAMES ":/\\"
|
||||
#define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
|
||||
#
|
||||
|
||||
#define COPY_ALL_CHARACTERS -1
|
||||
|
||||
/// Faster conversion of an ascii char to upper case. This function does not obey locale or any language
|
||||
/// setting. It should not be used to convert characters for printing, but it is a better choice
|
||||
/// for internal strings such as used for hash table keys, etc. It's meant to be inlined and used
|
||||
/// in places like the various dictionary classes. Not obeying locale also protects you from things
|
||||
/// like your hash values being different depending on the locale setting.
|
||||
#define FastASCIIToUpper( c ) ( ( ( (c) >= 'a' ) && ( (c) <= 'z' ) ) ? ( (c) - 32 ) : (c) )
|
||||
/// similar to FastASCIIToLower
|
||||
#define FastASCIIToLower( c ) ( ( ( (c) >= 'A' ) && ( (c) <= 'Z' ) ) ? ( (c) + 32 ) : (c) )
|
||||
|
||||
#define V_vsnprintf vsnprintf
|
||||
#define V_snprintf snprintf
|
||||
#define V_strlower _strlwr
|
||||
#define V_strlen strlen
|
||||
#define V_strncat strncat
|
||||
#define V_stricmp _stricmp
|
||||
#define V_strnicmp _strnicmp
|
||||
#define V_strcmp strcmp
|
||||
#define V_strncmp strncmp
|
||||
#define V_strstr strstr
|
||||
#define V_strncpy strncpy
|
||||
#define V_strdup _strdup
|
||||
#define V_strcat strcat
|
||||
|
||||
#define Q_vsnprintf V_vsnprintf
|
||||
#define Q_snprintf V_snprintf
|
||||
#define Q_strlower V_strlower
|
||||
#define Q_strlen V_strlen
|
||||
#define Q_strncat V_strncat
|
||||
#define Q_strnistr V_strnistr
|
||||
#define Q_stricmp V_stricmp
|
||||
#define Q_strnicmp V_strnicmp
|
||||
#define Q_strncasecmp V_strnicmp
|
||||
#define Q_strcasecmp V_stricmp
|
||||
#define Q_strcmp V_strcmp
|
||||
#define Q_strncmp V_strncmp
|
||||
#define Q_strstr V_strstr
|
||||
#define Q_strncpy V_strncpy
|
||||
#define Q_strdup V_strdup
|
||||
#define Q_strcat V_strcat
|
||||
|
||||
template <size_t maxLenInCharacters> int V_vsprintf_safe(char(&pDest)[maxLenInCharacters], const char* pFormat, va_list params) { return V_vsnprintf(pDest, maxLenInCharacters, pFormat, params); }
|
||||
|
||||
|
||||
char const* V_stristr(char const* pStr, char const* pSearch);
|
||||
const char* V_strnistr(const char* pStr, const char* pSearch, size_t n);
|
||||
const char* V_strnchr(const char* pStr, char c, size_t n);
|
||||
bool V_isspace(int c);
|
||||
|
||||
// Strip white space at the beginning and end of a string
|
||||
size_t V_StrTrim(char* pStr);
|
||||
|
||||
int V_UTF8ToUnicode(const char* pUTF8, wchar_t* pwchDest, int cubDestSizeInBytes);
|
||||
int V_UnicodeToUTF8(const wchar_t* pUnicode, char* pUTF8, int cubDestSizeInBytes);
|
||||
|
||||
int V_UTF8CharLength(const unsigned char input);
|
||||
bool V_IsValidUTF8(const char* pszString);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PATTERN_NONE = 0x00000000,
|
||||
PATTERN_DIRECTORY = 0x00000001
|
||||
} TStringPattern;
|
||||
|
||||
// String matching using wildcards (*) for partial matches.
|
||||
bool V_StringMatchesPattern(const char* szString, const char* szPattern, int flags = 0);
|
||||
|
||||
bool V_ComparePath(const char* a, const char* b);
|
||||
|
||||
void V_FixSlashes(char* pname, char separator = CORRECT_PATH_SEPARATOR);
|
||||
|
||||
// Adds a path separator to the end of the string if there isn't one already and the string is not empty.
|
||||
// Triggers a fatal error if it would run out of space.
|
||||
void V_AppendSlash(char* pStr, size_t strSize, char separator = CORRECT_PATH_SEPARATOR);
|
||||
|
||||
// Remove the final characters of ppath if it's '\' or '/'.
|
||||
void V_StripTrailingSlash(char* ppath);
|
||||
|
||||
// This removes "./" and "../" from the pathname. pFilename should be a full pathname.
|
||||
// Returns false if it tries to ".." past the root directory in the drive (in which case
|
||||
// it is an invalid path).
|
||||
bool V_RemoveDotSlashes(char* pFilename, char separator = CORRECT_PATH_SEPARATOR);
|
||||
|
||||
// Returns true if the path could be normalized.
|
||||
bool V_NormalizePath(char* pfilePath, char separator);
|
||||
|
||||
// Returns true if the path is an absolute path.
|
||||
bool V_IsAbsolutePath(const char* pPath);
|
||||
|
||||
// Returns true if the path is valid.
|
||||
bool V_IsValidPath(const char* pStr);
|
||||
|
||||
// If pPath is a relative path, this function makes it into an absolute path
|
||||
// using the current working directory as the base, or pStartingDir if it's non-NULL.
|
||||
// Returns false if it runs out of room in the string, or if pPath tries to ".." past the root directory.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
bool
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
V_MakeAbsolutePath(char* pOut, size_t outLen, const char* pPath, const char* pStartingDir = NULL);
|
||||
inline void V_MakeAbsolutePath(char* pOut, size_t outLen, const char* pPath, const char* pStartingDir, bool bLowercaseName)
|
||||
{
|
||||
V_MakeAbsolutePath(pOut, outLen, pPath, pStartingDir);
|
||||
if (bLowercaseName)
|
||||
{
|
||||
V_strlower(pOut);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the final directory from the path
|
||||
size_t V_StripLastDir(char* dirName, size_t maxLen);
|
||||
// Returns a pointer to the unqualified file name (no path) of a file name
|
||||
const char* V_UnqualifiedFileName(const char* in);
|
||||
// Given a path and a filename, composes "path\filename", inserting the (OS correct) separator if necessary
|
||||
void V_ComposeFileName(const char* path, const char* filename, char* dest, size_t destSize);
|
||||
|
||||
// Remove any extension from in and return resulting string in out
|
||||
void V_StripExtension(const char* in, char* out, size_t outLen);
|
||||
|
||||
// Copy out the file extension into dest
|
||||
void V_ExtractFileExtension(const char* path, char* dest, size_t destSize);
|
||||
|
||||
// Returns a pointer to the file extension or NULL if one doesn't exist
|
||||
const char* V_GetFileExtension(const char* path);
|
||||
|
||||
// Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator)
|
||||
void V_FileBase(const char* in, char* out, size_t maxlen);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: All of our code is completely Unicode. Instead of char, you should
|
||||
// use wchar, uint8, or char8, as explained below.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#ifndef WCHARTYPES_H
|
||||
#define WCHARTYPES_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef _INC_TCHAR
|
||||
#error ("Must include tier0 type headers before tchar.h")
|
||||
#endif
|
||||
|
||||
// Temporarily turn off Valve defines
|
||||
|
||||
|
||||
#if !defined(_WCHAR_T_DEFINED) && !defined( __WCHAR_TYPE__ ) && !defined(GNUC)
|
||||
typedef unsigned short wchar_t;
|
||||
#define _WCHAR_T_DEFINED
|
||||
#endif
|
||||
|
||||
// char8
|
||||
// char8 is equivalent to char, and should be used when you really need a char
|
||||
// (for example, when calling an external function that's declared to take
|
||||
// chars).
|
||||
typedef char char8;
|
||||
|
||||
// uint8
|
||||
// uint8 is equivalent to byte (but is preferred over byte for clarity). Use this
|
||||
// whenever you mean a byte (for example, one byte of a network packet).
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned char byte;
|
||||
|
||||
// wchar
|
||||
// wchar is a single character of text (currently 16 bits, as all of our text is
|
||||
// Unicode). Use this whenever you mean a piece of text (for example, in a string).
|
||||
typedef wchar_t wchar;
|
||||
//typedef char wchar;
|
||||
|
||||
// __WFILE__
|
||||
// This is a Unicode version of __FILE__
|
||||
#define WIDEN2(x) L ## x
|
||||
#define WIDEN(x) WIDEN2(x)
|
||||
#define __WFILE__ WIDEN(__FILE__)
|
||||
|
||||
#ifdef STEAM
|
||||
#ifndef _UNICODE
|
||||
#define FORCED_UNICODE
|
||||
#endif
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#if defined( POSIX )
|
||||
#define _tcsstr strstr
|
||||
#define _tcsicmp stricmp
|
||||
#define _tcscmp strcmp
|
||||
#define _tcscpy strcpy
|
||||
#define _tcsncpy strncpy
|
||||
#define _tcsrchr strrchr
|
||||
#define _tcslen strlen
|
||||
#define _tfopen fopen
|
||||
#define _stprintf sprintf
|
||||
#define _ftprintf fprintf
|
||||
#define _vsntprintf _vsnprintf
|
||||
#define _tprintf printf
|
||||
#define _sntprintf _snprintf
|
||||
#define _T(s) s
|
||||
#else
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#if defined(_UNICODE)
|
||||
typedef wchar tchar;
|
||||
#define tstring wstring
|
||||
#define __TFILE__ __WFILE__
|
||||
#define TCHAR_IS_WCHAR
|
||||
#else
|
||||
typedef char tchar;
|
||||
#define tstring string
|
||||
#define __TFILE__ __FILE__
|
||||
#define TCHAR_IS_CHAR
|
||||
#endif
|
||||
|
||||
#ifdef FORCED_UNICODE
|
||||
#undef _UNICODE
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) || defined( WIN32 )
|
||||
typedef wchar_t uchar16;
|
||||
typedef unsigned int uchar32;
|
||||
#else
|
||||
typedef unsigned short uchar16;
|
||||
typedef wchar_t uchar32;
|
||||
#endif
|
||||
|
||||
#ifdef GNUC
|
||||
typedef unsigned short ucs2; // wchar_t is 4 bytes on sane os's, specially define a ucs2 type so we can read out localization files and the list saved as 2 byte wchar (or ucs16 Matt tells me)
|
||||
#elif defined(_MSC_VER)
|
||||
typedef wchar_t ucs2; // under windows wchar_t is ucs2
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // WCHARTYPES
|
||||
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
//========= Copyright <20> 1996-2006, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Low level byte swapping routines.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
#ifndef BYTESWAP_H
|
||||
#define BYTESWAP_H
|
||||
#if defined(_WIN32)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "datamap.h" // needed for typedescription_t. note datamap.h is tier1 as well.
|
||||
|
||||
class CByteSwap
|
||||
{
|
||||
public:
|
||||
CByteSwap()
|
||||
{
|
||||
// Default behavior sets the target endian to match the machine native endian (no swap).
|
||||
SetTargetBigEndian(IsMachineBigEndian());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Write a single field.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SwapFieldToTargetEndian(void* pOutputBuffer, void* pData, typedescription_t* pField);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Write a block of fields. Works a bit like the saverestore code.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SwapFieldsToTargetEndian(void* pOutputBuffer, void* pBaseData, datamap_t* pDataMap);
|
||||
|
||||
// Swaps fields for the templated type to the output buffer.
|
||||
template<typename T> inline void SwapFieldsToTargetEndian(T* pOutputBuffer, void* pBaseData, unsigned int objectCount = 1)
|
||||
{
|
||||
for (unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer)
|
||||
{
|
||||
SwapFieldsToTargetEndian((void*)pOutputBuffer, pBaseData, &T::m_DataMap);
|
||||
pBaseData = pBaseData + sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
// Swaps fields for the templated type in place.
|
||||
template<typename T> inline void SwapFieldsToTargetEndian(T* pOutputBuffer, unsigned int objectCount = 1)
|
||||
{
|
||||
SwapFieldsToTargetEndian<T>(pOutputBuffer, (void*)pOutputBuffer, objectCount);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// True if the current machine is detected as big endian.
|
||||
// (Endianness is effectively detected at compile time when optimizations are
|
||||
// enabled)
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool IsMachineBigEndian()
|
||||
{
|
||||
short nIsBigEndian = 1;
|
||||
|
||||
// if we are big endian, the first byte will be a 0, if little endian, it will be a one.
|
||||
return (bool)(0 == *(char*)&nIsBigEndian);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets the target byte ordering we are swapping to or from.
|
||||
//
|
||||
// Braindead Endian Reference:
|
||||
// x86 is LITTLE Endian
|
||||
// PowerPC is BIG Endian
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void SetTargetBigEndian(bool bigEndian)
|
||||
{
|
||||
m_bBigEndian = bigEndian;
|
||||
m_bSwapBytes = IsMachineBigEndian() != bigEndian;
|
||||
}
|
||||
|
||||
// Changes target endian
|
||||
inline void FlipTargetEndian(void)
|
||||
{
|
||||
m_bSwapBytes = !m_bSwapBytes;
|
||||
m_bBigEndian = !m_bBigEndian;
|
||||
}
|
||||
|
||||
// Forces byte swapping state, regardless of endianess
|
||||
inline void ActivateByteSwapping(bool bActivate)
|
||||
{
|
||||
SetTargetBigEndian(IsMachineBigEndian() != bActivate);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns true if the target machine is the same as this one in endianness.
|
||||
//
|
||||
// Used to determine when a byteswap needs to take place.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool IsSwappingBytes(void) // Are bytes being swapped?
|
||||
{
|
||||
return m_bSwapBytes;
|
||||
}
|
||||
|
||||
inline bool IsTargetBigEndian(void) // What is the current target endian?
|
||||
{
|
||||
return m_bBigEndian;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// IsByteSwapped()
|
||||
//
|
||||
// When supplied with a chunk of input data and a constant or magic number
|
||||
// (in native format) determines the endienness of the current machine in
|
||||
// relation to the given input data.
|
||||
//
|
||||
// Returns:
|
||||
// 1 if input is the same as nativeConstant.
|
||||
// 0 if input is byteswapped relative to nativeConstant.
|
||||
// -1 if input is not the same as nativeConstant and not byteswapped either.
|
||||
//
|
||||
// ( This is useful for detecting byteswapping in magic numbers in structure
|
||||
// headers for example. )
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> inline int SourceIsNativeEndian(T input, T nativeConstant)
|
||||
{
|
||||
// If it's the same, it isn't byteswapped:
|
||||
if (input == nativeConstant)
|
||||
return 1;
|
||||
|
||||
int output;
|
||||
LowLevelByteSwap<T>(&output, &input);
|
||||
if (output == nativeConstant)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Swaps an input buffer full of type T into the given output buffer.
|
||||
//
|
||||
// Swaps [count] items from the inputBuffer to the outputBuffer.
|
||||
// If inputBuffer is omitted or NULL, then it is assumed to be the same as
|
||||
// outputBuffer - effectively swapping the contents of the buffer in place.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> inline void SwapBuffer(T* outputBuffer, T* inputBuffer = NULL, int count = 1)
|
||||
{
|
||||
|
||||
|
||||
// Fail gracefully in release:
|
||||
if (count <= 0 || !outputBuffer)
|
||||
return;
|
||||
|
||||
// Optimization for the case when we are swapping in place.
|
||||
if (inputBuffer == NULL)
|
||||
{
|
||||
inputBuffer = outputBuffer;
|
||||
}
|
||||
|
||||
// Swap everything in the buffer:
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
LowLevelByteSwap<T>(&outputBuffer[i], &inputBuffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Swaps an input buffer full of type T into the given output buffer.
|
||||
//
|
||||
// Swaps [count] items from the inputBuffer to the outputBuffer.
|
||||
// If inputBuffer is omitted or NULL, then it is assumed to be the same as
|
||||
// outputBuffer - effectively swapping the contents of the buffer in place.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> inline void SwapBufferToTargetEndian(T* outputBuffer, T* inputBuffer = NULL, int count = 1)
|
||||
{
|
||||
|
||||
|
||||
// Fail gracefully in release:
|
||||
if (count <= 0 || !outputBuffer)
|
||||
return;
|
||||
|
||||
// Optimization for the case when we are swapping in place.
|
||||
if (inputBuffer == NULL)
|
||||
{
|
||||
inputBuffer = outputBuffer;
|
||||
}
|
||||
|
||||
// Are we already the correct endienness? ( or are we swapping 1 byte items? )
|
||||
if (!m_bSwapBytes || (sizeof(T) == 1))
|
||||
{
|
||||
// If we were just going to swap in place then return.
|
||||
if (!inputBuffer)
|
||||
return;
|
||||
|
||||
// Otherwise copy the inputBuffer to the outputBuffer:
|
||||
if (outputBuffer != inputBuffer)
|
||||
memcpy(outputBuffer, inputBuffer, count * sizeof(T));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Swap everything in the buffer:
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
LowLevelByteSwap<T>(&outputBuffer[i], &inputBuffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//-----------------------------------------------------------------------------
|
||||
// The lowest level byte swapping workhorse of doom. output always contains the
|
||||
// swapped version of input. ( Doesn't compare machine to target endianness )
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> static void LowLevelByteSwap(T* output, T* input)
|
||||
{
|
||||
T temp = *output;
|
||||
#if defined( _X360 )
|
||||
// Intrinsics need the source type to be fixed-point
|
||||
DWORD* word = (DWORD*)input;
|
||||
switch (sizeof(T))
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
__storewordbytereverse(*(word + 1), 0, &temp);
|
||||
__storewordbytereverse(*(word + 0), 4, &temp);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
__storewordbytereverse(*word, 0, &temp);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
__storeshortbytereverse(*input, 0, &temp);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
Q_memcpy(&temp, input, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
CS_ASSERT("Invalid size in CByteswap::LowLevelByteSwap" && 0);
|
||||
}
|
||||
#else
|
||||
for (unsigned int i = 0; i < sizeof(T); i++)
|
||||
{
|
||||
((unsigned char*)&temp)[i] = ((unsigned char*)input)[sizeof(T) - (i + 1)];
|
||||
}
|
||||
#endif
|
||||
memcpy(output, &temp, sizeof(T));
|
||||
}
|
||||
|
||||
#if defined( _X360 )
|
||||
// specialized for void * to get 360 XDK compile working despite changelist 281331
|
||||
//-----------------------------------------------------------------------------
|
||||
// The lowest level byte swapping workhorse of doom. output always contains the
|
||||
// swapped version of input. ( Doesn't compare machine to target endianness )
|
||||
//-----------------------------------------------------------------------------
|
||||
template<> static void LowLevelByteSwap(void** output, void** input)
|
||||
{
|
||||
CS_ASSERTMsgOnce(sizeof(void*) == sizeof(unsigned int), "void *'s on this platform are not four bytes!");
|
||||
__storewordbytereverse(*reinterpret_cast<unsigned int*>(input), 0, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int m_bSwapBytes : 1;
|
||||
unsigned int m_bBigEndian : 1;
|
||||
};
|
||||
|
||||
#endif /* !BYTESWAP_H */
|
||||
@@ -0,0 +1,108 @@
|
||||
#ifndef CS2_CHEAT_CINTERLOCKEDINT_HPP
|
||||
#define CS2_CHEAT_CINTERLOCKEDINT_HPP
|
||||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
template< std::integral tElement >
|
||||
requires( sizeof( tElement ) == sizeof( std::int32_t ) || sizeof( tElement ) == sizeof( std::int64_t ) )
|
||||
class CInterlockedIntT
|
||||
{
|
||||
public:
|
||||
constexpr CInterlockedIntT( ) noexcept
|
||||
: m_iValue( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
constexpr CInterlockedIntT( tElement iValue ) noexcept
|
||||
: m_iValue( iValue )
|
||||
{
|
||||
}
|
||||
|
||||
constexpr tElement operator( )( ) const noexcept
|
||||
{
|
||||
return m_iValue;
|
||||
}
|
||||
|
||||
constexpr operator tElement( ) const noexcept
|
||||
{
|
||||
return m_iValue;
|
||||
}
|
||||
|
||||
constexpr bool operator!( ) const noexcept
|
||||
{
|
||||
return !m_iValue;
|
||||
}
|
||||
|
||||
tElement operator++( ) noexcept
|
||||
{
|
||||
if constexpr ( sizeof( tElement ) == sizeof( std::int32_t ) )
|
||||
return static_cast< tElement >( _InterlockedIncrement( reinterpret_cast< volatile long* >( &m_iValue ) ) );
|
||||
else
|
||||
return static_cast< tElement >( _InterlockedIncrement64( reinterpret_cast< volatile long long* >( &m_iValue ) ) );
|
||||
}
|
||||
|
||||
tElement operator--( ) noexcept
|
||||
{
|
||||
if constexpr ( sizeof( tElement ) == sizeof( std::int32_t ) )
|
||||
return static_cast< tElement >( _InterlockedDecrement( reinterpret_cast< volatile long* >( &m_iValue ) ) );
|
||||
else
|
||||
return static_cast< tElement >( _InterlockedDecrement64( reinterpret_cast< volatile long long* >( &m_iValue ) ) );
|
||||
}
|
||||
|
||||
tElement operator++( int ) noexcept
|
||||
{
|
||||
return operator++( ) - 1;
|
||||
}
|
||||
|
||||
tElement operator--( int ) noexcept
|
||||
{
|
||||
return operator--( ) + 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] tElement operator+( tElement iOtherValue ) const noexcept
|
||||
{
|
||||
return m_iValue + iOtherValue;
|
||||
}
|
||||
|
||||
[[nodiscard]] tElement operator-( tElement iOtherValue ) const noexcept
|
||||
{
|
||||
return m_iValue - iOtherValue;
|
||||
}
|
||||
|
||||
void operator+=( tElement iAdd ) noexcept
|
||||
{
|
||||
if constexpr ( sizeof( tElement ) == sizeof( std::int32_t ) )
|
||||
return static_cast< tElement >( _InterlockedExchangeAdd( reinterpret_cast< volatile long* >( &m_iValue ), iAdd ) );
|
||||
else
|
||||
return static_cast< tElement >( _InterlockedExchangeAdd64( reinterpret_cast< volatile long* >( &m_iValue ), iAdd ) );
|
||||
}
|
||||
|
||||
void operator-=( tElement iSub ) noexcept
|
||||
{
|
||||
if constexpr ( sizeof( tElement ) == sizeof( std::int32_t ) )
|
||||
return static_cast< tElement >( _InterlockedExchangeSub( reinterpret_cast< volatile long* >( &m_iValue ), iSub ) );
|
||||
else
|
||||
return static_cast< tElement >( _InterlockedExchangeSub64( reinterpret_cast< volatile long* >( &m_iValue ), iSub ) );
|
||||
}
|
||||
|
||||
tElement operator=( tElement iNewValue ) noexcept
|
||||
{
|
||||
if constexpr ( sizeof( tElement ) == sizeof( std::int32_t ) )
|
||||
_InterlockedExchange( reinterpret_cast< volatile long* >( &m_iValue ), iNewValue );
|
||||
else
|
||||
_InterlockedExchange64( reinterpret_cast< volatile long long* >( &m_iValue ), iNewValue );
|
||||
|
||||
return m_iValue;
|
||||
}
|
||||
|
||||
public:
|
||||
volatile tElement m_iValue;
|
||||
};
|
||||
|
||||
using CInterlockedInt = CInterlockedIntT< std::int32_t >;
|
||||
using CInterlockedUInt = CInterlockedIntT< std::uint32_t >;
|
||||
|
||||
#endif // CS2_CHEAT_CINTERLOCKEDINT_HPP
|
||||
@@ -0,0 +1,242 @@
|
||||
#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>
|
||||
Color_t Set(const std::uint8_t nValue) const
|
||||
{
|
||||
|
||||
Color_t colCopy = *this;
|
||||
colCopy[N] = nValue;
|
||||
return colCopy;
|
||||
}
|
||||
// Method to set the alpha to the product of current alpha and an additional alpha multiplier
|
||||
uint8_t SetAlphaM(const float alphaMultiplier) const
|
||||
{
|
||||
// Make a copy of the current color
|
||||
Color_t colCopy = *this;
|
||||
|
||||
// Multiply the alpha value by the alpha multiplier
|
||||
colCopy.a = static_cast<std::uint8_t>(alphaMultiplier);
|
||||
// Return the modified color
|
||||
return colCopy.a;
|
||||
}
|
||||
|
||||
/// @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;
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
struct ResourceBinding_t {
|
||||
void* data;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CStrongHandle {
|
||||
public:
|
||||
explicit operator T* () const {
|
||||
return is_valid() ? reinterpret_cast<T*>(binding_->data) : nullptr;
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
return is_valid() ? reinterpret_cast<T*>(binding_->data) : nullptr;
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] bool is_valid() const { return binding_->data != nullptr; }
|
||||
|
||||
private:
|
||||
const ResourceBinding_t* binding_;
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#pragma once
|
||||
|
||||
typedef enum _fieldtypes
|
||||
{
|
||||
FIELD_VOID = 0, // No type or value
|
||||
FIELD_FLOAT, // Any floating point value
|
||||
FIELD_STRING, // A string ID (return from ALLOC_STRING)
|
||||
FIELD_VECTOR, // Any vector, QAngle, or AngularImpulse
|
||||
FIELD_QUATERNION, // A quaternion
|
||||
FIELD_INTEGER, // Any integer or enum
|
||||
FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression
|
||||
FIELD_SHORT, // 2 byte integer
|
||||
FIELD_CHARACTER, // a byte
|
||||
FIELD_COLOR32, // 8-bit per channel r,g,b,a (32bit color)
|
||||
FIELD_EMBEDDED, // an embedded object with a datadesc, recursively traverse and embedded class/structure based on an additional typedescription
|
||||
FIELD_CUSTOM, // special type that contains function pointers to it's read/write/parse functions
|
||||
|
||||
FIELD_CLASSPTR, // CBaseEntity*
|
||||
FIELD_EHANDLE, // Entity handle
|
||||
FIELD_EDICT, // edict_t
|
||||
|
||||
FIELD_POSITION_VECTOR, // A world coordinate (these are fixed up across level transitions automagically)
|
||||
FIELD_TIME, // a floating point time (these are fixed up automatically too!)
|
||||
FIELD_TICK, // an integer tick count( fixed up similarly to time)
|
||||
FIELD_MODELNAME, // Engine string that is a model name (needs precache)
|
||||
FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache)
|
||||
|
||||
FIELD_INPUT, // a list of inputed data fields (all derived from CMultiInputVar)
|
||||
FIELD_FUNCTION, // A class function pointer (Think, Use, etc)
|
||||
|
||||
FIELD_VMATRIX, // a vmatrix (output coords are NOT worldspace)
|
||||
|
||||
// NOTE: Use float arrays for local transformations that don't need to be fixed up.
|
||||
FIELD_VMATRIX_WORLDSPACE,// A VMatrix that maps some local space to world space (translation is fixed up on level transitions)
|
||||
FIELD_MATRIX3X4_WORLDSPACE, // matrix3x4_t that maps some local space to world space (translation is fixed up on level transitions)
|
||||
|
||||
FIELD_INTERVAL, // a start and range floating point interval ( e.g., 3.2->3.6 == 3.2 and 0.4 )
|
||||
FIELD_MODELINDEX, // a model index
|
||||
FIELD_MATERIALINDEX, // a material index (using the material precache string table)
|
||||
|
||||
FIELD_VECTOR2D, // 2 floats
|
||||
FIELD_INTEGER64, // 64bit integer
|
||||
|
||||
FIELD_VECTOR4D, // 4 floats
|
||||
|
||||
FIELD_TYPECOUNT, // MUST BE LAST
|
||||
} fieldtype_t;
|
||||
|
||||
struct datamap_t;
|
||||
struct typedescription_t;
|
||||
|
||||
// [ PIXIE ] TODO: Verify this again, been a long time since I reversed this.
|
||||
struct datamap_t
|
||||
{
|
||||
typedescription_t* dataDesc;
|
||||
int unk1;
|
||||
int unk2;
|
||||
const char* dataClassName;
|
||||
uint64_t packed_size;
|
||||
int64_t dataNumFields;
|
||||
datamap_t* baseMap;
|
||||
// Verify size.
|
||||
};
|
||||
|
||||
// [ PIXIE ] TODO: Verify this again, been a long time since I reversed this.
|
||||
struct typedescription_t
|
||||
{
|
||||
fieldtype_t fieldType;
|
||||
const char* fieldName;
|
||||
int fieldOffset;
|
||||
unsigned short fieldSize;
|
||||
short flags;
|
||||
uint64_t unk2[5];
|
||||
datamap_t* td;
|
||||
// Not full size yet.
|
||||
};
|
||||
|
||||
namespace DataMapHandler
|
||||
{
|
||||
int FindOffsetForField(datamap_t* map, const std::string& fieldName);
|
||||
typedescription_t* FindFieldInDataMap(datamap_t* map, const std::string& fieldName);
|
||||
}
|
||||
|
||||
#define DATAMAP_VAR(type, name, datamap, varname) \
|
||||
type& name() { \
|
||||
static int _##name = NetVarManager::FindOffsetForField(datamap, varname); \
|
||||
return *(type*)((std::uintptr_t)this + _##name); \
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
#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)
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
#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 = std::clamp(this->x, -89.f, 89.f);
|
||||
this->y = std::clamp(std::remainder(this->y, 360.0f), -180.f, 180.f);
|
||||
this->z = 0.f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr float DotProduct(const QAngle_t& vecDot) const
|
||||
{
|
||||
return (this->x * vecDot.x + this->y * vecDot.y + this->z * vecDot.z);
|
||||
}
|
||||
QAngle_t& ToVec3(Vector_t vec)
|
||||
{
|
||||
this->x = vec.x;
|
||||
this->y = vec.y;
|
||||
this->z = 0.f;
|
||||
this->Clamp();
|
||||
return *this;
|
||||
}
|
||||
constexpr QAngle_t& ToVec(Vector_t vec)
|
||||
{
|
||||
this->x = vec.x;
|
||||
this->y = vec.y;
|
||||
this->z = 0.f;
|
||||
this->Clamp();
|
||||
return *this;
|
||||
}
|
||||
QAngle_t& Reset()
|
||||
{
|
||||
this->x = 0.f;
|
||||
this->y = 0.f;
|
||||
this->z = 0.f;
|
||||
return *this;
|
||||
}
|
||||
[[nodiscard]] constexpr float LengthSqr() const
|
||||
{
|
||||
return DotProduct(*this);
|
||||
}
|
||||
[[nodiscard]] float Length() const
|
||||
{
|
||||
return std::sqrtf(this->LengthSqr());
|
||||
}
|
||||
/// 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;
|
||||
}
|
||||
void normalize() {
|
||||
while (this->y > 180.f) this->y -= 360.f;
|
||||
while (this->y < -180.f) this->y += 360.f;
|
||||
|
||||
this->x = std::min(std::max(this->x, -89.f), 89.f);
|
||||
this->z = 0.f;
|
||||
}
|
||||
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;
|
||||
}
|
||||
QAngle_t Normalizes() const
|
||||
{
|
||||
QAngle_t vecOut = *this;
|
||||
vecOut.NormalizeInPlace();
|
||||
return vecOut;
|
||||
}
|
||||
|
||||
|
||||
/// 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;
|
||||
};
|
||||
@@ -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);
|
||||
@@ -0,0 +1 @@
|
||||
#pragma once
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "utlstring.h"
|
||||
#include "cinterlockedint.hpp"
|
||||
|
||||
enum EResourceBindingFlags
|
||||
{
|
||||
RESOURCE_BINDING_CACHED = 0x1,
|
||||
RESOURCE_BINDING_ERROR = 0x2,
|
||||
RESOURCE_BINDING_PERMANENT = 0x4,
|
||||
RESOURCE_BINDING_ANONYMOUS = 0x8,
|
||||
};
|
||||
|
||||
struct ResourceBindingBase_t
|
||||
{
|
||||
void* pData = nullptr;
|
||||
CUtlString* pResourceName = nullptr;
|
||||
std::uint32_t uFlags = 0;
|
||||
std::uint8_t uResourceType = -1;
|
||||
CInterlockedIntT< std::uint32_t > uRefCount = 0;
|
||||
};
|
||||
|
||||
template< typename tResource >
|
||||
struct ResourceBinding_t
|
||||
: public ResourceBindingBase_t
|
||||
{
|
||||
template< class tValue >
|
||||
friend class CStrongHandle;
|
||||
|
||||
template< class tValue >
|
||||
friend int ResourceAddRef( const ResourceBinding_t< tValue >* pResource ) noexcept;
|
||||
|
||||
template< class tValue >
|
||||
friend int ResourceRelease( const ResourceBinding_t< tValue >* pResource ) noexcept;
|
||||
};
|
||||
|
||||
template< class tValue >
|
||||
int ResourceAddRef( const ResourceBinding_t< tValue >* pResource ) noexcept
|
||||
{
|
||||
return ++pResource->uRefCount;
|
||||
}
|
||||
|
||||
template< class tValue >
|
||||
int ResourceRelease( const ResourceBinding_t< tValue >* pResource ) noexcept
|
||||
{
|
||||
return --pResource->uRefCount;
|
||||
}
|
||||
|
||||
using ResourceHandle_t = ResourceBindingBase_t*;
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
struct Resource_t
|
||||
{
|
||||
void* pData;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class stronghandle
|
||||
{
|
||||
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 Resource_t* pBinding;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
@@ -0,0 +1,245 @@
|
||||
#pragma once
|
||||
|
||||
template <typename T>
|
||||
struct RepeatedPtrField_t
|
||||
{
|
||||
struct Rep_t
|
||||
{
|
||||
int m_nAllocatedSize; // 0x0
|
||||
T* m_tElements[(std::numeric_limits<int>::max() - 2 * sizeof(int)) / sizeof(void*)]; // 0x8
|
||||
};
|
||||
|
||||
uint64_t unk_field_;
|
||||
int m_nCurrentSize; // 0x18
|
||||
int m_nTotalSize; // 0x1C
|
||||
Rep_t* m_pRep; // 0x20
|
||||
|
||||
template<class T>
|
||||
inline T* add(T* element)
|
||||
{
|
||||
static const auto sub_C92EF0 = MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 ? 57 48 83 EC ? 48 8B D9 48 8B FA 48 8B 49 ? 48 85 C9 74 ? 8B 01"));
|
||||
return reinterpret_cast<T * (__fastcall*)(RepeatedPtrField_t*, T*)>(sub_C92EF0)(this, element);
|
||||
}
|
||||
|
||||
inline uint64_t unk_field() {
|
||||
return unk_field_;
|
||||
}
|
||||
|
||||
inline int& size() {
|
||||
return m_nCurrentSize;
|
||||
}
|
||||
|
||||
inline int& max_size() {
|
||||
return m_pRep->m_nAllocatedSize;
|
||||
}
|
||||
|
||||
inline T*& operator[](int i) {
|
||||
return m_pRep->m_tElements[i];
|
||||
}
|
||||
|
||||
inline operator bool() {
|
||||
return m_pRep != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// @source: master/game/shared/in_buttons.h
|
||||
enum ECommandButtons : int
|
||||
{
|
||||
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_CANCEL = (1 << 6),
|
||||
IN_LEFT = (1 << 7),
|
||||
IN_RIGHT = (1 << 8),
|
||||
IN_MOVELEFT = (1 << 9),
|
||||
IN_MOVERIGHT = (1 << 10),
|
||||
IN_SECOND_ATTACK = (1 << 11),
|
||||
IN_RUN = (1 << 12),
|
||||
IN_RELOAD = (1 << 13),
|
||||
IN_LEFT_ALT = (1 << 14),
|
||||
IN_RIGHT_ALT = (1 << 15),
|
||||
IN_SCORE = (1 << 16),
|
||||
IN_SPEED = (1 << 17),
|
||||
IN_WALK = (1 << 18),
|
||||
IN_ZOOM = (1 << 19),
|
||||
IN_FIRST_WEAPON = (1 << 20),
|
||||
IN_SECOND_WEAPON = (1 << 21),
|
||||
IN_BULLRUSH = (1 << 22),
|
||||
IN_FIRST_GRENADE = (1 << 23),
|
||||
IN_SECOND_GRENADE = (1 << 24),
|
||||
IN_MIDDLE_ATTACK = (1 << 25),
|
||||
IN_USE_OR_RELOAD = (1 << 26)
|
||||
};
|
||||
|
||||
class CBasePB
|
||||
{
|
||||
public:
|
||||
void* pVTable; // 0x0
|
||||
std::uint32_t m_nHasBits; // 0x8
|
||||
std::uint64_t m_nCachedBits; // 0xC
|
||||
};
|
||||
static_assert(sizeof(CBasePB) == 0x18);
|
||||
|
||||
class CMsgQAngle : public CBasePB
|
||||
{
|
||||
public:
|
||||
QAngle_t m_angValue; // 0x18
|
||||
};
|
||||
|
||||
class CMsgVector : public CBasePB
|
||||
{
|
||||
public:
|
||||
Vector4D_t m_vecValue; // 0x18
|
||||
};
|
||||
|
||||
class CCSGOInterpolationInfoPB : public CBasePB
|
||||
{
|
||||
public:
|
||||
float m_flFraction; // 0x18
|
||||
int m_nSrcTick; // 0x1C
|
||||
int m_nDstTick; // 0x20
|
||||
};
|
||||
|
||||
class CCSGOInputHistoryEntryPB : public CBasePB
|
||||
{
|
||||
public:
|
||||
CMsgQAngle* m_pViewCmd; // 0x18
|
||||
CMsgVector* m_pShootOriginCmd; // 0x20
|
||||
CMsgVector* m_pTargetHeadOriginCmd; // 0x28
|
||||
CMsgVector* m_pTargetAbsOriginCmd; // 0x30
|
||||
CMsgQAngle* m_pTargetViewCmd; // 0x38
|
||||
CCSGOInterpolationInfoPB* m_cl_interp; // 0x40
|
||||
CCSGOInterpolationInfoPB* m_sv_interp0; // 0x48
|
||||
CCSGOInterpolationInfoPB* m_sv_interp1; // 0x50
|
||||
CCSGOInterpolationInfoPB* m_player_interp; // 0x58
|
||||
int m_nRenderTickCount; // 0x60
|
||||
float m_flRenderTickFraction; // 0x64
|
||||
int m_nPlayerTickCount; // 0x68
|
||||
float m_flPlayerTickFraction; // 0x6C
|
||||
int m_nFrameNumber; // 0x70
|
||||
int m_nTargetEntIndex; // 0x74
|
||||
};
|
||||
|
||||
struct CInButtonStatePB : CBasePB
|
||||
{
|
||||
uint64_t m_nValue; // 0x18
|
||||
uint64_t m_nValueChanged; // 0x20
|
||||
uint64_t m_nValueScroll; // 0x28
|
||||
};
|
||||
static_assert(sizeof(CInButtonStatePB) == 0x30);
|
||||
|
||||
struct CSubtickMoveStep : CBasePB
|
||||
{
|
||||
uint64_t nButton; // 0x18
|
||||
bool bPressed; // 0x20
|
||||
float flWhen; // 0x24
|
||||
float flAnalogForwardDelta; // 0x28
|
||||
float flAnalogLeftDelta; // 0x2C
|
||||
};
|
||||
|
||||
|
||||
class CBaseUserCmdPB : public CBasePB
|
||||
{
|
||||
public:
|
||||
RepeatedPtrField_t<CSubtickMoveStep> m_subtickMovesField; // 0x18
|
||||
const char* m_szMoveCrc; // 0x20
|
||||
CInButtonStatePB* m_pInButtonState; // 0x28
|
||||
CMsgQAngle* m_pViewangles; // 0x30
|
||||
int32_t m_nCommandNumber; // 0x38
|
||||
int32_t m_nTickCount; // 0x3C
|
||||
float m_flForwardMove; // 0x40
|
||||
float m_flSideMove; // 0x44
|
||||
float m_flUpMove; // 0x48
|
||||
int32_t m_nImpulse; // 0x4C
|
||||
int32_t m_nWeaponSelect; // 0x50
|
||||
int32_t m_nRandomSeed; // 0x54
|
||||
int32_t m_nMousedX; // 0x58
|
||||
int32_t m_nMousedY; // 0x5C
|
||||
uint32_t m_nConsumedServerAngleChanges; // 0x60
|
||||
int m_nCmdFlags; // 0x64
|
||||
uint32_t m_nPawnEntityHandle; // 0x68
|
||||
char pad_007D[3]; //0x007D
|
||||
|
||||
CSubtickMoveStep* AddSubTickMove();
|
||||
};
|
||||
|
||||
class CCSGOUserCmdPB
|
||||
{
|
||||
public:
|
||||
std::uint32_t m_nHasBits; // 0x0
|
||||
std::uint64_t m_nCachedSize; // 0x8
|
||||
RepeatedPtrField_t<CCSGOInputHistoryEntryPB> m_inputHistoryField; // 0x10
|
||||
CBaseUserCmdPB* m_pBaseCmd; // 0x18
|
||||
int32_t m_nAttack3StartHhistoryIndex; // 0x20
|
||||
int32_t m_nAttack1StartHhistoryIndex; // 0x24
|
||||
int32_t m_nAttack2StartHhistoryIndex; // 0x28
|
||||
};
|
||||
|
||||
|
||||
struct CInButtonState
|
||||
{
|
||||
void* pVTable; // 0x0
|
||||
uint64_t m_nValue; // 0x8
|
||||
uint64_t m_nValueChanged; // 0x10
|
||||
uint64_t m_nValueScroll; // 0x18
|
||||
};
|
||||
static_assert(sizeof(CInButtonStatePB) == 0x30);
|
||||
|
||||
class CUserCmd
|
||||
{
|
||||
public:
|
||||
void* pVTable; // 0x0
|
||||
CCSGOUserCmdPB m_csgoUserCmd; // 0x20
|
||||
CInButtonState m_nButtons; // 0x30
|
||||
MEM_PAD(0x20); // 0x48
|
||||
CSubtickMoveStep* GetSubTickMoveStep(int nIndex)
|
||||
{
|
||||
if (nIndex >= m_csgoUserCmd.m_pBaseCmd->m_subtickMovesField.m_pRep->m_nAllocatedSize)
|
||||
return nullptr;
|
||||
|
||||
return m_csgoUserCmd.m_pBaseCmd->m_subtickMovesField.m_pRep->m_tElements[nIndex];
|
||||
}
|
||||
CCSGOInputHistoryEntryPB* GetInputHistoryEntry(int nIndex)
|
||||
{
|
||||
if (nIndex >= m_csgoUserCmd.m_inputHistoryField.m_pRep->m_nAllocatedSize)
|
||||
return nullptr;
|
||||
|
||||
return m_csgoUserCmd.m_inputHistoryField.m_pRep->m_tElements[nIndex];
|
||||
}
|
||||
void SetPlayerTickCount() {
|
||||
for (int i = 0; i < this->m_csgoUserCmd.m_inputHistoryField.m_pRep->m_nAllocatedSize; i++)
|
||||
{
|
||||
CCSGOInputHistoryEntryPB* pInputEntry = this->GetInputHistoryEntry(i);
|
||||
if (pInputEntry == nullptr)
|
||||
continue;
|
||||
|
||||
if (pInputEntry->m_pViewCmd == nullptr)
|
||||
continue;
|
||||
|
||||
pInputEntry->m_nPlayerTickCount = 0;
|
||||
}
|
||||
}
|
||||
void SetSubTickAngle(const QAngle_t& angView)
|
||||
{
|
||||
for (int i = 0; i < this->m_csgoUserCmd.m_inputHistoryField.m_pRep->m_nAllocatedSize; i++)
|
||||
{
|
||||
CCSGOInputHistoryEntryPB* pInputEntry = this->GetInputHistoryEntry(i);
|
||||
if (pInputEntry == nullptr)
|
||||
continue;
|
||||
|
||||
if (pInputEntry->m_pViewCmd == nullptr)
|
||||
continue;
|
||||
|
||||
pInputEntry->m_pViewCmd->m_angValue = angView;
|
||||
}
|
||||
}
|
||||
void AdjustAttackStartIndex(int nTick) {
|
||||
this->m_csgoUserCmd.m_nAttack1StartHhistoryIndex = nTick;
|
||||
this->m_csgoUserCmd.m_nAttack2StartHhistoryIndex = nTick;
|
||||
this->m_csgoUserCmd.m_nAttack3StartHhistoryIndex = nTick;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(CUserCmd) == 0x88);
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "utlrbtree.h"
|
||||
#include <optional>
|
||||
|
||||
// @source: master/public/tier1/utlmap.h
|
||||
template <typename K, typename V>
|
||||
class CUtlMap {
|
||||
public:
|
||||
struct Node_t {
|
||||
int m_left;
|
||||
int m_right;
|
||||
int m_parent;
|
||||
int m_tag;
|
||||
K m_key;
|
||||
V m_value;
|
||||
};
|
||||
|
||||
auto begin() const { return m_data; }
|
||||
auto end() const { return m_data + m_size; }
|
||||
|
||||
std::optional<V> FindByKey(K key) const {
|
||||
int current = m_root;
|
||||
while (current != -1) {
|
||||
const Node_t& element = m_data[current];
|
||||
if (element.m_key < key)
|
||||
current = element.m_right;
|
||||
else if (element.m_key > key)
|
||||
current = element.m_left;
|
||||
else
|
||||
return element.m_value;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
char pad0[0x8]; // no idea
|
||||
Node_t* m_data;
|
||||
char pad1[0x8]; // no idea
|
||||
int m_root;
|
||||
int m_size;
|
||||
char pad2[0x8]; // no idea
|
||||
};
|
||||
@@ -0,0 +1,663 @@
|
||||
#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"
|
||||
#pragma warning (disable:4100)
|
||||
#pragma warning (disable:4514)
|
||||
// @source: master/public/tier1/utlmemory.h
|
||||
// Swap two of anything.
|
||||
template <class T>
|
||||
inline void V_swap(T& x, T& y)
|
||||
{
|
||||
T temp = x;
|
||||
x = y;
|
||||
y = temp;
|
||||
}
|
||||
|
||||
template <class T, class N = size_t>
|
||||
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;
|
||||
};
|
||||
|
||||
// constructor, destructor
|
||||
|
||||
|
||||
CUtlMemory() :
|
||||
pMemory(nullptr), nAllocationCount(0), nGrowSize(0) { }
|
||||
|
||||
CUtlMemory& operator=(const CUtlMemory& rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
// ... copy other members ...
|
||||
pMemory = rhs.pMemory; // Use the assignment operator of CUtlMemory
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
CUtlMemory(const int nInitialGrowSize, const int nAllocationCount) :
|
||||
pMemory(nullptr), nAllocationCount(nAllocationCount), nGrowSize(nInitialGrowSize)
|
||||
{
|
||||
|
||||
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(T* pMemory, const void* pElements, size_t size) :
|
||||
pMemory(pMemory), nAllocationCount(static_cast<N>(pElements / sizeof(T))), nGrowSize(size) // You may need to set nGrowSize appropriately
|
||||
{
|
||||
// Assuming nElements points to the start of the memory block to be copied
|
||||
if (pElements != nullptr)
|
||||
{
|
||||
CRT::MemoryCopy(pMemory, pElements, size);
|
||||
}
|
||||
}
|
||||
|
||||
~CUtlMemory()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
template<class T, class N>
|
||||
inline CUtlMemory(CUtlMemory&& moveFrom)
|
||||
{
|
||||
moveFrom.pMemory = nullptr;
|
||||
moveFrom.nAllocationCount = 0;
|
||||
moveFrom.nGrowSize = 0;
|
||||
}
|
||||
|
||||
template<class T, class N>
|
||||
inline CUtlMemory& operator=(CUtlMemory&& moveFrom)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
/*
|
||||
CUtlMemory(CUtlMemory&& moveFrom)
|
||||
{
|
||||
moveFrom.pMemory = nullptr;
|
||||
moveFrom.nAllocationCount = 0;
|
||||
moveFrom.nGrowSize = 0;
|
||||
}
|
||||
CUtlMemory(const CUtlMemory&) = delete;
|
||||
|
||||
|
||||
|
||||
CUtlMemory& operator=(CUtlMemory&& moveFrom)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
return pMemory[nIndex];
|
||||
}
|
||||
|
||||
[[nodiscard]] const T& operator[](const N nIndex) const
|
||||
{
|
||||
return pMemory[nIndex];
|
||||
}
|
||||
|
||||
[[nodiscard]] T& Element(const N nIndex)
|
||||
{
|
||||
return pMemory[nIndex];
|
||||
}
|
||||
|
||||
[[nodiscard]] const T& Element(const N nIndex) const
|
||||
{
|
||||
return pMemory[nIndex];
|
||||
}
|
||||
|
||||
[[nodiscard]] T* Base()
|
||||
{
|
||||
return pMemory;
|
||||
}
|
||||
|
||||
[[nodiscard]] const T* Base() const
|
||||
{
|
||||
return pMemory;
|
||||
}
|
||||
|
||||
[[nodiscard]] int AllocationCount() const
|
||||
{
|
||||
return nAllocationCount;
|
||||
}
|
||||
int AllocationNum() 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 Init(size_t nGrowSize, size_t nInitSize);
|
||||
|
||||
void SetExternalBuffer(T* pMemory, size_t numElements);
|
||||
|
||||
void AssumeMemory(T* pMemory, size_t numElements);
|
||||
|
||||
void* DetachMemory();
|
||||
|
||||
T* Detach();
|
||||
|
||||
CUtlMemory(const T* pMemory, size_t numElements);
|
||||
|
||||
void Swap(CUtlMemory< T, N >& mem);
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
public:
|
||||
T* pMemory; // 0x00
|
||||
int nAllocationCount; // 0x04
|
||||
int nGrowSize;
|
||||
// 0x08
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attaches the buffer to external memory....
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class N >
|
||||
void CUtlMemory<T, N>::SetExternalBuffer(T* pMemory, size_t numElements)
|
||||
{
|
||||
// Blow away any existing allocated memory
|
||||
Purge();
|
||||
|
||||
pMemory = pMemory;
|
||||
nAllocationCount = numElements;
|
||||
|
||||
// Indicate that we don't own the memory
|
||||
nGrowSize = EXTERNAL_BUFFER_MARKER;
|
||||
}
|
||||
|
||||
template< class T, class N >
|
||||
void CUtlMemory<T, N>::AssumeMemory(T* pMemory, size_t numElements)
|
||||
{
|
||||
// Blow away any existing allocated memory
|
||||
Purge();
|
||||
|
||||
// Simply take the pointer but don't mark us as external
|
||||
pMemory = pMemory;
|
||||
nAllocationCount = numElements;
|
||||
}
|
||||
|
||||
template< class T, class N >
|
||||
void* CUtlMemory<T, N>::DetachMemory()
|
||||
{
|
||||
if (IsExternallyAllocated())
|
||||
return NULL;
|
||||
|
||||
void* pMemory = pMemory;
|
||||
pMemory = 0;
|
||||
nAllocationCount = 0;
|
||||
return pMemory;
|
||||
}
|
||||
|
||||
template< class T, class N >
|
||||
inline T* CUtlMemory<T, N>::Detach()
|
||||
{
|
||||
return (T*)DetachMemory();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class N>
|
||||
inline CUtlMemory<T, N>::CUtlMemory(const T* pMemory, size_t numElements) : nAllocationCount(static_cast<N>(numElements))
|
||||
{
|
||||
// Special marker indicating externally supplied modifiable memory
|
||||
this->pMemory = (T*)pMemory;
|
||||
nGrowSize = -2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template< class T, class I >
|
||||
void CUtlMemory<T, I>::Init(size_t nGrowSize /*= 0*/, size_t nInitSize /*= 0*/)
|
||||
{
|
||||
Purge();
|
||||
nGrowSize = nGrowSize;
|
||||
nAllocationCount = nInitSize;
|
||||
ConvertToGrowableMemory(nGrowSize);
|
||||
if (nAllocationCount)
|
||||
{
|
||||
pMemory = (T*)malloc(nAllocationCount * sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
template< class T, class N >
|
||||
void CUtlMemory<T, N>::Swap(CUtlMemory<T, N>& mem)
|
||||
{
|
||||
V_swap(nGrowSize, mem.nGrowSize);
|
||||
V_swap(pMemory, mem.pMemory);
|
||||
V_swap(nAllocationCount, mem.nAllocationCount);
|
||||
}
|
||||
|
||||
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];
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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>;
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include "utlmemory.h"
|
||||
|
||||
// used: memorymove
|
||||
#include "../../utilities/fnv1a.h"
|
||||
|
||||
#define STRINGTOKEN_MURMURHASH_SEED 0x31415926
|
||||
|
||||
#pragma pack(push, 8)
|
||||
class CUtlStringToken
|
||||
{
|
||||
public:
|
||||
explicit CUtlStringToken(const char* szKeyName)
|
||||
{
|
||||
uHashCode = FNV1A::Hash(szKeyName, STRINGTOKEN_MURMURHASH_SEED);
|
||||
szDebugName = szKeyName;
|
||||
}
|
||||
|
||||
constexpr CUtlStringToken(const FNV1A_t uHashCode, const char* szKeyName) :
|
||||
uHashCode(uHashCode), szDebugName(szKeyName) { }
|
||||
|
||||
CS_INLINE bool operator==(const CUtlStringToken& other) const
|
||||
{
|
||||
return (other.uHashCode == uHashCode);
|
||||
}
|
||||
|
||||
CS_INLINE bool operator!=(const CUtlStringToken& other) const
|
||||
{
|
||||
return (other.uHashCode != uHashCode);
|
||||
}
|
||||
|
||||
CS_INLINE bool operator<(const CUtlStringToken& other) const
|
||||
{
|
||||
return (uHashCode < other.uHashCode);
|
||||
}
|
||||
|
||||
public:
|
||||
FNV1A_t uHashCode = 0U; // 0x00
|
||||
const char* szDebugName = nullptr; // 0x08 // @Todo: for some reason retards keep this even for non-debug builds, it can be changed later
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// helper to create a string token at compile-time
|
||||
CS_INLINE consteval CUtlStringToken MakeStringToken(const char* szKeyName)
|
||||
{
|
||||
return { FNV1A::HashConst(szKeyName, STRINGTOKEN_MURMURHASH_SEED), szKeyName };
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
#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->GetNext())
|
||||
{
|
||||
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))->GetData();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
tData GetData()
|
||||
{
|
||||
return *reinterpret_cast<tData*>(reinterpret_cast<std::uintptr_t>(this) + (0x10));
|
||||
}
|
||||
|
||||
HashFixedDataInternal_t<tData>* GetNext()
|
||||
{
|
||||
return *reinterpret_cast<HashFixedDataInternal_t<tData>**>(reinterpret_cast<std::uintptr_t>(this) + (0x20));
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
HashBucket_t aBuckets[nBucketCount];
|
||||
bool bNeedsCommit;
|
||||
};
|
||||
@@ -0,0 +1,362 @@
|
||||
#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 <typename T>
|
||||
class CUtlVectorCS2 {
|
||||
public:
|
||||
auto begin() const { return m_Data; }
|
||||
auto end() const { return m_Data + m_Size; }
|
||||
|
||||
auto At(int i) const { return m_Data[i]; }
|
||||
auto AtPtr(int i) const { return m_Data + i; }
|
||||
|
||||
int m_Size;
|
||||
char pad0[0x4];
|
||||
T* m_Data;
|
||||
char pad1[0x8];
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
#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::ToEulerAngles(Vector_t* pseudoup /*= nullptr*/) {
|
||||
auto pitch = 0.0f;
|
||||
auto yaw = 0.0f;
|
||||
auto roll = 0.0f;
|
||||
|
||||
auto length = this->ToVector2D().Length();
|
||||
|
||||
if (pseudoup) {
|
||||
auto left = pseudoup->CrossProduct(*this);
|
||||
|
||||
left.Normalizes();
|
||||
|
||||
pitch = ToDegrees(std::atan2(-this->z, length));
|
||||
|
||||
if (pitch < 0.0f)
|
||||
pitch += 360.0f;
|
||||
|
||||
if (length > 0.001f) {
|
||||
yaw = ToDegrees(std::atan2(this->y, this->x));
|
||||
|
||||
if (yaw < 0.0f)
|
||||
yaw += 360.0f;
|
||||
|
||||
auto up_z = (this->x * left.y) - (this->y * left.x);
|
||||
|
||||
roll = ToDegrees(std::atan2(left.z, up_z));
|
||||
|
||||
if (roll < 0.0f)
|
||||
roll += 360.0f;
|
||||
}
|
||||
else {
|
||||
yaw = ToDegrees(std::atan2(-left.x, left.y));
|
||||
|
||||
if (yaw < 0.0f)
|
||||
yaw += 360.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this->x == 0.0f && this->y == 0.0f) {
|
||||
if (this->z > 0.0f)
|
||||
pitch = 270.0f;
|
||||
else
|
||||
pitch = 90.0f;
|
||||
}
|
||||
else {
|
||||
pitch = ToDegrees(std::atan2(-this->z, length));
|
||||
|
||||
if (pitch < 0.0f)
|
||||
pitch += 360.0f;
|
||||
|
||||
yaw = ToDegrees(std::atan2(this->y, this->x));
|
||||
|
||||
if (yaw < 0.0f)
|
||||
yaw += 360.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return { pitch, yaw, roll };
|
||||
}
|
||||
|
||||
[[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;
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
#pragma once
|
||||
// used: [stl] numeric_limits
|
||||
#include <limits>
|
||||
// used: [crt] isfinite, fmodf, sqrtf
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
[[nodiscard]] float Dot(const Vector2D_t& v) const {
|
||||
return (this->x * v.x +
|
||||
this->y * v.y);
|
||||
}
|
||||
|
||||
float LengthSquared() const {
|
||||
return (this->Dot(*this));
|
||||
}
|
||||
|
||||
float Length() const {
|
||||
return (std::sqrt(this->LengthSquared()));
|
||||
}
|
||||
|
||||
float Length2DSquared() const {
|
||||
return (x * x + y * y);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
// New methods to add
|
||||
[[nodiscard]] constexpr Vector_t Min(const Vector_t& other) const
|
||||
{
|
||||
return { std::min(this->x, other.x), std::min(this->y, other.y), std::min(this->z, other.z) };
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector_t Max(const Vector_t& other) const
|
||||
{
|
||||
return { std::max(this->x, other.x), std::max(this->y, other.y), std::max(this->z, other.z) };
|
||||
}
|
||||
|
||||
[[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;
|
||||
}
|
||||
void clamp() {
|
||||
this->x = std::clamp(std::remainder(this->x, 180.0f), -89.0f, 89.0f);
|
||||
this->y = std::clamp(std::remainder(this->y, 360.0f), -180.0f, 180.0f);
|
||||
this->z = 0.f;
|
||||
}
|
||||
void Normalize() {
|
||||
this->x = std::remainderf(this->x, 180.f);
|
||||
this->y = std::remainderf(this->y, 360.f);
|
||||
}
|
||||
|
||||
__forceinline float length_sqr() const {
|
||||
return ((x * x) + (y * y) + (z * z));
|
||||
}
|
||||
|
||||
__forceinline float length_2d_sqr() const {
|
||||
return ((x * x) + (y * y));
|
||||
}
|
||||
|
||||
__forceinline float length() const {
|
||||
return std::sqrt(length_sqr());
|
||||
}
|
||||
|
||||
|
||||
__forceinline float normalize() {
|
||||
float len = this->length();
|
||||
|
||||
(*this) /= (length() + std::numeric_limits< float >::epsilon());
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
__forceinline Vector_t normalized() const {
|
||||
auto vec = *this;
|
||||
|
||||
vec.normalize();
|
||||
|
||||
return vec;
|
||||
}
|
||||
Vector_t Normalizes() const
|
||||
{
|
||||
Vector_t vecOut = *this;
|
||||
vecOut.NormalizeInPlace();
|
||||
return vecOut;
|
||||
}
|
||||
[[nodiscarrd]] inline float Dot(const Vector_t& vOther) const
|
||||
{
|
||||
const Vector_t& a = *this;
|
||||
|
||||
return (a.x * vOther.x + a.y * vOther.y + a.z * vOther.z);
|
||||
}
|
||||
|
||||
[[nodiscarrd]] inline float Dot(const float* fOther) const
|
||||
{
|
||||
const Vector_t& a = *this;
|
||||
|
||||
return (a.x * fOther[0] + a.y * fOther[1] + a.z * fOther[2]);
|
||||
}
|
||||
[[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;
|
||||
[[nodiscard]] QAngle_t ToEulerAngles(Vector_t* pseudoup /*= nullptr*/);
|
||||
|
||||
/// @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);
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -0,0 +1,899 @@
|
||||
#include "entity.h"
|
||||
// others
|
||||
#include "../core/hooks.h"
|
||||
#include "../utilities/draw.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"
|
||||
#include "../core/csig/sigscan.hpp"
|
||||
#include "../core/pointer/pointer.hpp"
|
||||
#include <array>
|
||||
#include "../features.h"
|
||||
#include "../cstrike/features/visuals/overlay.h"
|
||||
#include "../cstrike/features/legit/legit.h"
|
||||
#include "interfaces/iglobalvars.h"
|
||||
#include "../cstrike/features/skins/ccsplayerinventory.hpp"
|
||||
#include "../features/rage/rage.h"
|
||||
|
||||
Vector_t C_CSPlayerPawn::GetEyePosition() {
|
||||
Vector_t EyePosition;
|
||||
MEM::CallVFunc<void, 163>(this, &EyePosition);
|
||||
return EyePosition;
|
||||
}
|
||||
|
||||
static CachedEntity_t::Type GetEntityType(C_BaseEntity* pEntity);
|
||||
|
||||
static CachedEntity_t::Type GetEntityType(C_BaseEntity* pEntity) {
|
||||
if (!pEntity)
|
||||
return CachedEntity_t::UNKNOWN;
|
||||
|
||||
SchemaClassInfoData_t* pClassInfo = nullptr;
|
||||
pEntity->GetSchemaClassInfo(&pClassInfo);
|
||||
|
||||
if (pClassInfo == nullptr)
|
||||
return CachedEntity_t::UNKNOWN;
|
||||
|
||||
const FNV1A_t uHashedName = FNV1A::Hash(pClassInfo->szName);
|
||||
|
||||
if (uHashedName == FNV1A::HashConst(CS_XOR("CCSPlayerController"))) {
|
||||
return CachedEntity_t::PLAYER_CONTROLLER;
|
||||
}
|
||||
|
||||
return CachedEntity_t::UNKNOWN;
|
||||
}
|
||||
|
||||
// Definition of the global vector and mutex
|
||||
std::vector<CachedEntity_t> g_cachedEntities;
|
||||
std::mutex g_cachedEntitiesMutex;
|
||||
std::unordered_multimap<CachedEntity_t::Type, entity_callbacks> g_Callbacks;
|
||||
|
||||
namespace EntCache {
|
||||
|
||||
void CacheCurrentEntities() {
|
||||
// This function runs ONCE on injection and caches all the entities if
|
||||
// you happen to inject connected on a server.
|
||||
|
||||
if (!I::Engine->IsInGame() || !I::Engine->IsConnected()) return;
|
||||
|
||||
if (!I::GameResourceService->pGameEntitySystem) return;
|
||||
|
||||
|
||||
int highestIndex = I::GameResourceService->pGameEntitySystem->GetHighestEntityIndex();
|
||||
for (int i = 1; i <= highestIndex; ++i) {
|
||||
C_BaseEntity* pEntity = I::GameResourceService->pGameEntitySystem->Get(i);
|
||||
if (!pEntity) continue;
|
||||
|
||||
OnAddEntity(pEntity, pEntity->GetRefEHandle());
|
||||
}
|
||||
}
|
||||
|
||||
void OnAddEntity(CEntityInstance* inst, CBaseHandle handle) {
|
||||
if (!I::GameResourceService->pGameEntitySystem) return;
|
||||
|
||||
C_BaseEntity* pEntity = (C_BaseEntity*)inst;
|
||||
if (!pEntity) return;
|
||||
|
||||
// Cache only networked entities.
|
||||
// https://developer.valvesoftware.com/wiki/Entity_limit#Source_2_limits
|
||||
if (handle.GetEntryIndex() >= 16384) return;
|
||||
// call callbacks
|
||||
for (auto& [callback_type, callbacks] : g_Callbacks) {
|
||||
if (!callbacks.add || callback_type != GetEntityType(pEntity))
|
||||
continue;
|
||||
callbacks.add(handle.GetEntryIndex(), handle);
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(g_cachedEntitiesMutex);
|
||||
|
||||
auto it = std::find_if(g_cachedEntities.begin(), g_cachedEntities.end(),
|
||||
[handle](const CachedEntity_t& i) {
|
||||
return i.m_handle.GetEntryIndex() == handle.GetEntryIndex();
|
||||
});
|
||||
|
||||
if (it == g_cachedEntities.end()) {
|
||||
CachedEntity_t cachedEntity{};
|
||||
cachedEntity.m_handle = handle;
|
||||
cachedEntity.m_type = GetEntityType(pEntity);
|
||||
cachedEntity.index = handle.GetEntryIndex();
|
||||
cachedEntity.reset = false;
|
||||
|
||||
if (cachedEntity.m_type != CachedEntity_t::UNKNOWN) {
|
||||
g_cachedEntities.emplace_back(cachedEntity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
it->m_handle = handle;
|
||||
it->m_type = GetEntityType(pEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void OnRemoveEntity(CEntityInstance* inst, CBaseHandle handle) {
|
||||
if (!I::GameResourceService->pGameEntitySystem) return;
|
||||
|
||||
C_BaseEntity* pEntity = (C_BaseEntity*)inst;
|
||||
if (!pEntity) return;
|
||||
|
||||
// call callbacks
|
||||
for (auto& [callback_type, callbacks] : g_Callbacks) {
|
||||
if (!callbacks.remove)
|
||||
continue;
|
||||
|
||||
if (callback_type != GetEntityType(pEntity))
|
||||
continue;
|
||||
|
||||
callbacks.remove(handle.GetEntryIndex(), handle);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_cachedEntitiesMutex);
|
||||
|
||||
auto it = std::find_if(g_cachedEntities.begin(), g_cachedEntities.end(),
|
||||
[handle](const CachedEntity_t& i) {
|
||||
return i.m_handle == handle;
|
||||
});
|
||||
|
||||
if (it == g_cachedEntities.end()) return;
|
||||
|
||||
it->m_draw = false;
|
||||
it->m_type = CachedEntity_t::UNKNOWN;
|
||||
|
||||
}
|
||||
void RegisterCallback(CachedEntity_t::Type type, entity_callback add, entity_callback remove) noexcept {
|
||||
if (!add && !remove)
|
||||
return;
|
||||
|
||||
std::unique_lock lock(g_cachedEntitiesMutex);
|
||||
g_Callbacks.insert(std::make_pair(type, entity_callbacks{ add, remove }));
|
||||
|
||||
if (!add)
|
||||
return;
|
||||
|
||||
// add existing entities
|
||||
for (auto& cached_entity : g_cachedEntities) {
|
||||
if (cached_entity.m_type == type)
|
||||
add(cached_entity.m_handle.GetEntryIndex(), cached_entity.m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace EntCache
|
||||
// global empty vector for when we can't get the origin
|
||||
static Vector_t vecEmpty = Vector_t(0, 0, 0);
|
||||
|
||||
bool CCSPlayerController::IsThrowingGrenade(C_CSWeaponBase* pBaseWeapon)
|
||||
{
|
||||
if (!pBaseWeapon)
|
||||
return false;
|
||||
|
||||
if (!SDK::LocalController->IsPawnAlive() || !SDK::LocalController)
|
||||
return false;
|
||||
|
||||
const float flServerTime = TICKS_TO_TIME(this->m_nTickBase());
|
||||
const short nDefinitionIndex = pBaseWeapon->m_AttributeManager().m_Item().m_iItemDefinitionIndex();
|
||||
CCSWeaponBaseVData* pWeaponBaseVData = pBaseWeapon->datawep();
|
||||
if (!pWeaponBaseVData)
|
||||
return false;
|
||||
|
||||
if (pWeaponBaseVData->m_WeaponType() == WEAPONTYPE_GRENADE)
|
||||
{
|
||||
C_BaseCSGrenade* pGrenade = reinterpret_cast<C_BaseCSGrenade*>(pBaseWeapon);
|
||||
if (pGrenade != nullptr)
|
||||
{
|
||||
return !pGrenade->IsPinPulled() && pGrenade->GetThrowTime() > 0.f && pGrenade->GetThrowTime() < flServerTime;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CCSPlayerController* CCSPlayerController::GetLocalPlayerController()
|
||||
{
|
||||
|
||||
const int nIndex = I::Engine->GetLocalPlayer();
|
||||
return I::GameResourceService->pGameEntitySystem->Get<CCSPlayerController>(nIndex);
|
||||
}
|
||||
|
||||
const Vector_t& CCSPlayerController::GetPawnOrigin()
|
||||
{
|
||||
|
||||
CBaseHandle hPawn = this->GetPawnHandle();
|
||||
if (!hPawn.IsValid())
|
||||
return vecEmpty;
|
||||
|
||||
C_CSPlayerPawn* pPawn = I::GameResourceService->pGameEntitySystem->Get<C_CSPlayerPawn>(hPawn);
|
||||
if (pPawn == nullptr)
|
||||
return vecEmpty;
|
||||
|
||||
return pPawn->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::CalculateBoundingBox(ImVec4& out, bool compute_surrounding_box) {
|
||||
|
||||
if (!this || this->GetHealth() <= 0)
|
||||
return false;
|
||||
|
||||
CCollisionProperty* pCollision = this->GetCollision();
|
||||
if (pCollision == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector_t min{}, max{};
|
||||
|
||||
CTransform nodeToWorldTransform = this->GetGameSceneNode()->GetNodeToWorld();
|
||||
const Matrix3x4_t matTransform = nodeToWorldTransform.quatOrientation.ToMatrix(nodeToWorldTransform.vecPosition);
|
||||
if (compute_surrounding_box) {
|
||||
if (!ComputeHitboxSurroundingBox(min, max)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
min = pCollision->GetMins();
|
||||
max = pCollision->GetMaxs();
|
||||
}
|
||||
|
||||
out.x = out.y = std::numeric_limits<float>::max();
|
||||
out.z = out.w = -std::numeric_limits<float>::max();
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
const Vector_t vecPoint{
|
||||
i & 1 ? max.x : min.x,
|
||||
i & 2 ? max.y : min.y,
|
||||
i & 4 ? max.z : min.z
|
||||
};
|
||||
ImVec2 vecScreen;
|
||||
if (!D::WorldToScreen(vecPoint.Transform(matTransform), vecScreen))
|
||||
return false;
|
||||
|
||||
out.x = MATH::Min(out.x, vecScreen.x);
|
||||
out.y = MATH::Min(out.y, vecScreen.y);
|
||||
out.z = MATH::Max(out.z, vecScreen.x);
|
||||
out.w = MATH::Max(out.w, vecScreen.y);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_CSPlayerPawn::hasArmour(const int hitgroup) {
|
||||
if (!this->GetItemServices())
|
||||
return false;
|
||||
|
||||
switch (hitgroup) {
|
||||
case HITGROUP_HEAD:
|
||||
return this->GetItemServices()->m_bHasHelmet();
|
||||
case HITGROUP_GENERIC:
|
||||
case HITGROUP_CHEST:
|
||||
case HITGROUP_STOMACH:
|
||||
case HITGROUP_LEFTARM:
|
||||
case HITGROUP_RIGHTARM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
/*
|
||||
bool CEconItemDefinition::IsWeapon() {
|
||||
// Every gun supports at least 4 stickers.
|
||||
return GetStickersSupportedCount() >= 4;
|
||||
}
|
||||
|
||||
bool CEconItemDefinition::IsKnife(bool excludeDefault) {
|
||||
static constexpr auto CSGO_Type_Knife =
|
||||
HASHCNSX::hash_32_fnv1a_const("#CSGO_Type_Knife");
|
||||
|
||||
if (HASHCNSX::hash_32_fnv1a_const(m_pszItemTypeName) != CSGO_Type_Knife)
|
||||
return false;
|
||||
|
||||
return excludeDefault ? m_nDefIndex >= 500 : true;
|
||||
}
|
||||
|
||||
bool CEconItemDefinition::IsGlove(bool excludeDefault) {
|
||||
static constexpr auto Type_Hands = HASHCNSX::hash_32_fnv1a_const("#Type_Hands");
|
||||
|
||||
if (HASHCNSX::hash_32_fnv1a_const(m_pszItemTypeName) != Type_Hands) return false;
|
||||
const bool defaultGlove = m_nDefIndex == 5028 || m_nDefIndex == 5029;
|
||||
|
||||
return excludeDefault ? !defaultGlove : true;
|
||||
}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
#include "interfaces/itrace.h"
|
||||
//48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 30 48 8B 59 08 41 8B F8 8B 69 10 8B 72 10 0F 29 74 24 20 0F 28 F3 48 8D 8B C0 00 00 00 81 39 00 02 00 00 7F 6D E8 ?? ?? ?? ?? 48 63 C8 48 C1 E1 06 48 03 8B D0 00 00 00 33 C0 48 C7 01 01"
|
||||
/*bool C_CSPlayerPawn::SetupBones(matrix3x4* out, int maxBones, int boneMask, float currentTime) noexcept
|
||||
{
|
||||
if (localPlayer && this == localPlayer.get() && localPlayer->isAlive())
|
||||
{
|
||||
uint32_t* effects = this->getEffects();
|
||||
uint32_t* shouldskipframe = (uint32_t*)((uintptr_t)this + 0xA68);
|
||||
uint32_t backup_effects = *effects;
|
||||
uint32_t backup_shouldskipframe = *shouldskipframe;
|
||||
*shouldskipframe = 0;
|
||||
*effects |= 8;
|
||||
auto result = VirtualMethod::call<bool, 13>(this + 4, out, maxBones, boneMask, currentTime);
|
||||
*effects = backup_effects;
|
||||
*shouldskipframe = backup_shouldskipframe;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
*reinterpret_cast<int*>(this + 0xA28) = 0;
|
||||
*reinterpret_cast<int*>(this + 0xA30) = memory->globalVars->framecount;
|
||||
int* render = reinterpret_cast<int*>(this + 0x274);
|
||||
uint32_t* shouldskipframe = (uint32_t*)((uintptr_t)this + 0xA68);
|
||||
uint32_t* effects = this->getEffects();
|
||||
int backup = *render;
|
||||
uint32_t backup_effects = *effects;
|
||||
*shouldskipframe = 0;
|
||||
*render = 0;
|
||||
boneMask |= 0x200;
|
||||
*effects |= 8;
|
||||
auto result = VirtualMethod::call<bool, 13>(this + 4, out, maxBones, boneMask, currentTime);
|
||||
*render = backup;
|
||||
*effects = backup_effects;
|
||||
return result;
|
||||
}
|
||||
return VirtualMethod::call<bool, 13>(this + 4, out, maxBones, boneMask, currentTime);
|
||||
}*/
|
||||
|
||||
static Vector_t get_target_angle(C_CSPlayerPawn* localplayer, Vector_t position)
|
||||
{
|
||||
Vector_t eye_position = localplayer->GetEyePosition();
|
||||
Vector_t angle = position;
|
||||
|
||||
angle.x = position.x - eye_position.x;
|
||||
angle.y = position.y - eye_position.y;
|
||||
angle.z = position.z - eye_position.z;
|
||||
|
||||
angle.Normalizes();
|
||||
MATH::vec_angles(angle, &angle);
|
||||
|
||||
angle.clamp();
|
||||
return angle;
|
||||
}
|
||||
template<class T, class U>
|
||||
T fine(T in, U low, U high)
|
||||
{
|
||||
if (in <= low)
|
||||
return low;
|
||||
|
||||
if (in >= high)
|
||||
return high;
|
||||
|
||||
return in;
|
||||
}
|
||||
// basic extrap made in 3 mins gonna improve a lot later on its rly Important & needed
|
||||
Vector_t extrapolate(C_CSPlayerPawn* ent, Vector_t pos) {
|
||||
if (!ent)
|
||||
return pos;
|
||||
|
||||
auto simtime = ent->m_flSimulationTime();
|
||||
auto old_simtime = simtime + 4;
|
||||
float simtime_delta = simtime - old_simtime;
|
||||
int choked_ticks = fine(TIME_TO_TICKS(simtime_delta), 1, 15);
|
||||
|
||||
Vector_t lastOrig;
|
||||
|
||||
if (lastOrig.Length() != pos.Length())
|
||||
lastOrig = pos;
|
||||
|
||||
float delta_distance = (pos - lastOrig).Length();
|
||||
Vector_t velocity_per_tick = ent->m_vecVelocity() * I::GlobalVars->flIntervalPerTick;
|
||||
Vector_t new_origin = pos + (velocity_per_tick * choked_ticks);
|
||||
return new_origin;
|
||||
}
|
||||
void C_CSPlayerPawn::CalculateHitboxData(uint32_t idx, Vector_t& pos, Vector4D_t& rot, float& scale, bool predict) {
|
||||
if (!this || this->GetHealth() <= 0)
|
||||
return;
|
||||
|
||||
auto game_scene_node = this->GetGameSceneNode();
|
||||
if (!game_scene_node)
|
||||
return;
|
||||
|
||||
auto skeleton = game_scene_node->GetSkeletonInstance();
|
||||
if (!skeleton)
|
||||
return;
|
||||
|
||||
auto model_state = &skeleton->GetModel();
|
||||
if (!model_state)
|
||||
return;
|
||||
|
||||
CStrongHandle<CModel> model = model_state->m_hModel();
|
||||
if (!model.is_valid())
|
||||
return;
|
||||
|
||||
auto model_skelet = &model->m_modelSkeleton();
|
||||
if (!model_skelet)
|
||||
return;
|
||||
|
||||
skeleton->calc_world_space_bones(0, bone_flags::FLAG_HITBOX);
|
||||
|
||||
auto data = model_state->GetHitboxData();
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (!(model->GetHitboxFlags(idx) & bone_flags::FLAG_HITBOX))
|
||||
return;
|
||||
|
||||
auto parent_index = model->GetHitboxParent(idx);
|
||||
if (parent_index == -1)
|
||||
return;
|
||||
|
||||
rot = data[idx].rot;
|
||||
scale = data[idx].scale;
|
||||
|
||||
|
||||
if (predict) {
|
||||
// Extrapolate position based on velocity and acceleration
|
||||
pos = data[idx].pos + this->m_vecVelocity() * I::GlobalVars->flIntervalPerTick;
|
||||
}
|
||||
else {
|
||||
pos = data[idx].pos;
|
||||
}
|
||||
|
||||
}
|
||||
uint32_t C_CSPlayerPawn::GetHitGroup(int idx) {
|
||||
switch (idx) {
|
||||
case HEAD:
|
||||
case NECK:
|
||||
return HITGROUP_HEAD;
|
||||
case CHEST:
|
||||
case LEFT_CHEST:
|
||||
case RIGHT_CHEST:
|
||||
case PELVIS:
|
||||
return HITGROUP_CHEST;
|
||||
case STOMACH:
|
||||
return HITGROUP_STOMACH;
|
||||
case L_LEG:
|
||||
case R_LEG:
|
||||
case L_FEET:
|
||||
case R_FEET:
|
||||
return HITGROUP_LEFTLEG;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
C_CSWeaponBase* C_CSPlayerPawn::ActiveWeapon() {
|
||||
CPlayer_WeaponServices* WeaponServices = this->GetWeaponServices();
|
||||
if (!WeaponServices)
|
||||
return nullptr;
|
||||
|
||||
auto ActiveWeapon = I::GameResourceService->pGameEntitySystem->Get<C_CSWeaponBase>(WeaponServices->m_hActiveWeapon());
|
||||
if (!ActiveWeapon)
|
||||
return nullptr;
|
||||
|
||||
return ActiveWeapon;
|
||||
}
|
||||
|
||||
C_CSWeaponBase* CCSPlayerController::GetPlayerWeapon(C_CSPlayerPawn* pPlayer)
|
||||
{
|
||||
if (!pPlayer || !pPlayer->GetWeaponServices())
|
||||
return nullptr;
|
||||
|
||||
CBaseHandle hActiveWeapon = pPlayer->GetWeaponServices()->m_hActiveWeapon();
|
||||
|
||||
if (!hActiveWeapon.IsValid())
|
||||
return nullptr;
|
||||
|
||||
C_CSWeaponBase* pWeapon = I::GameResourceService->pGameEntitySystem->Get<C_CSWeaponBase>(hActiveWeapon);
|
||||
|
||||
return pWeapon;
|
||||
}
|
||||
|
||||
bool C_CSPlayerPawn::CanNextAttack(float svtime) {
|
||||
return false;
|
||||
}
|
||||
bool C_CSPlayerPawn::CanShoot(float svtime) {
|
||||
CPlayer_WeaponServices* WeaponServices = this->GetWeaponServices();
|
||||
if (!WeaponServices)
|
||||
return false;
|
||||
|
||||
auto ActiveWeapon = I::GameResourceService->pGameEntitySystem->Get<C_CSWeaponBase>(WeaponServices->m_hActiveWeapon());
|
||||
if (!ActiveWeapon)
|
||||
return false;
|
||||
|
||||
auto data = ActiveWeapon->datawep();
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (ActiveWeapon->clip1() <= 0)
|
||||
return false;
|
||||
|
||||
if (data->m_WeaponType() == WEAPONTYPE_KNIFE || data->m_WeaponType() == WEAPONTYPE_FISTS)
|
||||
return true;
|
||||
/*
|
||||
auto next_attack = (WeaponServices->m_flNextAttack());
|
||||
auto next_2 = WeaponServices->m_flNextAttack() * I::GlobalVars->flIntervalPerTick;
|
||||
auto next_3 = static_cast<float>(WeaponServices->m_flNextAttack() * I::GlobalVars->flIntervalPerTick);
|
||||
*/
|
||||
|
||||
auto primary_tick = ActiveWeapon->m_nNextPrimaryAttackTick();
|
||||
|
||||
if (primary_tick > svtime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool C_CSPlayerPawn::Visible(C_CSPlayerPawn* local, int type, bool v)
|
||||
{
|
||||
if (!this || this->GetHealth() <= 0)
|
||||
return false;
|
||||
|
||||
if (type == 0) {
|
||||
trace_filter_t filter = {};
|
||||
I::Trace->Init(filter, local, 0x1C3003, 4, 7);
|
||||
|
||||
game_trace_t trace = {};
|
||||
ray_t ray = {};
|
||||
|
||||
Vector_t start_eye = local->GetEyePosition();
|
||||
Vector_t end_eye = this->GetEyePosition();
|
||||
|
||||
I::Trace->TraceShape(ray, &start_eye, &end_eye, filter, trace);
|
||||
|
||||
return trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == this->GetRefEHandle().GetEntryIndex() || trace.Fraction > 0.97f;
|
||||
}
|
||||
else if (type == TRACE_TYPE::AIMBOT) {
|
||||
if (v) {
|
||||
trace_filter_t filter = {};
|
||||
I::Trace->Init(filter, local, 0x1C3003, 4, 7);
|
||||
|
||||
game_trace_t trace = {};
|
||||
ray_t ray = {};
|
||||
|
||||
Vector_t start_eye = local->GetEyePosition();
|
||||
Vector_t end_eye = this->GetEyePosition();
|
||||
|
||||
I::Trace->TraceShape(ray, &start_eye, &end_eye, filter, trace);
|
||||
|
||||
return trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == this->GetRefEHandle().GetEntryIndex() || trace.Fraction > 0.97f;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
float C_CSPlayerPawn::GetProperSpread() {
|
||||
/* acc penalty */
|
||||
auto weapon = this->ActiveWeapon();
|
||||
if (!weapon)
|
||||
return 0.f;
|
||||
|
||||
auto vdata = weapon->datawep();
|
||||
if (!vdata)
|
||||
return 0.f;
|
||||
float flSpread = 0.f;
|
||||
if (weapon->m_weaponMode() == CSWeaponMode::Primary_Mode)
|
||||
{
|
||||
return vdata->m_flSpread().flValue[0];
|
||||
}
|
||||
else if (weapon->m_weaponMode() == CSWeaponMode::Secondary_Mode)
|
||||
{
|
||||
return vdata->m_flSpread().flValue[1];
|
||||
}
|
||||
return flSpread;
|
||||
};
|
||||
float C_CSPlayerPawn::GetProperAccuracy() {
|
||||
/* acc penalty */
|
||||
auto weapon = this->ActiveWeapon();
|
||||
if (!weapon)
|
||||
return 0.f;
|
||||
|
||||
auto vdata = weapon->datawep();
|
||||
if (!vdata)
|
||||
return 0.f;
|
||||
|
||||
float flInnacuracy = weapon->m_fAccuracyPenalty();
|
||||
|
||||
if (this->m_vecVelocity().Length2D() != 0.0f) /* we are not standing */
|
||||
{
|
||||
float flInnacuracyMove = 0.0f;
|
||||
|
||||
if (weapon->m_weaponMode() == CSWeaponMode::Primary_Mode)
|
||||
flInnacuracyMove = vdata->m_flInaccuracyMove().flValue[0];
|
||||
else if (weapon->m_weaponMode() == CSWeaponMode::Secondary_Mode)
|
||||
flInnacuracyMove = vdata->m_flInaccuracyMove().flValue[1];
|
||||
|
||||
if (this->m_bIsWalking())
|
||||
flInnacuracyMove /= 3.f;
|
||||
|
||||
else if (this->GetFlags() & FL_DUCKING)
|
||||
flInnacuracyMove /= 6.f;
|
||||
|
||||
flInnacuracy += flInnacuracyMove;
|
||||
}
|
||||
|
||||
if (!(this->GetFlags() & FL_ONGROUND))
|
||||
{
|
||||
if (weapon->m_weaponMode() == CSWeaponMode::Primary_Mode)
|
||||
flInnacuracy += vdata->m_flInaccuracyJump().flValue[0];
|
||||
else if (weapon->m_weaponMode() == CSWeaponMode::Secondary_Mode)
|
||||
flInnacuracy += vdata->m_flInaccuracyJump().flValue[1];
|
||||
}
|
||||
|
||||
return flInnacuracy;
|
||||
};
|
||||
bool C_CSPlayerPawn::InsideCrosshair(C_CSPlayerPawn* target, QAngle_t ang, float range)
|
||||
{
|
||||
if (!this || this->GetHealth() <= 0)
|
||||
return false;
|
||||
|
||||
|
||||
trace_filter_t filter = {};
|
||||
I::Trace->Init(filter, target, 0x1C3003, 4, 7);
|
||||
|
||||
game_trace_t trace = {};
|
||||
ray_t ray = {};
|
||||
Vector_t vecForward = { };
|
||||
ang.ToDirections(&vecForward);
|
||||
vecForward *= range;
|
||||
Vector_t vecStart = target->GetEyePosition();
|
||||
Vector_t vecEnd = vecStart + vecForward;
|
||||
I::Trace->TraceShape(ray, &vecStart, &vecEnd, filter, trace);
|
||||
|
||||
return trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == this->GetRefEHandle().GetEntryIndex();
|
||||
}
|
||||
|
||||
bool C_CSPlayerPawn::TracePoint(C_CSPlayerPawn* target, Vector_t end)
|
||||
{
|
||||
if (!this || this->GetHealth() <= 0)
|
||||
return false;
|
||||
|
||||
trace_filter_t filter = {};
|
||||
I::Trace->Init(filter, this, 0x1C3003, 4, 7);
|
||||
|
||||
game_trace_t trace = {};
|
||||
ray_t ray = {};
|
||||
|
||||
Vector_t vecStart = this->GetEyePosition();
|
||||
I::Trace->TraceShape(ray, &vecStart, &end, filter, trace);
|
||||
|
||||
if (trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == target->GetRefEHandle().GetEntryIndex())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// cHoca
|
||||
|
||||
bool C_BaseEntity::ComputeHitboxSurroundingBox(Vector_t& min, Vector_t& max) {
|
||||
using fnComputeHitboxSurroundingBox = bool(CS_FASTCALL*)(void*, Vector_t&, Vector_t&);
|
||||
static auto ComputeHitboxSurroundingBox = reinterpret_cast<fnComputeHitboxSurroundingBox>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E9 ? ? ? ? F6 43 5B FD")), 1, 0));
|
||||
if (!ComputeHitboxSurroundingBox) {
|
||||
L_PRINT(LOG_ERROR) << CS_XOR("[C_BaseEntity::ComputeHitboxSurroundingBox] C_HOOK::ComputeHitboxSurroundingBox > null");
|
||||
return false;
|
||||
}
|
||||
return ComputeHitboxSurroundingBox(this, min, max);
|
||||
|
||||
}
|
||||
//?GetNumberOfBoundContexts@SchedulerBase@details@Concurrency@@IEBAKXZ_0 ; Concurrency::details::SchedulerBase::GetNumberOfBoundContexts(void)
|
||||
// Em baixo no SUBROUTINE de baixo
|
||||
|
||||
#include "../core/spoofcall/invoker.h"
|
||||
void CSkeletonInstance::get_bone_data(bone_data& data, int index)
|
||||
{
|
||||
// cHoca
|
||||
|
||||
using fnBoneData = void(CS_FASTCALL*)(void*, bone_data&, int index);
|
||||
static auto BoneData = reinterpret_cast<fnBoneData>(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? EB 19 48 8B CF")));
|
||||
|
||||
return BoneData(this, data, index);
|
||||
}
|
||||
// #STR: "C:\\buildworker\\csgo_rel_win64\\build\\src\\game\\shared\, "Bone merge bones from parent were invalid: parent model '%, "CalcWorldSpaceBones"
|
||||
void CS_FASTCALL CSkeletonInstance::calc_world_space_bones(uint32_t parent, uint32_t mask)
|
||||
{ // cHoca
|
||||
|
||||
using fnNewCalcWSsBones = void(CS_FASTCALL)(void*, uint32_t);
|
||||
static auto bone_new = reinterpret_cast<fnNewCalcWSsBones*>(MEM::FindPattern(CLIENT_DLL, CS_XOR("40 55 56 57 41 54 41 55 41 56 41 57 48 81 EC D0")));
|
||||
return bone_new(this, mask);
|
||||
}
|
||||
|
||||
uint32_t CModel::GetHitboxesNum() {
|
||||
|
||||
using fnHitboxNum = uint32_t(CS_FASTCALL*)(void*);
|
||||
static auto HitboxNum = reinterpret_cast<fnHitboxNum>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 8B D8 48 C7 44 24 50 00 00 00 00")), 1, 0));
|
||||
CS_ASSERT(HitboxNum != nullptr);
|
||||
|
||||
return HitboxNum(this);
|
||||
|
||||
}
|
||||
|
||||
CGCClientSharedObjectCache* CGCClient::FindSOCache(SOID_t ID,
|
||||
bool bCreateIfMissing) {
|
||||
|
||||
using fnFindSOCache = CGCClientSharedObjectCache * (CS_FASTCALL*)(void*, SOID_t, bool);
|
||||
static auto FindSOCache = reinterpret_cast<fnFindSOCache>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 10 48 89 6C 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 83 EC 40 48")));
|
||||
CS_ASSERT(FindSOCache != nullptr);
|
||||
|
||||
return FindSOCache(this, ID, bCreateIfMissing);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CGameSceneNode::SetMeshGroupMask(uint64_t meshGroupMask) {
|
||||
if (!H::SetMeshGroupMask) {
|
||||
L_PRINT(LOG_ERROR) << "error getting meshgroupmask";
|
||||
}
|
||||
|
||||
return H::SetMeshGroupMask(this, meshGroupMask);
|
||||
}
|
||||
|
||||
void C_BaseModelEntity::SetModel(const char* name) {
|
||||
auto orig = H::hkSetModel.GetOriginal();
|
||||
return orig(this, name);
|
||||
}
|
||||
|
||||
|
||||
void CEconItem::SetDynamicAttributeValue(int index, void* value) {
|
||||
CEconItemSchema* pItemSchema =
|
||||
I::Client->GetEconItemSystem()->GetEconItemSchema();
|
||||
if (!pItemSchema) return;
|
||||
|
||||
void* pAttributeDefinitionInterface =
|
||||
pItemSchema->GetAttributeDefinitionInterface(index);
|
||||
if (!pAttributeDefinitionInterface) return;
|
||||
|
||||
if (!H::fnSetDynamicAttributeValueUint) return;
|
||||
H::fnSetDynamicAttributeValueUint(this, pAttributeDefinitionInterface,
|
||||
value);
|
||||
}
|
||||
|
||||
void CEconItem::SetDynamicAttributeValueString(int index, const char* value) {
|
||||
// CS2FIXME: Function got inlined and cannot be sigscanned.
|
||||
}
|
||||
|
||||
CEconItem* CEconItem::CreateInstance() {
|
||||
// ida: // #STR: "Update(CEconItem)", "CEconItem", "Create(CEconItem)", "BuildCacheSubscribed(CEconItem)", "Update(CEconEquipSlot)", "CEconEquipSlot", "Create(CEconEquipSlot)", "BuildCacheSubscribed(CEconEquipSlot)", "Update(CEconPersonaDataPublic)", "CEconPersonaDataPublic"
|
||||
// ida: sub_E0F420(
|
||||
// 1,
|
||||
// (unsigned int)CEconItem::CreateInstance,
|
||||
// 0,
|
||||
// (unsigned int)"CEconItem",
|
||||
// (__int64)"BuildCacheSubscribed(CEconItem)",
|
||||
// (__int64)"Create(CEconItem)",
|
||||
// (__int64)"Update(CEconItem)");
|
||||
|
||||
using fnCreateSharedObjectSubclassEconItem = CEconItem * (__cdecl*)();
|
||||
static fnCreateSharedObjectSubclassEconItem oCreateSharedObjectSubclassEconItem = reinterpret_cast<fnCreateSharedObjectSubclassEconItem>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 83 EC 28 B9 48 00 00 00 E8 ? ? ? ? 48 85")));
|
||||
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(oCreateSharedObjectSubclassEconItem != nullptr);
|
||||
#endif
|
||||
|
||||
return oCreateSharedObjectSubclassEconItem();
|
||||
}
|
||||
uint32_t CModel::GetHitboxFlags(uint32_t index)
|
||||
{
|
||||
|
||||
using fnHitboxFlags = uint32_t(CS_FASTCALL*)(void*, uint32_t);
|
||||
static auto HitboxFlags = reinterpret_cast<fnHitboxFlags>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 78 16 3B 91")));
|
||||
CS_ASSERT(HitboxFlags != nullptr);
|
||||
|
||||
return HitboxFlags(this, index);
|
||||
}
|
||||
|
||||
const char* CModel::GetHitboxName(uint32_t index)
|
||||
{
|
||||
using fnHitboxName = const char* (CS_FASTCALL*)(void*, uint32_t);
|
||||
static auto HitboxName = reinterpret_cast<fnHitboxName>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 78 25 3B 91")));
|
||||
CS_ASSERT(HitboxName != nullptr);
|
||||
|
||||
return HitboxName(this, index);
|
||||
}
|
||||
|
||||
uint32_t CModel::GetHitboxParent(uint32_t index)
|
||||
{
|
||||
|
||||
using fnHitboxParent = uint32_t(CS_FASTCALL*)(void*, uint32_t);
|
||||
static auto HitboxParent = reinterpret_cast<fnHitboxParent>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 78 17 3B 91 78")));
|
||||
CS_ASSERT(HitboxParent != nullptr);
|
||||
return HitboxParent(this, index);
|
||||
}
|
||||
|
||||
CGCClientSharedObjectTypeCache* CGCClientSharedObjectCache::CreateBaseTypeCache(
|
||||
int nClassID) {
|
||||
using fnCGCClientSharedObjectTypeCache = CGCClientSharedObjectTypeCache * (CS_FASTCALL*)(void*, int);
|
||||
static fnCGCClientSharedObjectTypeCache createbasetypecache = reinterpret_cast<fnCGCClientSharedObjectTypeCache>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 33 C9 8B D1")), 1, 0));
|
||||
CS_ASSERT(createbasetypecache != nullptr);
|
||||
return createbasetypecache(this, nClassID);
|
||||
}
|
||||
|
||||
|
||||
void C_CSWeaponBase::AddStattrakEntity()
|
||||
{
|
||||
using fnAddStattrakEntity = void(CS_FASTCALL*)(void*);
|
||||
static auto hkAddStattrakEntity = reinterpret_cast<fnAddStattrakEntity>(MEM::FindPattern(CLIENT_DLL, CS_XOR("40 55 41 55 48 8D 6C 24 B8")));
|
||||
CS_ASSERT(hkAddStattrakEntity != nullptr);
|
||||
return hkAddStattrakEntity(this);
|
||||
}
|
||||
|
||||
void C_CSWeaponBase::AddNametagEntity()
|
||||
{
|
||||
using fnAddNametagEntity = void(CS_FASTCALL*)(void*);
|
||||
static auto hkAddNametagEntity = reinterpret_cast<fnAddNametagEntity>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 48 8B CF E8 ? ? ? ? 48 8B C8 E8 ? ? ? ?")), 1, 0));
|
||||
CS_ASSERT(hkAddNametagEntity != nullptr);
|
||||
return hkAddNametagEntity(this);
|
||||
}
|
||||
|
||||
CEconItem* C_EconItemView::GetSOCData(CCSPlayerInventory* sdfsdf) {
|
||||
CCSPlayerInventory* pInventory = CCSPlayerInventory::GetInstance();
|
||||
if (!pInventory) return nullptr;
|
||||
|
||||
return pInventory->GetSOCDataForItem(m_iItemID());
|
||||
}
|
||||
|
||||
|
||||
bool CEconItemDefinition::IsWeapon() {
|
||||
// Every gun supports at least 4 stickers.
|
||||
return GetStickersSupportedCount() >= 4;
|
||||
}
|
||||
|
||||
bool CEconItemDefinition::IsKnife(bool excludeDefault, const char* name) {
|
||||
auto CSGO_Type_Knife = FNV1A::Hash("#CSGO_Type_Knife");
|
||||
|
||||
if (FNV1A::Hash(this->m_pszItemBaseName) != CSGO_Type_Knife)
|
||||
return false;
|
||||
|
||||
return excludeDefault ? m_nDefIndex >= 500 : true;
|
||||
}
|
||||
|
||||
bool CEconItemDefinition::IsGlove(bool excludeDefault, const char* name) {
|
||||
auto Type_Hands = FNV1A::Hash("#Type_Hands");
|
||||
|
||||
bool valid = FNV1A::Hash(this->m_pszItemBaseName) == Type_Hands;
|
||||
bool defaultGlove = valid && m_nDefIndex == 5028 || m_nDefIndex == 5029;
|
||||
|
||||
return excludeDefault ? !defaultGlove : valid;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
#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;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "ccsgoinput.h"
|
||||
#include "../datatypes/usercmd.h"
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
CSubtickMoveStep* CBaseUserCmdPB::AddSubTickMove()
|
||||
{
|
||||
if (m_subtickMovesField && m_subtickMovesField.size() < m_subtickMovesField.max_size())
|
||||
return m_subtickMovesField[m_subtickMovesField.size()++];
|
||||
|
||||
static auto sub_258D30 = MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 48 8B D0 48 8D 4B ? E8 ? ? ? ? 48 8B D0") + 0x1);
|
||||
|
||||
CSubtickMoveStep* subtick = reinterpret_cast<CSubtickMoveStep* (__fastcall*)(uint64_t)>(sub_258D30)(m_subtickMovesField.unk_field());
|
||||
|
||||
m_subtickMovesField.add(subtick);
|
||||
|
||||
return subtick;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
// used: mem_pad
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
// used: cusercmd
|
||||
#include "../datatypes/usercmd.h"
|
||||
|
||||
#define MULTIPLAYER_BACKUP 150
|
||||
|
||||
class CCSGOInput
|
||||
{
|
||||
public:
|
||||
MEM_PAD(0x250); // Offset 0x0000, Padding
|
||||
CUserCmd arrCommands[MULTIPLAYER_BACKUP]; // Offset 0x0250, Array of CUserCmd
|
||||
MEM_PAD(0x1); // Offset 0x0A50, Padding
|
||||
bool bInThirdPerson; // Offset 0x0A51, Boolean flag
|
||||
MEM_PAD(0x22); // Offset 0x0A52, Padding
|
||||
std::int32_t nSequenceNumber; // Offset 0x0A74, Integer
|
||||
std::int32_t nOldSequenceNumber; // Offset 0x0A78, Integer
|
||||
MEM_PAD(0x4); // Offset 0x0A7C, Padding
|
||||
double dbUnknown; // Offset 0x0A80, Double
|
||||
std::uint64_t nButtonState1; // Offset 0x0A88, Unsigned 64-bit integer
|
||||
std::uint64_t nButtonState2; // Offset 0x0A90, Unsigned 64-bit integer
|
||||
std::uint64_t nButtonState3; // Offset 0x0A98, Unsigned 64-bit integer
|
||||
std::uint64_t nButtonState4; // Offset 0x0AA0, Unsigned 64-bit integer
|
||||
MEM_PAD(0xC); // Offset 0x0AA8, Padding
|
||||
std::int32_t nMouseDeltaX; // Offset 0x0AB4, Integer
|
||||
std::int32_t nMouseDeltaY; // Offset 0x0AB8, Integer
|
||||
MEM_PAD(0xC); // Offset 0x0ABC, Padding
|
||||
std::int64_t nOldPressedButton; // Offset 0x0AC8, Integer
|
||||
bool bIsButtonPressed; // Offset 0x0AD0, Boolean flag
|
||||
MEM_PAD(0x10F); // Offset 0x0AD1, Padding
|
||||
QAngle_t angViewAngles; // Offset 0x0BE0, QAngle_t struct
|
||||
MEM_PAD(0x8C); // Offset 0x0C6C, Padding
|
||||
bool bUnknownBool; // Offset 0x0CF8, Boolean flag
|
||||
|
||||
|
||||
void InputCamera() {
|
||||
|
||||
using orig = void(CS_FASTCALL*)(void*);
|
||||
static auto oInputcam = reinterpret_cast<orig>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 0F 85 8A")));
|
||||
CS_ASSERT(oInputcam != nullptr);
|
||||
|
||||
auto backup = *(Vector_t*)((uintptr_t)this + 0x539);
|
||||
// store old camera angles
|
||||
|
||||
// call original
|
||||
oInputcam(this);
|
||||
|
||||
|
||||
|
||||
}
|
||||
CUserCmd* GetUserCmd()
|
||||
{
|
||||
return &arrCommands[nSequenceNumber % MULTIPLAYER_BACKUP];
|
||||
}
|
||||
QAngle_t GetViewAngle() // 4C 8B C1 85 D2 74 08
|
||||
{
|
||||
using fnGetViewAngle = std::int64_t(CS_FASTCALL*)(void*, std::int32_t);
|
||||
static auto oGetViewAngle = reinterpret_cast<fnGetViewAngle>(MEM::FindPattern(CLIENT_DLL, CS_XOR("4C 8B C1 85 D2 74 08")));
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(oGetViewAngle != nullptr);
|
||||
#endif
|
||||
QAngle_t* fn = reinterpret_cast<QAngle_t*>(oGetViewAngle(this, 0));
|
||||
return *fn;
|
||||
}
|
||||
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"))); // \xF2\x41\x0F\x10?\x4C\x63\xCA
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(oSetViewAngle != nullptr);
|
||||
#endif
|
||||
oSetViewAngle(this, 0, std::ref(angView));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
enum CSWeaponID {
|
||||
GLOCK = 1,
|
||||
USP_S = 2,
|
||||
P2000 = 3,
|
||||
DUAL_BERETTAS = 4,
|
||||
P250 = 5,
|
||||
TEC9 = 6,
|
||||
FIVE_SEVEN = 7,
|
||||
DESERT_EAGLE = 8,
|
||||
|
||||
MAC10 = 17,
|
||||
MP9 = 18,
|
||||
MP7 = 19,
|
||||
UMP45 = 24,
|
||||
P90 = 26,
|
||||
|
||||
GALIL_AR = 13,
|
||||
FAMAS = 14,
|
||||
AK47 = 10,
|
||||
M4A4 = 16,
|
||||
M4A1_S = 20,
|
||||
AUG = 23,
|
||||
SG553 = 27,
|
||||
|
||||
AWP = 9,
|
||||
G3SG1 = 11,
|
||||
SCAR20 = 38,
|
||||
|
||||
M249 = 28,
|
||||
NEGEV = 35
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "events.h"
|
||||
|
||||
std::int64_t IGameEvent::get_int(const std::string_view event_name) noexcept {
|
||||
// client.dll; 48 89 5C 24 08 48 89 74 24 10 48 89 7C 24 18 41 56 48 83 EC 30 48 8B 01 41 8B F0 4C 8B F1 41 B0 01 48 8D 4C 24 20 48 8B DA 48 8B 78
|
||||
using function_t = std::int64_t(__fastcall*)(void*, const char*);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, "48 89 5C 24 08 48 89 74 24 10 48 89 7C 24 18 41 56 48 83 EC 30 48 8B 01 41 8B F0 4C 8B F1 41 B0 01 48 8D 4C 24 20 48 8B DA 48 8B 78"));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
return fn(this, event_name.data());
|
||||
}
|
||||
|
||||
void* IGameEvent::get_player_pawn_from_id(const std::string_view event_name) noexcept {
|
||||
// client.dll; 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 30 48 8B 01 48 8B F1 41 B0 01 48 8D 4C 24 20 48 8B FA 48 8B 98
|
||||
using function_t = void*(__fastcall*)(void*, const char*, std::int64_t);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 30 48 8B 01 48 8B F1 41 B0 01 48 8D 4C 24 20 48 8B FA 48 8B 98"));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
return fn(this, event_name.data(), 0);
|
||||
}
|
||||
|
||||
void* IGameEvent::get_pointer_from_id(const std::string_view event_name) noexcept {
|
||||
// used: "userid", "attackerid"
|
||||
std::int64_t id{ };
|
||||
{
|
||||
// client.dll; 48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 30 48 8B 01 49
|
||||
using function_t = std::int64_t(__fastcall*)(void*, std::int64_t*, const char*);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 30 48 8B 01 48 8B F1 41 B0 01 48 8D 4C 24 20 48 8B FA 48 8B 98"));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
fn(this, &id, event_name.data());
|
||||
}
|
||||
|
||||
if (id == -1)
|
||||
return { };
|
||||
|
||||
// xref: "player_disconnect"
|
||||
// client.dll; E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B D8 48 85 C9
|
||||
using function_t2 = void*(__fastcall*)(std::int64_t);
|
||||
static function_t2 fn = reinterpret_cast<function_t2>(MEM::FindPattern(CLIENT_DLL, "E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B D8 48 85 C9"));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
|
||||
return fn(id);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#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"
|
||||
|
||||
// used: call virtual function
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
// used: color_t
|
||||
#include "../datatypes/color.h"
|
||||
|
||||
// used: cbasehandle
|
||||
#include "../entity.h"
|
||||
#include "../datatypes/utlstringtoken.h"
|
||||
using namespace MEM;
|
||||
|
||||
class IGameEvent
|
||||
{
|
||||
public:
|
||||
virtual ~IGameEvent() { }
|
||||
|
||||
[[nodiscard]] const char* GetName() const
|
||||
{
|
||||
// @ida: client.dll -> U8["48 8B CE FF 50 ? 48 8D 0D" + 0x5] @XREF: "show_freeze_panel"
|
||||
return CallVFunc<const char*, 1U>(this);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool GetBool(const CUtlStringToken& keyToken, bool bDefault = false) const
|
||||
{
|
||||
return CallVFunc<bool, 6U>(this, &keyToken, bDefault);
|
||||
}
|
||||
|
||||
[[nodiscard]] int GetInt(const CUtlStringToken& keyToken, int iDefault = 0) const
|
||||
{
|
||||
// @ida CGameEvent::GetInt(const char*, int): client.dll -> ABS["E8 ? ? ? ? 0F B6 4D 77" + 0x1]
|
||||
// @ida: client.dll -> U8["E8 ? ? ? ? 45 33 C0 48 89 74 24 ? 48 8D 54 24 ? 49 8B CF FF D3 85 C0 8B 44 24 48" - 0x1] / sizeof(std::uintptr_t) @XREF: "headshot"
|
||||
return CallVFunc<int, 7U>(this, &keyToken, iDefault);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint64_t GetUint64(const CUtlStringToken& keyToken, std::uint64_t ullDefault = 0ULL) const
|
||||
{
|
||||
return CallVFunc<std::uint64_t, 8U>(this, &keyToken, ullDefault);
|
||||
}
|
||||
|
||||
[[nodiscard]] float GetFloat(const CUtlStringToken& keyToken, const float flDefault = 0.0f) const
|
||||
{
|
||||
// @ida CGameEvent::GetFloat(const char*, float): client.dll -> ABS["E8 ? ? ? ? 0F 28 D8 89 5C 24 20" + 0x1]
|
||||
// @ida: client.dll -> U8["4C 8B 60 ? 4D 8B C6" + 0x3] / sizeof(std::uintptr_t) @XREF: "theta"
|
||||
return CallVFunc<float, 9U>(this, &keyToken, flDefault);
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* GetString(const CUtlStringToken& keyToken, const char* szDefault = "") const
|
||||
{
|
||||
// @ida: client.dll -> U8["48 8B 78 ? 48 8D 4D 80" + 0x3] / sizeof(std::uintptr_t) @XREF: "weapon"
|
||||
return CallVFunc<const char*, 10U>(this, &keyToken, szDefault);
|
||||
}
|
||||
|
||||
[[nodiscard]] const wchar_t* GetWString(const CUtlStringToken& keyToken, const wchar_t* wszDefault = L"") const
|
||||
{
|
||||
return CallVFunc<const wchar_t*, 11U>(this, &keyToken, wszDefault);
|
||||
}
|
||||
|
||||
[[nodiscard]] const void* GetPtr(const CUtlStringToken& keyToken) const
|
||||
{
|
||||
return CallVFunc<const void*, 12U>(this, &keyToken);
|
||||
}
|
||||
|
||||
int GetPlayerIndex(const CUtlStringToken& keyToken)
|
||||
{
|
||||
// @ida: client.dll -> U8["4C 8B 70 ? 4C 89 7C 24" + 0x3] / sizeof(std::uintptr_t) @XREF: "attacker", "assister", "userid"
|
||||
int nOutIndex;
|
||||
CallVFunc<void, 15U>(this, &nOutIndex, &keyToken);
|
||||
return nOutIndex;
|
||||
}
|
||||
|
||||
|
||||
// xref: client.dll & 4C 8B A8 80 00 00 00 ("killer")
|
||||
inline CBasePlayerController* get_player_controller(const std::string_view token_name) noexcept {
|
||||
CUtlStringToken token(token_name.data());
|
||||
return CallVFunc<CBasePlayerController*, 16U>(this, &token);
|
||||
|
||||
}
|
||||
C_CSPlayerPawn* GetPlayerPawn(const CUtlStringToken& keyToken)
|
||||
{
|
||||
// @XREF: "_pawn"
|
||||
// @ida CGameEvent::GetPlayerPawn(const char*): server.dll -> ABS["E8 ? ? ? ? 48 85 C0 74 0B 48 8B C8 E8 ? ? ? ? 4C 8B F0 41 8B 46 08" + 0x1] @XREF: "userid"
|
||||
return CallVFunc<C_CSPlayerPawn*, 17U>(this, &keyToken);
|
||||
}
|
||||
|
||||
void SetBool(const CUtlStringToken& keyToken, const bool bValue)
|
||||
{
|
||||
// @ida CGameEvent::SetBool(const char*, bool): server.dll -> ABS["E8 ? ? ? ? 48 8B 0D ? ? ? ? 45 33 C0 48 8B D3 48 8B 01 FF 50 38 48 8B 46 10" + 0x1] @XREF: "canbuy"
|
||||
CallVFunc<void, 20U>(this, &keyToken, bValue);
|
||||
}
|
||||
|
||||
void SetInt(const CUtlStringToken& keyToken, const int nValue)
|
||||
{
|
||||
// @ida: server.dll -> ["48 8D 4D A7 4C 8B B0 ? ? ? ? FF" + 0x7] / sizeof(std::uintptr_t)
|
||||
CallVFunc<void, 21U>(this, &keyToken, nValue);
|
||||
}
|
||||
|
||||
void SetUint64(const CUtlStringToken& keyToken, const std::uint64_t ullValue)
|
||||
{
|
||||
CallVFunc<void, 22U>(this, &keyToken, ullValue);
|
||||
}
|
||||
|
||||
void SetFloat(const CUtlStringToken& keyToken, const float flValue)
|
||||
{
|
||||
// @ida: server.dll -> ["48 8B B0 ? ? ? ? 33 D2 44 89 6C 24" + 0x3] / sizeof(std::uintptr_t) @XREF: "inferno_expire"
|
||||
CallVFunc<void, 23U>(this, &keyToken, flValue);
|
||||
}
|
||||
|
||||
void SetString(const CUtlStringToken& keyToken, const char* szValue)
|
||||
{
|
||||
// @ida: server.dll -> ["48 8D 4D A7 48 8B B8 ? ? ? ? 33" + 0x7] / sizeof(std::uintptr_t) @XREF: "weapon"
|
||||
CallVFunc<void, 24U>(this, &keyToken, szValue);
|
||||
}
|
||||
|
||||
void SetWString(const CUtlStringToken& keyToken, const wchar_t* wszValue)
|
||||
{
|
||||
CallVFunc<void, 25U>(this, &keyToken, wszValue);
|
||||
}
|
||||
|
||||
void SetPtr(const CUtlStringToken& keyToken, const void* pValue)
|
||||
{
|
||||
CallVFunc<void, 26U>(this, &keyToken, pValue);
|
||||
}
|
||||
|
||||
void SetPlayerIndex(const CUtlStringToken& keyToken, const int nIndex)
|
||||
{
|
||||
// @ida: server.dll -> ["48 8B B8 ? ? ? ? E8 ? ? ? ? 48 8D 05 ? ? ? ? 44 8B C3 48 8D 55 97 48 89 45 9F 48 8B CE FF D7 48 8D 15" + 0x3] / sizeof(std::uintptr_t) @XREF: "attacker_pawn"
|
||||
CallVFunc<void, 27U>(this, &keyToken, nIndex);
|
||||
}
|
||||
|
||||
void SetPlayerController(const CUtlStringToken& keyToken, CBasePlayerController* pPlayerController)
|
||||
{
|
||||
CallVFunc<void, 28U>(this, &keyToken, pPlayerController);
|
||||
}
|
||||
|
||||
void SetPlayerPawn(const CUtlStringToken& keyToken, C_CSPlayerPawn* pPlayerPawn)
|
||||
{
|
||||
// @XREF: "_pawn"
|
||||
CallVFunc<void, 29U>(this, &keyToken, pPlayerPawn);
|
||||
}
|
||||
|
||||
public:
|
||||
std::byte pad0[0x60]; // 0x08
|
||||
|
||||
void FireEvent(IGameEvent* event);
|
||||
|
||||
bool initialize();
|
||||
bool release();
|
||||
void* get_player_pawn_from_id(std::string_view event_name) noexcept;
|
||||
|
||||
/* output (name | int):
|
||||
team: 2
|
||||
dmg_health: 21
|
||||
entityid: 316
|
||||
defindex: 49
|
||||
radius: 1100
|
||||
*/
|
||||
std::int64_t get_int(std::string_view event_name) noexcept;
|
||||
|
||||
void* get_pointer_from_id(const std::string_view event_name) noexcept;
|
||||
};
|
||||
static_assert(sizeof(IGameEvent) == 0x68);
|
||||
|
||||
|
||||
|
||||
// todo: you can use this instead of hooking like you did it in csgo (input ur listeners), but that's a task for the reader.
|
||||
// client.dll; 48 89 05 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8D 8B E0 00 00 00
|
||||
struct event_manager_t {
|
||||
void init_event( /*C_CSPlayerPawnBase*/ void* player_pawn_base,
|
||||
const std::string_view event_name, void* unk = nullptr) noexcept {
|
||||
// (*(*g_pGameEventManager + 24i64))(g_pGameEventManager, a1 + 4680, "round_end", 0i64);
|
||||
return MEM::CallVFunc< void, 6U>(this, player_pawn_base, event_name.data(), unk);
|
||||
}
|
||||
};
|
||||
|
||||
class IGameEventManager2
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
SERVERSIDE = 0, // this is a server side listener, event logger etc
|
||||
CLIENTSIDE, // this is a client side listenet, HUD element etc
|
||||
CLIENTSTUB, // this is a serverside stub for a remote client listener (used by engine only)
|
||||
SERVERSIDE_OLD, // legacy support for old server event listeners
|
||||
CLIENTSIDE_OLD // legacy support for old client event listeners
|
||||
};
|
||||
|
||||
virtual ~IGameEventManager2() { }
|
||||
|
||||
/// load game event descriptions from a file e.g. "resource\gameevents.res"
|
||||
/// @Returns: count of loaded game events
|
||||
int LoadEventsFromFile(const char* szFileName)
|
||||
{
|
||||
return CallVFunc<int, 1U>(this, szFileName);
|
||||
}
|
||||
|
||||
// remove all and anything
|
||||
void Reset()
|
||||
{
|
||||
CallVFunc<void, 2U>(this);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -0,0 +1,165 @@
|
||||
#pragma once
|
||||
|
||||
// used: callvfunc
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
class CEconItemDefinition;
|
||||
|
||||
inline constexpr uint64_t Helper_GetAlternateIconKeyForWeaponPaintWearItem(
|
||||
uint16_t nDefIdx, uint32_t nPaintId, uint32_t nWear) {
|
||||
return (nDefIdx << 16) + (nPaintId << 2) + nWear;
|
||||
}
|
||||
|
||||
struct AlternateIconData_t {
|
||||
const char* sSimpleName;
|
||||
const char* sLargeSimpleName;
|
||||
|
||||
private:
|
||||
char pad0[0x8]; // no idea
|
||||
char pad1[0x8]; // no idea
|
||||
|
||||
};
|
||||
class CPaintKit {
|
||||
public:
|
||||
char pad_0x0000[0xE0]; //0x0000
|
||||
|
||||
int64_t PaintKitId() {
|
||||
return *reinterpret_cast<int64_t*>((uintptr_t)(this));
|
||||
}
|
||||
|
||||
const char* PaintKitName() {
|
||||
return *reinterpret_cast<const char**>((uintptr_t)(this) + 0x8);
|
||||
}
|
||||
|
||||
const char* PaintKitDescriptionString() {
|
||||
return *reinterpret_cast<const char**>((uintptr_t)(this) + 0x10);
|
||||
}
|
||||
|
||||
const char* PaintKitDescriptionTag() {
|
||||
return *reinterpret_cast<const char**>((uintptr_t)(this) + 0x18);
|
||||
}
|
||||
|
||||
int32_t PaintKitRarity() {
|
||||
return *reinterpret_cast<int32_t*>((uintptr_t)(this) + 0x44);
|
||||
}
|
||||
|
||||
bool UsesOldModel() {
|
||||
return *reinterpret_cast<bool*>((uintptr_t)(this) + 0xB2);
|
||||
}
|
||||
};
|
||||
#include "../cstrike/sdk/datatypes/utlmap.h"
|
||||
class CEconItemSchema {
|
||||
public:
|
||||
auto GetAttributeDefinitionInterface(int iAttribIndex) {
|
||||
return MEM::CallVFunc<void*, 27U> (this, iAttribIndex);
|
||||
}
|
||||
|
||||
auto& GetSortedItemDefinitionMap() {
|
||||
return *reinterpret_cast<CUtlMap<int, CEconItemDefinition*>*>(
|
||||
(uintptr_t)(this) + 0x128);
|
||||
}
|
||||
|
||||
auto& GetAlternateIconsMap() {
|
||||
return *reinterpret_cast<CUtlMap<uint64_t, AlternateIconData_t>*>(
|
||||
(uintptr_t)(this) + 0x278);
|
||||
}
|
||||
|
||||
auto& GetPaintKits() {
|
||||
return *reinterpret_cast<CUtlMap<int, CPaintKit*>*>((uintptr_t)(this) +
|
||||
0x2F0);
|
||||
}
|
||||
};
|
||||
|
||||
class CEconItemSystem {
|
||||
public:
|
||||
auto GetEconItemSchema() {
|
||||
return *reinterpret_cast<CEconItemSchema**>((uintptr_t)(this) + 0x8);
|
||||
}
|
||||
};
|
||||
|
||||
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 = 9,
|
||||
// finished rendering the scene
|
||||
FRAME_RENDER_END,
|
||||
FRAME_NET_FULL_FRAME_UPDATE_ON_REMOVE
|
||||
};
|
||||
|
||||
enum flow : int {
|
||||
FLOW_OUTGOING = 0,
|
||||
FLOW_INCOMING = 1,
|
||||
};
|
||||
|
||||
class INetChannelInfo {
|
||||
public:
|
||||
float get_latency(flow flow)
|
||||
{
|
||||
return MEM::CallVFunc<int, 10U>(this, flow);
|
||||
}
|
||||
};
|
||||
|
||||
class ISource2Client {
|
||||
public:
|
||||
auto GetEconItemSystem() {
|
||||
return MEM::CallVFunc<CEconItemSystem*, 114U>(this);
|
||||
}
|
||||
};
|
||||
|
||||
class IEngineClient
|
||||
{
|
||||
public:
|
||||
int GetMaxClients()
|
||||
{
|
||||
return MEM::CallVFunc<int, 31U>(this);
|
||||
}
|
||||
|
||||
bool IsInGame()
|
||||
{
|
||||
return MEM::CallVFunc<bool, 32U>(this);
|
||||
}
|
||||
|
||||
bool IsConnected()
|
||||
{
|
||||
return MEM::CallVFunc<bool, 33U>(this);
|
||||
}
|
||||
//gusta
|
||||
INetChannelInfo* GetNetChannelInfo(int split_screen_slot) {
|
||||
return MEM::CallVFunc<INetChannelInfo*, 34U>(this, split_screen_slot);
|
||||
}
|
||||
// return CBaseHandle index
|
||||
int GetLocalPlayer()
|
||||
{
|
||||
int nIndex = -1;
|
||||
|
||||
MEM::CallVFunc<void, 44U>(this, std::ref(nIndex), 0);
|
||||
|
||||
return nIndex + 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* GetLevelName()
|
||||
{
|
||||
return MEM::CallVFunc<const char*, 53U>(this);
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* GetLevelNameShort()
|
||||
{
|
||||
return MEM::CallVFunc<const char*, 54U>(this);
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* GetProductVersionString()
|
||||
{
|
||||
return MEM::CallVFunc<const char*, 77U>(this);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
// used: mem_pad
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
class CGameEntitySystem;
|
||||
|
||||
class IGameResourceService
|
||||
{
|
||||
public:
|
||||
MEM_PAD(0x58);
|
||||
CGameEntitySystem* pGameEntitySystem;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
// used: mem_pad
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
class IGlobalVars
|
||||
{
|
||||
public:
|
||||
float flRealTime; //0x0000
|
||||
__int32 nFrameCount; //0x0004
|
||||
float flFrameTime; //0x0008
|
||||
float flFrameTime2; //0x000C
|
||||
__int32 mMaxclients; //0x0010
|
||||
float flIntervalPerTick; //0x0014
|
||||
__int32 N0000007F; //0x0018
|
||||
__int32 N0000008B; //0x001C
|
||||
void* unkfunc; //0x0020
|
||||
float N00000081; //0x0028
|
||||
float flCurtime; //0x002C
|
||||
float flCurtime2; //0x0030
|
||||
MEM_PAD(0xC); //0x0034
|
||||
__int32 nTickCount; //0x0040
|
||||
float flIntervalPerTick2; //0x0044
|
||||
void* pCurrentNetChannel; //0x0048
|
||||
MEM_PAD(0x130); //0x0050
|
||||
char* szCurrentMap; //0x0180
|
||||
char* szCurrentMapName; //0x0188
|
||||
|
||||
}; //Size=0x0190
|
||||
|
||||
static_assert(sizeof(IGlobalVars) == 0x190);
|
||||
@@ -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) + 0x4F);
|
||||
}
|
||||
|
||||
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) + 0x2678);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
|
||||
// used: call virtual function
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
// used: color_t
|
||||
#include "../datatypes/color.h"
|
||||
|
||||
// used: cbasehandle
|
||||
#include "../entity_handle.h"
|
||||
|
||||
// material2
|
||||
class material2_t {
|
||||
public:
|
||||
virtual const char* get_name() = 0;
|
||||
virtual const char* get_shader_name() = 0;
|
||||
};
|
||||
|
||||
// material key var
|
||||
struct material_key_var_t {
|
||||
std::uint64_t m_key;
|
||||
const char* m_name;
|
||||
|
||||
material_key_var_t(std::uint64_t m_key, const char* m_name) :
|
||||
m_key(m_key), m_name(m_name) { }
|
||||
|
||||
material_key_var_t(const char* m_name, bool m_should_find_key = false) :
|
||||
m_name(m_name) {
|
||||
m_key = m_should_find_key ? find_key(m_name) : 0x0;
|
||||
}
|
||||
|
||||
// find key
|
||||
std::uint64_t find_key(const char* m_name) {
|
||||
// helper ida: CBodyGameSystem::NotifyResourcePreReload
|
||||
using function_find_key = std::uint64_t(__fastcall*)
|
||||
(const char*, unsigned int, int);
|
||||
static auto find_key_var = reinterpret_cast<function_find_key>(
|
||||
MEM::FindPattern(L"particles.dll", CS_XOR("48 89 5C 24 ? 57 48 81 EC ? ? ? ? 33 C0 8B DA")));
|
||||
|
||||
#ifdef CS_PARANOID
|
||||
CS_ASSERT(find_key_var != nullptr);
|
||||
#endif
|
||||
|
||||
return find_key_var(m_name, 0x12, 0x31415926);
|
||||
}
|
||||
};
|
||||
|
||||
// object info.
|
||||
class object_info_t {
|
||||
MEM_PAD(0xB0);
|
||||
int m_id;
|
||||
};
|
||||
|
||||
class scene_animable_object_t {
|
||||
MEM_PAD(0xB0);
|
||||
CBaseHandle m_owner;
|
||||
};
|
||||
|
||||
class material_data_t {
|
||||
public:
|
||||
void set_shader_type(const char* m_shader_name) {
|
||||
// E8 ? ? ? ? 48 8D B7 ? ? ? ?
|
||||
// spritecard.vfx
|
||||
using function_set_material_shader_type = void(__fastcall*)(void*, material_key_var_t, const char*, int);
|
||||
static auto set_material_shader = reinterpret_cast<function_set_material_shader_type>(MEM::FindPattern(L"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(set_material_shader != nullptr);
|
||||
#endif
|
||||
|
||||
material_key_var_t shader_vcar(0x162C1777, CS_XOR("shader"));
|
||||
set_material_shader(this, shader_vcar, m_shader_name, 0x18); // ida: 0x19
|
||||
}
|
||||
|
||||
void set_material_function(const char* function_name, int m_value) {
|
||||
using function_set_material = void(__fastcall*)(void*, material_key_var_t, int, int);
|
||||
static auto set_material = reinterpret_cast<function_set_material>(MEM::FindPattern(L"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(set_material != nullptr);
|
||||
#endif
|
||||
|
||||
material_key_var_t func_var(function_name, true);
|
||||
set_material(this, func_var, m_value, 0x18);
|
||||
}
|
||||
|
||||
MEM_PAD(0x18);
|
||||
scene_animable_object_t* m_scene_animable;
|
||||
material2_t* m_material;
|
||||
MEM_PAD(0x20);
|
||||
Color_t m_color;
|
||||
MEM_PAD(0x4);
|
||||
object_info_t* m_object_info;
|
||||
};
|
||||
|
||||
class material_system_t {
|
||||
public:
|
||||
material2_t*** find_or_create_from_resource(material2_t*** m_out_material, const char* m_material_name) {
|
||||
return MEM::CallVFunc<material2_t***, 14>(this, m_out_material, m_material_name);
|
||||
}
|
||||
|
||||
material2_t*** create_material(material2_t*** m_out_material, const char* m_material_name, material_data_t* m_data) {
|
||||
return MEM::CallVFunc<material2_t***, 29>(this, m_out_material, m_material_name, m_data, 0, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
void set_create_data_by_material(const void* m_data, material2_t*** const m_in_material) {
|
||||
return MEM::CallVFunc< void, 37 >(this, m_in_material, m_data);
|
||||
}
|
||||
|
||||
static void set_color(void* m_data, Color_t m_color) {
|
||||
*(byte*)((uintptr_t)m_data + 0x40) = m_color.r;
|
||||
*(byte*)((uintptr_t)m_data + 0x41) = m_color.g;
|
||||
*(byte*)((uintptr_t)m_data + 0x42) = m_color.b;
|
||||
*(byte*)((uintptr_t)m_data + 0x43) = m_color.a;
|
||||
}
|
||||
};
|
||||
@@ -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)
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
class CNetworkGameClient
|
||||
{
|
||||
public:
|
||||
bool IsConnected()
|
||||
{
|
||||
return MEM::CallVFunc<bool, 13U>(this);
|
||||
}
|
||||
|
||||
// force game to clear cache and reset delta tick
|
||||
void FullUpdate()
|
||||
{
|
||||
// @ida: #STR: "Requesting full game update (%s)...\n"
|
||||
MEM::CallVFunc<void, 31U>(this, CS_XOR("initial update"));
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
int* deltaTickPtr = reinterpret_cast<int*>(reinterpret_cast<std::uintptr_t>(this) + 0x258);
|
||||
|
||||
*deltaTickPtr = -1;
|
||||
}
|
||||
int GetDeltaTick()
|
||||
{
|
||||
// @ida: offset in FullUpdate();
|
||||
// (nDeltaTick = -1) == FullUpdate() called
|
||||
return *reinterpret_cast<int*>(reinterpret_cast<std::uintptr_t>(this) + 0x258);
|
||||
}
|
||||
};
|
||||
|
||||
class INetworkClientService
|
||||
{
|
||||
public:
|
||||
int deltatick() {
|
||||
return *reinterpret_cast<int*>(reinterpret_cast<std::uintptr_t>(this) + 0x258);
|
||||
}
|
||||
CNetworkGameClient* GetNetworkClient() {
|
||||
return MEM::CallVFunc<CNetworkGameClient*, 23>(this);
|
||||
}
|
||||
};
|
||||
@@ -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 0x190
|
||||
#define SCHEMASYSTEMTYPESCOPE_OFF1 0x4B0
|
||||
#define SCHEMASYSTEMTYPESCOPE_OFF2 0x2808
|
||||
|
||||
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
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "itrace.h"
|
||||
#include "../cstrike/sdk/interfaces/iengineclient.h"
|
||||
#include "../cstrike/sdk/interfaces/cgameentitysystem.h"
|
||||
#include "../cstrike/sdk/interfaces/igameresourceservice.h"
|
||||
@@ -0,0 +1,294 @@
|
||||
#pragma once
|
||||
// used: call virtual function
|
||||
#include "../../utilities/memory.h"
|
||||
|
||||
// used: color_t
|
||||
#include "../datatypes/color.h"
|
||||
|
||||
// used: cbasehandle
|
||||
#include "../entity_handle.h"
|
||||
#include "..\cstrike\core\sdk.h"
|
||||
#include "..\cstrike\sdk\entity.h"
|
||||
#define CLIP_TRACE_TO_PLAYERS "48 8B C4 55 56 48 8D A8 58 FF FF FF 48 81 EC 98 01 00 00 48"
|
||||
#define TRACE_SHAPE "48 89 54 24 ? 48 89 4C 24 ? 55 53 56 57 41 55 41 56 48 8D AC 24"
|
||||
#define COMBINE(x, y) x##y
|
||||
#define COMBINE2(x, y) COMBINE(x, y)
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
|
||||
#define PAD_CLASS_DEBUG(sz) int COMBINE2(pad_, __COUNTER__)[sz];
|
||||
#define CS2_PAD( number, size ) \
|
||||
private: \
|
||||
[[maybe_unused]] std::array< std::byte, size > m_unknown_##number{ }; \
|
||||
public:
|
||||
enum Contents_t {
|
||||
CONTENTS_EMPTY = 0,
|
||||
CONTENTS_SOLID = 0x1,
|
||||
CONTENTS_WINDOW = 0x2,
|
||||
CONTENTS_AUX = 0x4,
|
||||
CONTENTS_GRATE = 0x8,
|
||||
CONTENTS_SLIME = 0x10,
|
||||
CONTENTS_WATER = 0x20,
|
||||
CONTENTS_BLOCKLOS = 0x40,
|
||||
CONTENTS_OPAQUE = 0x80,
|
||||
CONTENTS_TESTFOGVOLUME = 0x100,
|
||||
CONTENTS_UNUSED = 0x200,
|
||||
CONTENTS_BLOCKLIGHT = 0x400,
|
||||
CONTENTS_TEAM1 = 0x800,
|
||||
CONTENTS_TEAM2 = 0x1000,
|
||||
CONTENTS_IGNORE_NODRAW_OPAQUE = 0x2000,
|
||||
CONTENTS_MOVEABLE = 0x4000,
|
||||
CONTENTS_AREAPORTAL = 0x8000,
|
||||
CONTENTS_PLAYERCLIP = 0x10000,
|
||||
CONTENTS_MONSTERCLIP = 0x20000,
|
||||
CONTENTS_CURRENT_0 = 0x40000,
|
||||
CONTENTS_CURRENT_90 = 0x80000,
|
||||
CONTENTS_CURRENT_180 = 0x100000,
|
||||
CONTENTS_CURRENT_270 = 0x200000,
|
||||
CONTENTS_CURRENT_UP = 0x400000,
|
||||
CONTENTS_CURRENT_DOWN = 0x800000,
|
||||
CONTENTS_ORIGIN = 0x1000000,
|
||||
CONTENTS_MONSTER = 0x2000000,
|
||||
CONTENTS_DEBRIS = 0x4000000,
|
||||
CONTENTS_DETAIL = 0x8000000,
|
||||
CONTENTS_TRANSLUCENT = 0x10000000,
|
||||
CONTENTS_LADDER = 0x20000000,
|
||||
CONTENTS_HITBOX = 0x40000000,
|
||||
};
|
||||
|
||||
enum Masks_t {
|
||||
MASK_ALL = 0xFFFFFFFF,
|
||||
MASK_SOLID = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE,
|
||||
MASK_PLAYERSOLID = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_PLAYERCLIP | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE,
|
||||
MASK_NPCSOLID = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MONSTERCLIP | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE,
|
||||
MASK_NPCFLUID = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MONSTERCLIP | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE,
|
||||
MASK_WATER = CONTENTS_WATER | CONTENTS_MOVEABLE | CONTENTS_SLIME,
|
||||
MASK_OPAQUE = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_OPAQUE,
|
||||
MASK_OPAQUE_AND_NPCS = MASK_OPAQUE | CONTENTS_MONSTER,
|
||||
MASK_BLOCKLOS = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_BLOCKLOS,
|
||||
MASK_BLOCKLOS_AND_NPCS = MASK_BLOCKLOS | CONTENTS_MONSTER,
|
||||
MASK_VISIBLE = MASK_OPAQUE | CONTENTS_IGNORE_NODRAW_OPAQUE,
|
||||
MASK_VISIBLE_AND_NPCS = MASK_OPAQUE_AND_NPCS | CONTENTS_IGNORE_NODRAW_OPAQUE,
|
||||
MASK_SHOT = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MONSTER | CONTENTS_WINDOW | CONTENTS_DEBRIS | CONTENTS_GRATE | CONTENTS_HITBOX,
|
||||
MASK_SHOT_BRUSHONLY = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_DEBRIS,
|
||||
MASK_SHOT_HULL = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MONSTER | CONTENTS_WINDOW | CONTENTS_DEBRIS | CONTENTS_GRATE,
|
||||
MASK_SHOT_PORTAL = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_MONSTER,
|
||||
MASK_SOLID_BRUSHONLY = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_GRATE,
|
||||
MASK_PLAYERSOLID_BRUSHONLY = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_PLAYERCLIP | CONTENTS_GRATE,
|
||||
MASK_NPCSOLID_BRUSHONLY = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_MONSTERCLIP | CONTENTS_GRATE,
|
||||
MASK_NPCWORLDSTATIC = CONTENTS_SOLID | CONTENTS_WINDOW | CONTENTS_MONSTERCLIP | CONTENTS_GRATE,
|
||||
MASK_NPCWORLDSTATIC_FLUID = CONTENTS_SOLID | CONTENTS_WINDOW | CONTENTS_MONSTERCLIP,
|
||||
MASK_SPLITAREPORTAL = CONTENTS_WATER | CONTENTS_SLIME,
|
||||
MASK_CURRENT = CONTENTS_CURRENT_0 | CONTENTS_CURRENT_90 | CONTENTS_CURRENT_180 | CONTENTS_CURRENT_270 | CONTENTS_CURRENT_UP | CONTENTS_CURRENT_DOWN,
|
||||
MASK_DEADSOLID = CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_WINDOW | CONTENTS_GRATE,
|
||||
};
|
||||
|
||||
enum {
|
||||
SURF_LIGHT = 0x0001,
|
||||
SURF_SKY2D = 0x0002,
|
||||
SURF_SKY = 0x0004,
|
||||
SURF_WARP = 0x0008,
|
||||
SURF_TRANS = 0x0010,
|
||||
SURF_NOPORTAL = 0x0020,
|
||||
SURF_TRIGGER = 0x0040,
|
||||
SURF_NODRAW = 0x0080,
|
||||
SURF_HINT = 0x0100,
|
||||
SURF_SKIP = 0x0200,
|
||||
SURF_NOLIGHT = 0x0400,
|
||||
SURF_BUMPLIGHT = 0x0800,
|
||||
SURF_NOSHADOWS = 0x1000,
|
||||
SURF_NODECALS = 0x2000,
|
||||
SURF_NOPAINT = SURF_NODECALS,
|
||||
SURF_NOCHOP = 0x4000,
|
||||
SURF_HITBOX = 0x8000
|
||||
};
|
||||
struct ray_t
|
||||
{
|
||||
Vector_t Start = Vector_t(0, 0, 0);
|
||||
Vector_t End = Vector_t(0, 0, 0);
|
||||
Vector_t Mins = Vector_t(0, 0, 0);
|
||||
Vector_t Maxs = Vector_t(0, 0, 0);
|
||||
char __pad0000[0x4];
|
||||
std::uint8_t UnkownType = 0x0;
|
||||
};
|
||||
static_assert(sizeof(ray_t) == 0x38);
|
||||
|
||||
class trace_filter_t
|
||||
{
|
||||
public:
|
||||
char __pad0000[0x8];
|
||||
std::uint64_t trace_mask ;
|
||||
std::uint64_t null_it[2] ;
|
||||
std::uint32_t SkipHandles[4];
|
||||
std::uint16_t Collisions[2] ;
|
||||
std::uint16_t N0000011C;
|
||||
std::uint8_t layer;
|
||||
std::uint8_t N00000104 ;
|
||||
std::uint8_t null_it3 ;
|
||||
|
||||
// manua initialization
|
||||
/*virtual ~trace_filter_t() {}
|
||||
virtual bool function() { return true; }
|
||||
trace_filter_t(C_CSPlayerPawn* skip, uint64_t mask, uint8_t layer, uint16_t idk)
|
||||
{
|
||||
//initfilter_19A770((__int64)filter, a2, 536577i64, 4, 7);
|
||||
using function_t = trace_filter_t * (__fastcall*)(trace_filter_t&, void*, uint64_t, uint8_t, uint16_t);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 0F B6 41 37 33")));
|
||||
// way better sig
|
||||
if (fn == nullptr) {
|
||||
L_PRINT(LOG_WARNING) << CS_XOR("trace_filter_t Invalid signature!");
|
||||
}
|
||||
|
||||
CS_ASSERT(fn != nullptr);
|
||||
|
||||
fn(*this, skip, mask, layer, idk);
|
||||
}*/
|
||||
};
|
||||
|
||||
struct C_TraceHitboxData {
|
||||
CS2_PAD(0, 0x38)
|
||||
int m_hitgroup{ };
|
||||
};
|
||||
|
||||
class game_trace_t {
|
||||
public:
|
||||
void* Surface;
|
||||
C_BaseEntity* HitEntity;
|
||||
C_TraceHitboxData* HitboxData;
|
||||
CS2_PAD(0, 0x38)
|
||||
std::uint32_t Contents;
|
||||
CS2_PAD(1, 0x24)
|
||||
Vector_t m_start_pos, m_end_pos, m_normal, m_pos;
|
||||
MEM_PAD(0x4);
|
||||
float Fraction;
|
||||
MEM_PAD(0x6);
|
||||
bool m_all_solid;
|
||||
CS2_PAD(4, 0x4D)
|
||||
};
|
||||
|
||||
|
||||
struct UpdateValueT {
|
||||
float previousLenght{ };
|
||||
float currentLenght{ };
|
||||
CS2_PAD(0, 0x8)
|
||||
std::int16_t handleIdx{ };
|
||||
CS2_PAD(1, 0x6)
|
||||
};
|
||||
struct trace_arr_element_t {
|
||||
CS2_PAD(0, 0x30)
|
||||
};
|
||||
|
||||
struct trace_data_t {
|
||||
std::int32_t m_uk1{ };
|
||||
float m_uk2{ 52.0f };
|
||||
void* m_arr_pointer{ };
|
||||
std::int32_t m_uk3{ 128 };
|
||||
std::int32_t m_uk4{ static_cast<std::int32_t>(0x80000000) };
|
||||
std::array< trace_arr_element_t, 0x80 > m_arr = { };
|
||||
CS2_PAD(0, 0x8)
|
||||
std::int64_t m_num_update{ };
|
||||
void* m_pointer_update_value{ };
|
||||
CS2_PAD(1, 0xC8)
|
||||
Vector_t m_start{ }, m_end{ };
|
||||
CS2_PAD(2, 0x50)
|
||||
};
|
||||
class i_trace
|
||||
{
|
||||
public: // cHoca
|
||||
void InitializeTraceInfo(game_trace_t* const hit )
|
||||
{
|
||||
using function_t = void(__fastcall*)(game_trace_t*);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, "48 89 5C 24 08 57 48 83 EC 20 48 8B D9 33 FF 48 8B 0D"));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
fn(hit);
|
||||
|
||||
}
|
||||
void InitializeTrace(game_trace_t& trace)
|
||||
{
|
||||
using function_t = void(__fastcall*)(game_trace_t&);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, "48 89 5C 24 08 57 48 83 EC 20 48 8B D9 33 FF 48 8B 0D"));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
fn(trace);
|
||||
|
||||
}
|
||||
// cHoca
|
||||
|
||||
void Init(trace_filter_t& filter, C_CSPlayerPawn* skip, uint64_t mask, uint8_t layer, uint16_t idk)
|
||||
{
|
||||
//initfilter_19A770((__int64)filter, a2, 536577i64, 4, 7);
|
||||
using function_t = trace_filter_t*(__fastcall*)(trace_filter_t&, void*, uint64_t, uint8_t, uint16_t);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 0F B6 41 37 33")));
|
||||
// way better sig
|
||||
if (fn == nullptr) {
|
||||
L_PRINT(LOG_WARNING) << CS_XOR("trace_filter_t Invalid signature!");
|
||||
}
|
||||
|
||||
CS_ASSERT(fn != nullptr);
|
||||
|
||||
fn(filter, skip, mask, layer, idk);
|
||||
}
|
||||
// __int64 __fastcall sub_695330(__int64 a1, __int64 a2, __int64 a3, __int64 a4, float a5, int a6, float a7)
|
||||
// #STR: "particles/impact_fx/impact_wallbang_heavy.vpcf", "particles/impact_fx/impact_wallbang_light.vpcf", "particles/impact_fx/impact_wallbang_light_silent.vpcf", "gunshotsplash"
|
||||
// local variable allocation has failed, the output may be wrong!
|
||||
//abaixo da funcao
|
||||
void ClipTraceToPlayers(Vector_t& start, Vector_t& end, trace_filter_t* filter, game_trace_t* trace, float min, int length, float max)
|
||||
{ // cHoca
|
||||
|
||||
using function_t = void(__fastcall*)(Vector_t&, Vector_t&, trace_filter_t*, game_trace_t*, float, int, float);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, CLIP_TRACE_TO_PLAYERS));
|
||||
// way better sig
|
||||
if (fn == nullptr) {
|
||||
L_PRINT(LOG_WARNING) << CS_XOR("ClipTraceToPlayers creating new signature!");
|
||||
fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, "48 8B C4 55 56 48 8D A8 58"));
|
||||
}
|
||||
|
||||
CS_ASSERT(fn != nullptr);
|
||||
|
||||
fn(start, end, filter, trace, min, max, length);
|
||||
}
|
||||
// cHoca
|
||||
// client.dll; 48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 56 48 83 EC 40 F2
|
||||
// client.dll; 48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B E9 0F
|
||||
|
||||
static void get_trace_info(trace_data_t* trace, game_trace_t* hit,
|
||||
const float unknown_float, void* unknown) {
|
||||
|
||||
using function_t = void(__fastcall*)(trace_data_t*, game_trace_t*, float, void*);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B E9 0F")));
|
||||
|
||||
return fn(trace, hit, unknown_float, unknown);
|
||||
}
|
||||
// william: there is no need to rebuild this function.
|
||||
// client.dll; 48 8B C4 44 89 48 20 55 57 41 55
|
||||
static bool handle_bullet_penetration(trace_data_t* const trace, void* stats,
|
||||
UpdateValueT* const mod_value,
|
||||
const bool draw_showimpacts = false) {
|
||||
|
||||
using function_t = bool(__fastcall*)(trace_data_t*, void*, UpdateValueT*, void*, void*, void*, void*, void*, bool);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 8B C4 44 89 48 20 55 57 41 55")));
|
||||
|
||||
return fn(trace, stats, mod_value, nullptr, nullptr, nullptr, nullptr, nullptr, draw_showimpacts);
|
||||
}
|
||||
|
||||
static void CreateTrace(trace_data_t* const trace, const Vector_t start,
|
||||
const Vector_t end, const trace_filter_t& filler,
|
||||
const int penetration_count) {
|
||||
|
||||
|
||||
using function_t = void(__fastcall*)(trace_data_t*, Vector_t, Vector_t,
|
||||
trace_filter_t, int);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 56 41 57 48 83 EC 40 F2")));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
return fn(trace, start, end, filler, penetration_count);
|
||||
}
|
||||
|
||||
// #STR: "Physics/TraceShape (Client)" then xref
|
||||
void TraceShape(ray_t& ray, Vector_t* start, Vector_t* end, trace_filter_t filter, game_trace_t& trace)
|
||||
{
|
||||
using function_t = bool(__fastcall*)(void*, ray_t&, Vector_t*, Vector_t*, trace_filter_t, game_trace_t&);
|
||||
static function_t fn = reinterpret_cast<function_t>(MEM::FindPattern(CLIENT_DLL, "48 89 5C 24 10 48 89 74 24 18 48 89 7C 24 20 48 89 4C 24 08 55 41 54 41 55 41 56 41 57 48 8D"));
|
||||
CS_ASSERT(fn != nullptr);
|
||||
fn(this, ray, start, end, filter, trace);
|
||||
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "../datatypes/qangle.h"
|
||||
#include "../datatypes/matrix.h"
|
||||
#include "../../core/memaddon.hpp"
|
||||
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
|
||||
};
|
||||
#ifndef CS2_CHEAT_CRENDERGAMESYSTEM_HPP
|
||||
#define CS2_CHEAT_CRENDERGAMESYSTEM_HPP
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // CS2_CHEAT_CRENDERGAMESYSTEM_HPP
|
||||
Reference in New Issue
Block a user