This commit is contained in:
Oscar
2025-07-22 22:06:34 +03:00
parent d3c189f949
commit f892794557
780 changed files with 436498 additions and 170 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,139 @@
#pragma once
// used: [ext] minhook
// @credits: https://github.com/TsudaKageyu/minhook
#include "../../dependencies/minhook/minhook.h"
// used: l_print
#include "log.h"
template <typename T>
class CBaseHookObject
{
public:
/// setup hook and replace function
/// @returns: true if hook has been successfully created, false otherwise
bool Create(void* pFunction, void* pDetour)
{
if (pFunction == nullptr || pDetour == nullptr)
return false;
pBaseFn = pFunction;
pReplaceFn = pDetour;
if (const MH_STATUS status = MH_CreateHook(pBaseFn, pReplaceFn, &pOriginalFn); status != MH_OK)
{
#ifdef _DEBUG
L_PRINT(LOG_ERROR) << CS_XOR("failed to create hook, status: \"") << MH_StatusToString(status) << CS_XOR("\" with base address: ") << L::AddFlags(LOG_MODE_INT_SHOWBASE | LOG_MODE_INT_FORMAT_HEX) << reinterpret_cast<std::uintptr_t>(pBaseFn);
#else
L_PRINT(LOG_ERROR) << CS_XOR("failed to create hook");
#endif
CS_ASSERT(false);
return false;
}
if (!Replace())
return false;
return true;
}
/// patch memory to jump to our function instead of original
/// @returns: true if hook has been successfully applied, false otherwise
bool Replace()
{
// check is hook has been created
if (pBaseFn == nullptr)
return false;
// check that function isn't already hooked
if (bIsHooked)
return false;
if (const MH_STATUS status = MH_EnableHook(pBaseFn); status != MH_OK)
{
#ifdef _DEBUG
L_PRINT(LOG_ERROR) << CS_XOR("failed to enable hook, status: \"") << MH_StatusToString(status) << CS_XOR("\" with base address: ") << L::AddFlags(LOG_MODE_INT_SHOWBASE | LOG_MODE_INT_FORMAT_HEX) << reinterpret_cast<std::uintptr_t>(pBaseFn);
#else
L_PRINT(LOG_ERROR) << CS_XOR("failed to enable hook");
#endif
CS_ASSERT(false);
return false;
}
// switch hook state
bIsHooked = true;
return true;
}
/// restore original function call and cleanup hook data
/// @returns: true if hook has been successfully removed, false otherwise
bool Remove()
{
// restore it at first
if (!Restore())
return false;
if (const MH_STATUS status = MH_RemoveHook(pBaseFn); status != MH_OK)
{
#ifdef _DEBUG
L_PRINT(LOG_ERROR) << CS_XOR("failed to remove hook, status: \"") << MH_StatusToString(status) << CS_XOR("\" with base address: ") << L::AddFlags(LOG_MODE_INT_SHOWBASE | LOG_MODE_INT_FORMAT_HEX) << reinterpret_cast<std::uintptr_t>(pBaseFn);
#else
L_PRINT(LOG_ERROR) << CS_XOR("failed to remove hook");
#endif
CS_ASSERT(false);
return false;
}
return true;
}
/// restore patched memory to original function call
/// @returns: true if hook has been successfully restored, false otherwise
bool Restore()
{
// check that function is hooked
if (!bIsHooked)
return false;
if (const MH_STATUS status = MH_DisableHook(pBaseFn); status != MH_OK)
{
#ifdef _DEBUG
L_PRINT(LOG_ERROR) << CS_XOR("failed to restore hook, status: \"") << MH_StatusToString(status) << CS_XOR("\" with base address: ") << L::AddFlags(LOG_MODE_INT_SHOWBASE | LOG_MODE_INT_FORMAT_HEX) << reinterpret_cast<std::uintptr_t>(pBaseFn);
#else
L_PRINT(LOG_ERROR) << CS_XOR("failed to restore hook");
#endif
CS_ASSERT(false);
return false;
}
// switch hook state
bIsHooked = false;
return true;
}
/// @returns: original, unwrapped function that would be called without the hook
CS_INLINE T GetOriginal()
{
return reinterpret_cast<T>(pOriginalFn);
}
/// @returns: true if hook is applied at the time, false otherwise
CS_INLINE bool IsHooked() const
{
return bIsHooked;
}
private:
// current hook state
bool bIsHooked = false;
// function base handle
void* pBaseFn = nullptr;
// function that being replace the original call
void* pReplaceFn = nullptr;
// original function
void* pOriginalFn = nullptr;
};

View File

@@ -0,0 +1,830 @@
#include "draw.h"
// used: cheat variables
#include "../core/variables.h"
// used: viewmatrix
#include "../core/sdk.h"
// used: m_deg2rad
#include "math.h"
// used: memoryset
#include "crt.h"
// used: easing
#include "easing.h"
// used: ipt
#include "inputsystem.h"
// used: [ext] imgui
#include "../../dependencies/imgui/imgui_freetype.h"
#include "../../dependencies/imgui/imgui_impl_dx11.h"
#include "../../dependencies/imgui/imgui_impl_win32.h"
// used: [resouces] font awesome
#include "../../resources/fa_solid_900.h"
#include "../../resources/font_awesome_5.h"
// used: iinputsystem
#include "../core/interfaces.h"
#include "../sdk/interfaces/iinputsystem.h"
// used: bMainWindowOpened
#include "../core/menu.h"
// used: hkIsRelativeMouseMode.GetOriginal();
#include "../core/hooks.h"
#pragma region imgui_extended
static constexpr const char* arrKeyNames[] = {
"",
"mouse 1", "mouse 2", "cancel", "mouse 3", "mouse 4", "mouse 5", "",
"backspace", "tab", "", "", "clear", "enter", "", "",
"shift", "control", "alt", "pause", "caps", "", "", "", "", "", "",
"escape", "", "", "", "", "space", "page up", "page down",
"end", "home", "left", "up", "right", "down", "", "", "",
"print", "insert", "delete", "",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"", "", "", "", "", "", "",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
"v", "w", "x", "y", "z", "lwin", "rwin", "", "", "",
"num0", "num1", "num2", "num3", "num4", "num5",
"num6", "num7", "num8", "num9",
"*", "+", "", "-", ".", "/",
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8",
"f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16",
"f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24",
"", "", "", "", "", "", "", "",
"num lock", "scroll lock",
"", "", "", "", "", "", "",
"", "", "", "", "", "", "",
"lshift", "rshift", "lctrl",
"rctrl", "lmenu", "rmenu"
};
void ImGui::HelpMarker(const char* szDescription)
{
TextDisabled(CS_XOR("(?)"));
if (IsItemHovered())
{
BeginTooltip();
PushTextWrapPos(450.f);
TextUnformatted(szDescription);
PopTextWrapPos();
EndTooltip();
}
}
bool ImGui::HotKey(const char* szLabel, unsigned int* pValue)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* pWindow = g.CurrentWindow;
if (pWindow->SkipItems)
return false;
ImGuiIO& io = g.IO;
const ImGuiStyle& style = g.Style;
const ImGuiID nIndex = pWindow->GetID(szLabel);
const float flWidth = CalcItemWidth();
const ImVec2 vecLabelSize = CalcTextSize(szLabel, nullptr, true);
const ImRect rectFrame(pWindow->DC.CursorPos + ImVec2(vecLabelSize.x > 0.0f ? style.ItemInnerSpacing.x + GetFrameHeight() : 0.0f, 0.0f), pWindow->DC.CursorPos + ImVec2(flWidth, vecLabelSize.x > 0.0f ? vecLabelSize.y + style.FramePadding.y : 0.f));
const ImRect rectTotal(rectFrame.Min, rectFrame.Max);
ItemSize(rectTotal, style.FramePadding.y);
if (!ItemAdd(rectTotal, nIndex, &rectFrame))
return false;
const bool bHovered = ItemHoverable(rectFrame, nIndex, ImGuiItemFlags_None);
if (bHovered)
{
SetHoveredID(nIndex);
g.MouseCursor = ImGuiMouseCursor_TextInput;
}
const bool bClicked = bHovered && io.MouseClicked[0];
const bool bDoubleClicked = bHovered && io.MouseDoubleClicked[0];
if (bClicked || bDoubleClicked)
{
if (g.ActiveId != nIndex)
{
CRT::MemorySet(io.MouseDown, 0, sizeof(io.MouseDown));
CRT::MemorySet(io.KeysDown, 0, sizeof(io.KeysDown));
*pValue = 0U;
}
SetActiveID(nIndex, pWindow);
FocusWindow(pWindow);
}
bool bValueChanged = false;
if (unsigned int nKey = *pValue; g.ActiveId == nIndex)
{
for (int n = 0; n < IM_ARRAYSIZE(io.MouseDown); n++)
{
if (IsMouseDown(n))
{
switch (n)
{
case 0:
nKey = VK_LBUTTON;
break;
case 1:
nKey = VK_RBUTTON;
break;
case 2:
nKey = VK_MBUTTON;
break;
case 3:
nKey = VK_XBUTTON1;
break;
case 4:
nKey = VK_XBUTTON2;
break;
}
bValueChanged = true;
ClearActiveID();
}
}
if (!bValueChanged)
{
for (int n = VK_BACK; n <= VK_RMENU; n++)
{
if (IsKeyDown((ImGuiKey)n))
{
nKey = n;
bValueChanged = true;
ClearActiveID();
}
}
}
if (IsKeyPressed(ImGuiKey_Escape))
{
*pValue = 0U;
ClearActiveID();
}
else
*pValue = nKey;
}
char szBuffer[64] = {};
char* szBufferEnd = CRT::StringCopy(szBuffer, " ");
if (*pValue != 0 && g.ActiveId != nIndex)
szBufferEnd = CRT::StringCat(szBufferEnd, arrKeyNames[*pValue]);
else if (g.ActiveId == nIndex)
szBufferEnd = CRT::StringCat(szBufferEnd, CS_XOR("press"));
else
szBufferEnd = CRT::StringCat(szBufferEnd, CS_XOR("none"));
CRT::StringCat(szBufferEnd, " ");
// modified by asphyxia
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, -1));
const ImVec2 vecBufferSize = CalcTextSize(szBuffer);
RenderFrame(ImVec2(rectFrame.Max.x - vecBufferSize.x, rectTotal.Min.y), ImVec2(rectFrame.Max.x, rectTotal.Min.y + style.FramePadding.y + vecBufferSize.y), GetColorU32((bHovered || bClicked || bDoubleClicked) ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
pWindow->DrawList->AddText(ImVec2(rectFrame.Max.x - vecBufferSize.x, rectTotal.Min.y + style.FramePadding.y), GetColorU32(g.ActiveId == nIndex ? ImGuiCol_Text : ImGuiCol_TextDisabled), szBuffer);
if (vecLabelSize.x > 0.f)
RenderText(ImVec2(rectTotal.Min.x, rectTotal.Min.y + style.FramePadding.y), szLabel);
PopStyleVar();
return bValueChanged;
}
bool ImGui::HotKey(const char* szLabel, KeyBind_t* pKeyBind, const bool bAllowSwitch)
{
const bool bValueChanged = HotKey(szLabel, &pKeyBind->uKey);
if (bAllowSwitch)
{
char* szUniqueID = static_cast<char*>(MEM_STACKALLOC(CRT::StringLength(szLabel) + 6));
CRT::StringCat(CRT::StringCopy(szUniqueID, CS_XOR("key##")), szLabel);
if (IsItemClicked(ImGuiMouseButton_Right))
OpenPopup(szUniqueID);
if (BeginPopup(szUniqueID))
{
SetNextItemWidth(ImGui::GetWindowWidth() * 0.75f);
if (Combo(CS_XOR("##keybind.mode"), reinterpret_cast<int*>(&pKeyBind->nMode), CS_XOR("Hold\0Toggle\0\0")))
CloseCurrentPopup();
EndPopup();
}
MEM_STACKFREE(szUniqueID);
}
return bValueChanged;
}
bool ImGui::MultiCombo(const char* szLabel, unsigned int* pFlags, const char* const* arrItems, int nItemsCount)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* pWindow = g.CurrentWindow;
if (pWindow->SkipItems)
return false;
IM_ASSERT(nItemsCount < 32); // bitflags shift overflow, decrease items count or change variable type
const ImGuiStyle& style = g.Style;
const ImVec2 vecLabelSize = CalcTextSize(szLabel, nullptr, true);
const float flActiveWidth = CalcItemWidth() - (vecLabelSize.x > 0.0f ? style.ItemInnerSpacing.x + GetFrameHeight() : 0.0f);
std::vector<const char*> vecActiveItems = {};
// collect active items
for (int i = 0; i < nItemsCount; i++)
{
if (*pFlags & (1 << i))
vecActiveItems.push_back(arrItems[i]);
}
// fuck it, stl still haven't boost::join, fmt::join replacement
std::string strBuffer = {};
for (std::size_t i = 0U; i < vecActiveItems.size(); i++)
{
strBuffer.append(vecActiveItems[i]);
if (i < vecActiveItems.size() - 1U)
strBuffer.append(", ");
}
if (strBuffer.empty())
strBuffer.assign("none");
else
{
const char* szWrapPosition = g.Font->CalcWordWrapPositionA(GetCurrentWindow()->FontWindowScale, strBuffer.data(), strBuffer.data() + strBuffer.length(), flActiveWidth - style.FramePadding.x * 2.0f);
const std::size_t nWrapLength = szWrapPosition - strBuffer.data();
if (nWrapLength > 0U && nWrapLength < strBuffer.length())
{
strBuffer.resize(nWrapLength);
strBuffer.append("...");
}
}
bool bValueChanged = false;
if (BeginCombo(szLabel, strBuffer.c_str()))
{
for (int i = 0; i < nItemsCount; i++)
{
const int nCurrentFlag = (1 << i);
if (Selectable(arrItems[i], (*pFlags & nCurrentFlag), ImGuiSelectableFlags_DontClosePopups))
{
// flip bitflag
*pFlags ^= nCurrentFlag;
bValueChanged = true;
}
}
EndCombo();
}
return bValueChanged;
}
bool ImGui::BeginListBox(const char* szLabel, int nItemsCount, int nHeightInItems)
{
float height = GetTextLineHeightWithSpacing() * ((nHeightInItems < 0 ? ImMin(nItemsCount, 7) : nHeightInItems) + 0.25f) + GetStyle().FramePadding.y * 2.0f;
return BeginListBox(szLabel, ImVec2(0.0f, height));
}
bool ImGui::ColorEdit3(const char* szLabel, Color_t* pColor, ImGuiColorEditFlags flags)
{
return ColorEdit4(szLabel, pColor, flags | ImGuiColorEditFlags_NoAlpha);
}
bool ImGui::ColorEdit4(const char* szLabel, Color_t* pColor, ImGuiColorEditFlags flags)
{
float arrColor[4];
pColor->BaseAlpha(arrColor);
if (ColorEdit4(szLabel, &arrColor[0], flags))
{
*pColor = Color_t::FromBase4(arrColor);
return true;
}
return false;
}
bool ImGui::ColorEdit3(const char* szLabel, ColorPickerVar_t* pColor, ImGuiColorEditFlags flags)
{
return ColorEdit4(szLabel, pColor, flags | ImGuiColorEditFlags_NoAlpha);
}
bool ImGui::ColorEdit4(const char* szLabel, ColorPickerVar_t* pColorVar, ImGuiColorEditFlags flags)
{
const bool bResult = ColorEdit4(szLabel, &pColorVar->colValue, flags);
// switch rainbow mode on middle mouse click
if (IsItemHovered())
{
// tooltip for turn on/off rainbow mode
BeginTooltip();
{
PushTextWrapPos(450.f);
TextUnformatted(CS_XOR("use mouse middle-click to turn on/off rainbow mode!"));
PopTextWrapPos();
}
EndTooltip();
if (IsMouseClicked(ImGuiMouseButton_Middle))
pColorVar->bRainbow = !pColorVar->bRainbow;
}
// open the context popup
OpenPopupOnItemClick(CS_XOR("context##color.picker"), ImGuiPopupFlags_MouseButtonRight);
// @todo: cleaner code
SetNextWindowSize(ImVec2((pColorVar->bRainbow ? 120.f : 60.f) * D::CalculateDPI(C_GET(int, Vars.nDpiScale)), 0.f));
if (BeginPopup(CS_XOR("context##color.picker")))
{
if (Button(CS_XOR("copy##color.picker"), ImVec2(-1, 15 * D::CalculateDPI(C_GET(int, Vars.nDpiScale)))))
{
// @todo: im32 hex format is AARRGGBB, but we need RRGGBBAA
CRT::String_t<64U> szBuffer(CS_XOR("#%X"), pColorVar->colValue.GetU32());
SetClipboardText(szBuffer.Data());
szBuffer.Clear();
CloseCurrentPopup();
}
if (Button(CS_XOR("paste##color.picker"), ImVec2(-1, 15 * D::CalculateDPI(C_GET(int, Vars.nDpiScale)))))
{
const char* szClipboardText = GetClipboardText();
// @note: +1U for '#' prefix skipping
const ImU32 uConvertedColor = CRT::StringToInteger<ImU32>(szClipboardText + 1U, nullptr, 16);
pColorVar->colValue = Color_t(uConvertedColor);
CloseCurrentPopup();
}
if (pColorVar->bRainbow)
{
// @note: urgh padding moment idk
SetNextItemWidth(ImGui::GetWindowWidth() * 0.90f + 1.f);
SliderFloat(CS_XOR("##speed.color.picker"), &pColorVar->flRainbowSpeed, 0.f, 5.f, CS_XOR("speed: %.1f"), ImGuiSliderFlags_AlwaysClamp);
}
EndPopup();
}
return bResult;
}
#pragma endregion
// thread-safe draw data mutex
static SRWLOCK drawLock = {};
static void* __cdecl ImGuiAllocWrapper(const std::size_t nSize, [[maybe_unused]] void* pUserData = nullptr)
{
return MEM::HeapAlloc(nSize);
}
static void __cdecl ImGuiFreeWrapper(void* pMemory, [[maybe_unused]] void* pUserData = nullptr) noexcept
{
MEM::HeapFree(pMemory);
}
bool D::Setup(HWND hWnd, ID3D11Device* pDevice, ID3D11DeviceContext* pContext)
{
// check is it were already initialized
if (bInitialized)
return true;
ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper);
ImGui::CreateContext();
// setup platform and renderer bindings
if (!ImGui_ImplWin32_Init(hWnd))
return false;
if (!ImGui_ImplDX11_Init(pDevice, pContext))
return false;
// create draw data containers
pDrawListActive = IM_NEW(ImDrawList)(ImGui::GetDrawListSharedData());
pDrawListSafe = IM_NEW(ImDrawList)(ImGui::GetDrawListSharedData());
pDrawListRender = IM_NEW(ImDrawList)(ImGui::GetDrawListSharedData());
// setup styles
#pragma region draw_setup_style
ImGuiStyle& style = ImGui::GetStyle();
style.Alpha = 1.0f;
style.WindowPadding = ImVec2(8, 8);
style.WindowRounding = 4.0f;
style.WindowBorderSize = 1.0f;
style.WindowMinSize = ImVec2(32, 32);
style.WindowTitleAlign = ImVec2(0.5f, 0.5f);
style.ChildRounding = 4.0f;
style.ChildBorderSize = 1.0f;
style.PopupRounding = 4.0f;
style.PopupBorderSize = 1.0f;
style.FramePadding = ImVec2(4, 2);
style.FrameRounding = 4.0f;
style.FrameBorderSize = 1.0f;
style.ItemSpacing = ImVec2(8, 4);
style.ItemInnerSpacing = ImVec2(4, 4);
style.IndentSpacing = 6.0f;
style.ColumnsMinSpacing = 6.0f;
style.ScrollbarSize = 6.0f;
style.ScrollbarRounding = 9.0f;
style.GrabMinSize = 0.0f;
style.GrabRounding = 4.0f;
style.TabRounding = 4.0f;
style.TabBorderSize = 1.0f;
style.ButtonTextAlign = ImVec2(0.5f, 0.5f);
style.SelectableTextAlign = ImVec2(0.0f, 0.5f);
style.WindowShadowSize = 0.f;
style.AntiAliasedLines = true;
style.AntiAliasedFill = true;
style.AntiAliasedLinesUseTex = true;
style.ColorButtonPosition = ImGuiDir_Right;
#pragma endregion
ImGuiIO& io = ImGui::GetIO();
static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig icons_config;
icons_config.MergeMode = true;
icons_config.PixelSnapH = true;
icons_config.FontDataOwnedByAtlas = false;
io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
ImFontConfig imVerdanaConfig;
imVerdanaConfig.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LightHinting;
for (int i = 0; i < CS_ARRAYSIZE(FONT::pMenu); i++)
{
const float flFontSize = 12.f * CalculateDPI(i);
FONT::pMenu[i] = io.Fonts->AddFontFromFileTTF(CS_XOR("C:\\Windows\\Fonts\\Verdana.ttf"), flFontSize, &imVerdanaConfig, io.Fonts->GetGlyphRangesCyrillic());
io.Fonts->AddFontFromMemoryTTF((void*)fa_solid_900, sizeof(fa_solid_900), flFontSize, &icons_config, icons_ranges);
}
imVerdanaConfig.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_Bold;
FONT::pExtra = io.Fonts->AddFontFromFileTTF(CS_XOR("C:\\Windows\\Fonts\\Verdana.ttf"), 14.f, &imVerdanaConfig, io.Fonts->GetGlyphRangesCyrillic());
ImFontConfig imTahomaConfig;
imTahomaConfig.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LightHinting;
FONT::pVisual = io.Fonts->AddFontFromFileTTF(CS_XOR("C:\\Windows\\Fonts\\Tahoma.ttf"), 14.f, &imTahomaConfig, io.Fonts->GetGlyphRangesCyrillic());
io.Fonts->FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LightHinting;
bInitialized = io.Fonts->Build();
return bInitialized;
}
void D::Destroy()
{
// check is it already destroyed or wasn't initialized at all
if (!bInitialized)
return;
// free draw data containers
IM_DELETE(pDrawListActive);
IM_DELETE(pDrawListSafe);
IM_DELETE(pDrawListRender);
// shutdown imgui directx9 renderer binding
ImGui_ImplDX11_Shutdown();
// shutdown imgui win32 platform binding
ImGui_ImplWin32_Shutdown();
// destroy imgui context
ImGui::DestroyContext();
bInitialized = false;
}
#pragma region draw_callbacks
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
bool D::OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// check is drawing initialized
if (!bInitialized)
return false;
IPT::OnWndProc(hWnd, uMsg, wParam, lParam);
// switch menu state
if (IPT::IsKeyReleased(C_GET(unsigned int, Vars.nMenuKey)))
{
MENU::bMainWindowOpened = !MENU::bMainWindowOpened;
// update animation
MENU::animMenuDimBackground.Switch();
// handle IsRelativeMouseMode original
const auto oIsRelativeMouseMode = H::hkIsRelativeMouseMode.GetOriginal();
oIsRelativeMouseMode(I::InputSystem, MENU::bMainWindowOpened ? false : MENU::bMainActive);
}
// handle ImGui's window messages and block game's input if menu is opened
return ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam) || MENU::bMainWindowOpened;
}
void D::NewFrame()
{
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
}
void D::Render()
{
ImGui::Render();
RenderDrawData(ImGui::GetDrawData());
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
}
#pragma endregion
#pragma region draw_main
void D::RenderDrawData(ImDrawData* pDrawData)
{
if (::TryAcquireSRWLockExclusive(&drawLock))
{
*pDrawListRender = *pDrawListSafe;
::ReleaseSRWLockExclusive(&drawLock);
}
if (pDrawListRender->CmdBuffer.empty())
return;
// remove trailing command if unused
// @note: equivalent to pDrawList->_PopUnusedDrawCmd()
if (const ImDrawCmd& lastCommand = pDrawListRender->CmdBuffer.back(); lastCommand.ElemCount == 0 && lastCommand.UserCallback == nullptr)
{
pDrawListRender->CmdBuffer.pop_back();
if (pDrawListRender->CmdBuffer.empty())
return;
}
ImGuiContext* pContext = ImGui::GetCurrentContext();
ImGuiViewportP* pViewport = pContext->Viewports[0];
ImVector<ImDrawList*>* vecDrawLists = pViewport->DrawDataBuilder.Layers[0];
vecDrawLists->push_front(pDrawListRender); // this one being most background
pDrawData->CmdLists.push_front(pDrawListRender);
pDrawData->CmdListsCount = vecDrawLists->Size;
pDrawData->TotalVtxCount += pDrawListRender->VtxBuffer.Size;
pDrawData->TotalIdxCount += pDrawListRender->IdxBuffer.Size;
}
void D::ResetDrawData()
{
pDrawListActive->_ResetForNewFrame();
pDrawListActive->PushTextureID(ImGui::GetIO().Fonts->TexID);
pDrawListActive->PushClipRectFullScreen();
}
void D::SwapDrawData()
{
::AcquireSRWLockExclusive(&drawLock);
IM_ASSERT(pDrawListActive->VtxBuffer.Size == 0 || pDrawListActive->_VtxWritePtr == pDrawListActive->VtxBuffer.Data + pDrawListActive->VtxBuffer.Size);
IM_ASSERT(pDrawListActive->IdxBuffer.Size == 0 || pDrawListActive->_IdxWritePtr == pDrawListActive->IdxBuffer.Data + pDrawListActive->IdxBuffer.Size);
if (!(pDrawListActive->Flags & ImDrawListFlags_AllowVtxOffset))
IM_ASSERT(static_cast<int>(pDrawListActive->_VtxCurrentIdx) == pDrawListActive->VtxBuffer.Size);
*pDrawListSafe = *pDrawListActive;
::ReleaseSRWLockExclusive(&drawLock);
}
#pragma endregion
#pragma region draw_bindings
bool D::WorldToScreen(const Vector_t& vecOrigin, ImVec2* pvecScreen)
{
const float flWidth = SDK::ViewMatrix[3][0] * vecOrigin.x + SDK::ViewMatrix[3][1] * vecOrigin.y + SDK::ViewMatrix[3][2] * vecOrigin.z + SDK::ViewMatrix[3][3];
// check is point can't fit on screen, because it's behind us
if (flWidth < 0.001f)
return false;
// compute the scene coordinates of a point in 3D
const float flInverse = 1.0f / flWidth;
pvecScreen->x = (SDK::ViewMatrix[0][0] * vecOrigin.x + SDK::ViewMatrix[0][1] * vecOrigin.y + SDK::ViewMatrix[0][2] * vecOrigin.z + SDK::ViewMatrix[0][3]) * flInverse;
pvecScreen->y = (SDK::ViewMatrix[1][0] * vecOrigin.x + SDK::ViewMatrix[1][1] * vecOrigin.y + SDK::ViewMatrix[1][2] * vecOrigin.z + SDK::ViewMatrix[1][3]) * flInverse;
// screen transform
// get the screen position in pixels of given point
const ImVec2 vecDisplaySize = ImGui::GetIO().DisplaySize;
pvecScreen->x = (vecDisplaySize.x * 0.5f) + (pvecScreen->x * vecDisplaySize.x) * 0.5f;
pvecScreen->y = (vecDisplaySize.y * 0.5f) - (pvecScreen->y * vecDisplaySize.y) * 0.5f;
return true;
}
float D::CalculateDPI(const int nScaleTarget)
{
switch ((EMiscDpiScale)nScaleTarget)
{
case EMiscDpiScale::MISC_DPISCALE_DEFAULT:
return 1.f;
case EMiscDpiScale::MISC_DPISCALE_125:
return 1.25f;
case EMiscDpiScale::MISC_DPISCALE_150:
return 1.5f;
case EMiscDpiScale::MISC_DPISCALE_175:
return 1.75f;
case EMiscDpiScale::MISC_DPISCALE_200:
return 2.f;
default:
return 1.f;
}
}
void D::AddDrawListRect(ImDrawList* pDrawList, const ImVec2& vecMin, const ImVec2& vecMax, const Color_t& colRect, const unsigned int uFlags, const Color_t& colOutline, const float flRounding, const ImDrawFlags roundingCorners, float flThickness, const float flOutlineThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
const ImU32 colRectPacked = colRect.GetU32();
const ImU32 colOutlinePacked = colOutline.GetU32();
if (uFlags & DRAW_RECT_FILLED)
pDrawList->AddRectFilled(vecMin, vecMax, colRectPacked, flRounding, roundingCorners);
else
{
pDrawList->AddRect(vecMin, vecMax, colRectPacked, flRounding, roundingCorners, flThickness);
flThickness *= 0.5f;
}
const float flHalfOutlineThickness = flOutlineThickness * 0.5f;
const ImVec2 vecThicknessOffset = { flThickness + flHalfOutlineThickness, flThickness + flHalfOutlineThickness };
if (uFlags & DRAW_RECT_BORDER)
pDrawList->AddRect(vecMin + vecThicknessOffset, vecMax - vecThicknessOffset, colOutlinePacked, flRounding, roundingCorners, flOutlineThickness);
if (uFlags & DRAW_RECT_OUTLINE)
pDrawList->AddRect(vecMin - vecThicknessOffset, vecMax + vecThicknessOffset, colOutlinePacked, flRounding, roundingCorners, flOutlineThickness);
}
void D::AddDrawListRectMultiColor(ImDrawList* pDrawList, const ImVec2& vecMin, const ImVec2& vecMax, const Color_t& colUpperLeft, const Color_t& colUpperRight, const Color_t& colBottomRight, const Color_t& colBottomLeft)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
pDrawList->AddRectFilledMultiColor(vecMin, vecMax, colUpperLeft.GetU32(), colUpperRight.GetU32(), colBottomRight.GetU32(), colBottomLeft.GetU32());
}
void D::AddDrawListCircle(ImDrawList* pDrawList, const ImVec2& vecCenter, const float flRadius, const Color_t& colCircle, const int nSegments, const unsigned int uFlags, const Color_t& colOutline, float flThickness, const float flOutlineThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
const ImU32 colCirclePacked = colCircle.GetU32();
if (uFlags & DRAW_CIRCLE_FILLED)
{
pDrawList->AddCircleFilled(vecCenter, flRadius, colCirclePacked, nSegments);
flThickness = 0.0f;
}
else
pDrawList->AddCircle(vecCenter, flRadius, colCirclePacked, nSegments, flThickness);
if (uFlags & DRAW_CIRCLE_OUTLINE)
pDrawList->AddCircle(vecCenter, flRadius + flOutlineThickness, colOutline.GetU32(), nSegments, flThickness + flOutlineThickness);
}
void D::AddDrawListArc(ImDrawList* pDrawList, const ImVec2& vecPosition, const float flRadius, const float flMinimumAngle, const float flMaximumAngle, const Color_t& colArc, const float flThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
pDrawList->PathArcTo(vecPosition, flRadius, M_DEG2RAD(flMinimumAngle), M_DEG2RAD(flMaximumAngle), 32);
pDrawList->PathStroke(colArc.GetU32(), false, flThickness);
}
void D::AddDrawListLine(ImDrawList* pDrawList, const ImVec2& vecFirst, const ImVec2& vecSecond, const Color_t& colLine, const float flThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
pDrawList->AddLine(vecFirst, vecSecond, colLine.GetU32(), flThickness);
}
void D::AddDrawListTriangle(ImDrawList* pDrawList, const ImVec2& vecFirst, const ImVec2& vecSecond, const ImVec2& vecThird, const Color_t& colTriangle, const unsigned int uFlags, const Color_t& colOutline, const float flThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
const ImU32 colTrianglePacked = colTriangle.GetU32();
if (uFlags & DRAW_TRIANGLE_FILLED)
pDrawList->AddTriangleFilled(vecFirst, vecSecond, vecThird, colTrianglePacked);
else
pDrawList->AddTriangle(vecFirst, vecSecond, vecThird, colTrianglePacked, flThickness);
if (uFlags & DRAW_TRIANGLE_OUTLINE)
pDrawList->AddTriangle(vecFirst, vecSecond, vecThird, colOutline.GetU32(), flThickness + 1.0f);
}
void D::AddDrawListQuad(ImDrawList* pDrawList, const ImVec2& vecFirst, const ImVec2& vecSecond, const ImVec2& vecThird, const ImVec2& vecFourth, const Color_t& colQuad, const unsigned int uFlags, const Color_t& colOutline, const float flThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
const ImU32 colQuadPacked = colQuad.GetU32();
if (uFlags & DRAW_QUAD_FILLED)
pDrawList->AddQuadFilled(vecFirst, vecSecond, vecThird, vecFourth, colQuadPacked);
else
pDrawList->AddQuad(vecFirst, vecSecond, vecThird, vecFourth, colQuadPacked, flThickness);
if (uFlags & DRAW_QUAD_OUTLINE)
pDrawList->AddQuad(vecFirst, vecSecond, vecThird, vecFourth, colOutline.GetU32(), flThickness + 1.0f);
}
void D::AddDrawListPolygon(ImDrawList* pDrawList, const ImVec2* vecPoints, const int nPointsCount, const Color_t& colPolygon, unsigned int uFlags, const Color_t& colOutline, const bool bClosed, const float flThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
const ImU32 colPolygonPacked = colPolygon.GetU32();
if (uFlags & DRAW_POLYGON_FILLED)
pDrawList->AddConvexPolyFilled(vecPoints, nPointsCount, colPolygonPacked);
else
pDrawList->AddPolyline(vecPoints, nPointsCount, colPolygonPacked, bClosed, flThickness);
if (uFlags & DRAW_POLYGON_OUTLINE)
pDrawList->AddPolyline(vecPoints, nPointsCount, colOutline.GetU32(), bClosed, flThickness + 1.0f);
}
void D::AddDrawListText(ImDrawList* pDrawList, const ImFont* pFont, const ImVec2& vecPosition, const char* szText, const Color_t& colText, const unsigned int uFlags, const Color_t& colOutline, const float flThickness)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
// set font texture
pDrawList->PushTextureID(pFont->ContainerAtlas->TexID);
const ImU32 colOutlinePacked = colOutline.GetU32();
if (uFlags & DRAW_TEXT_DROPSHADOW)
pDrawList->AddText(pFont, pFont->FontSize, vecPosition + ImVec2(flThickness, flThickness), colOutlinePacked, szText);
else if (uFlags & DRAW_TEXT_OUTLINE)
{
pDrawList->AddText(pFont, pFont->FontSize, vecPosition + ImVec2(flThickness, -flThickness), colOutlinePacked, szText);
pDrawList->AddText(pFont, pFont->FontSize, vecPosition + ImVec2(-flThickness, flThickness), colOutlinePacked, szText);
}
pDrawList->AddText(pFont, pFont->FontSize, vecPosition, colText.GetU32(), szText);
pDrawList->PopTextureID();
}
void D::AddDrawListShadowRect(ImDrawList* pDrawList, const ImVec2& vecMin, const ImVec2& vecMax, const Color_t& colShadow, float flThickness, float flRounding, ImDrawFlags roundingCorners)
{
if (pDrawList == nullptr)
pDrawList = pDrawListActive;
pDrawList->AddShadowRect(vecMin, vecMax, colShadow.GetU32(), flThickness, ImVec2(0, 0), roundingCorners, flRounding);
}
#pragma endregion
#pragma region draw_structures
void AnimationHandler_t::Update(const float flDeltaTime, const float flDuration)
{
if (fnEaseIn == nullptr)
fnEaseIn = &EASING::InSine;
if (fnEaseOut == nullptr)
fnEaseOut = &EASING::OutSine;
// Reset the elapsed time if the bool switches
if (bSwitch != bLastSwitch)
flElapsedTime = 0;
flElapsedTime = MATH::Max(0.0f, MATH::Min(flElapsedTime, flDuration));
float flTime = flElapsedTime / flDuration;
// Determine the initial and target value based on the current state
float flInitialValue = bSwitch ? 0.1f : flValue;
float flTargetValue = bSwitch ? 1.0f : 0.1f; /*(1.0f is max value)*/
// Select the appropriate easing function based on the current state
EasingFunction_t fnCurrentEase = bSwitch ? fnEaseIn : fnEaseOut;
// Apply the appropriate easing function based on fade-in or fade-out (with lerping, which is basically what's the math were doing)
flValue = (flInitialValue + (flTargetValue - flInitialValue)) * (float)fnCurrentEase(flTime);
flValue = MATH::Clamp(flValue, 0.1f, 1.0f);
flElapsedTime += flDeltaTime;
bLastSwitch = bSwitch;
}
#pragma endregion

View File

@@ -0,0 +1,205 @@
#pragma once
// used: [d3d]
#include <d3d11.h>
#include "../common.h"
#include "../sdk/datatypes/color.h"
#include "../sdk/datatypes/vector.h"
// used: [ext] imgui
#include "../../dependencies/imgui/imgui.h"
#include "../../dependencies/imgui/imgui_internal.h"
// forward declarations
struct KeyBind_t;
#pragma region draw_objects_enumerations
enum ERectRenderFlags : unsigned int
{
DRAW_RECT_NONE = 0,
DRAW_RECT_OUTLINE = (1 << 0),
DRAW_RECT_BORDER = (1 << 1),
DRAW_RECT_FILLED = (1 << 2)
};
enum ECircleRenderFlags : unsigned int
{
DRAW_CIRCLE_NONE = 0,
DRAW_CIRCLE_OUTLINE = (1 << 0),
DRAW_CIRCLE_FILLED = (1 << 1)
};
enum ETriangleRenderFlags : unsigned int
{
DRAW_TRIANGLE_NONE = 0,
DRAW_TRIANGLE_OUTLINE = (1 << 0),
DRAW_TRIANGLE_FILLED = (1 << 1)
};
enum EQuadRenderFlags : unsigned int
{
DRAW_QUAD_NONE = 0,
DRAW_QUAD_OUTLINE = (1 << 0),
DRAW_QUAD_FILLED = (1 << 1)
};
enum EPolygonRenderFlags : unsigned int
{
DRAW_POLYGON_NONE = 0,
DRAW_POLYGON_OUTLINE = (1 << 0),
DRAW_POLYGON_FILLED = (1 << 1)
};
enum ETextRenderFlags : unsigned int
{
DRAW_TEXT_NONE = 0,
DRAW_TEXT_DROPSHADOW = (1 << 0),
DRAW_TEXT_OUTLINE = (1 << 1)
};
#pragma endregion
#pragma region draw_structures
// predefined custom user type
struct ColorPickerVar_t;
typedef double (*EasingFunction_t)(double);
struct AnimationHandler_t
{
// default: ease::in/outsine
AnimationHandler_t(EasingFunction_t fnIn = nullptr, EasingFunction_t fnOut = nullptr) :
fnEaseIn(fnIn), fnEaseOut(fnOut), bSwitch(false), bLastSwitch(false), flElapsedTime(0.f), flValue(0.1f){};
~AnimationHandler_t() = default;
// Has to be called every frame
void Update(const float flDeltaTime, const float flDuration);
// Get the current value multiplied by a scale
float GetValue(float flScale = 1.0f)
{
return flValue * flScale;
}
const bool GetSwitch() const
{
return bSwitch;
}
// switch state
void Switch()
{
bSwitch = !bSwitch;
}
void SetSwitch(const bool bState)
{
bSwitch = bState;
}
private:
// Set to true for ease-in animation, false for ease-out
bool bSwitch = 0;
bool bLastSwitch = bSwitch;
float flElapsedTime = 0.f;
// Current value of the animation
float flValue = 0.1f;
// Ease in and out functions Declaration
EasingFunction_t fnEaseIn = nullptr;
EasingFunction_t fnEaseOut = nullptr;
};
#pragma endregion
/*
* FONTS
*/
namespace FONT
{
// 0. verdana, size: 12px * scaledDPI(1.0f->2.0f); lighthinting
inline ImFont* pMenu[5];
// 1. verdana, size: 14px; bold
inline ImFont* pExtra;
// 2. tahoma, size: 16px; lighthinting
inline ImFont* pVisual;
}
// extended imgui functionality
namespace ImGui
{
/* @section: main */
void HelpMarker(const char* szDescription);
bool HotKey(const char* szLabel, unsigned int* pValue);
bool HotKey(const char* szLabel, KeyBind_t* pKeyBind, const bool bAllowSwitch = true);
bool MultiCombo(const char* szLabel, unsigned int* pFlags, const char* const* arrItems, int nItemsCount);
bool BeginListBox(const char* szLabel, int nItemsCount, int nHeightInItems = -1);
/* @section: wrappers */
bool ColorEdit3(const char* szLabel, Color_t* pColor, ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_DisplayHex);
bool ColorEdit4(const char* szLabel, Color_t* pColor, ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_DisplayHex | ImGuiColorEditFlags_AlphaBar);
bool ColorEdit3(const char* szLabel, ColorPickerVar_t* pColor, ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_DisplayHex);
bool ColorEdit4(const char* szLabel, ColorPickerVar_t* pColorVar, ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_DisplayHex | ImGuiColorEditFlags_AlphaBar);
}
/*
* DRAW
* - rendering framework
*/
namespace D
{
// initialize rendering engine, create fonts, set styles etc
bool Setup(HWND hWnd, ID3D11Device* pDevice, ID3D11DeviceContext* pContext);
// shutdown rendering engine
void Destroy();
/* @section: callbacks */
// handle input window message and save keys states in array
bool OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
/* @section: main */
// render primitives by stored safe data
void RenderDrawData(ImDrawData* pDrawData);
// reset active draw data container
void ResetDrawData();
// swap active draw data container to safe one
void SwapDrawData();
// call it before rendering
void NewFrame();
// call to render all primitives
void Render();
/* @section: get */
/// convert world space to screen space coordinates by game's conversion matrix
/// @param[out] pvecScreen output for converted screen position
/// @returns: true if converted coordinates fit into display size, false otherwise
bool WorldToScreen(const Vector_t& vecOrigin, ImVec2* pvecScreen);
float CalculateDPI(const int nScaleTarget = 0);
/* @section: bindings */
void AddDrawListRect(ImDrawList* pDrawList, const ImVec2& vecMin, const ImVec2& vecMax, const Color_t& colRect, const unsigned int uFlags = DRAW_RECT_NONE, const Color_t& colOutline = Color_t(0, 0, 0, 255), const float flRounding = 0.f, const ImDrawFlags roundingCorners = ImDrawFlags_RoundCornersAll, float flThickness = 1.0f, const float flOutlineThickness = 1.0f);
void AddDrawListRectMultiColor(ImDrawList* pDrawList, const ImVec2& vecMin, const ImVec2& vecMax, const Color_t& colUpperLeft, const Color_t& colUpperRight, const Color_t& colBottomRight, const Color_t& colBottomLeft);
void AddDrawListCircle(ImDrawList* pDrawList, const ImVec2& vecCenter, const float flRadius, const Color_t& colCircle, const int nSegments, const unsigned int uFlags = DRAW_CIRCLE_NONE, const Color_t& colOutline = Color_t(0, 0, 0, 255), const float flThickness = 1.0f, const float flOutlineThickness = 1.0f);
void AddDrawListArc(ImDrawList* pDrawList, const ImVec2& vecPosition, const float flRadius, const float flMinimumAngle, const float flMaximumAngle, const Color_t& colArc = Color_t(255, 255, 255, 255), const float flThickness = 1.0f);
void AddDrawListLine(ImDrawList* pDrawList, const ImVec2& vecFirst, const ImVec2& vecSecond, const Color_t& colLine, const float flThickness = 1.0f);
void AddDrawListTriangle(ImDrawList* pDrawList, const ImVec2& vecFirst, const ImVec2& vecSecond, const ImVec2& vecThird, const Color_t& colTriangle, const unsigned int uFlags = DRAW_TRIANGLE_NONE, const Color_t& colOutline = Color_t(0, 0, 0, 255), const float flThickness = 0.f);
void AddDrawListQuad(ImDrawList* pDrawList, const ImVec2& vecFirst, const ImVec2& vecSecond, const ImVec2& vecThird, const ImVec2& vecFourth, const Color_t& colQuad, const unsigned int uFlags = DRAW_QUAD_NONE, const Color_t& colOutline = Color_t(0, 0, 0, 255), const float flThickness = 0.f);
void AddDrawListPolygon(ImDrawList* pDrawList, const ImVec2* vecPoints, const int nPointsCount, const Color_t& colPolygon, unsigned int uFlags = DRAW_POLYGON_NONE, const Color_t& colOutline = Color_t(0, 0, 0, 255), const bool bClosed = true, const float flThickness = 1.0f);
void AddDrawListText(ImDrawList* pDrawList, const ImFont* pFont, const ImVec2& vecPosition, const char* szText, const Color_t& colText, const unsigned int uFlags = DRAW_TEXT_NONE, const Color_t& colOutline = Color_t(0, 0, 0, 255), const float flThickness = 1.0f);
void AddDrawListShadowRect(ImDrawList* pDrawList, const ImVec2& vecMin, const ImVec2& vecMax, const Color_t& colShadow, float flThickness = 32.f, float flRounding = 0.0f, ImDrawFlags roundingCorners = ImDrawFlags_RoundCornersAll);
/* @section: values */
// rendering engine initialization state
inline bool bInitialized = false;
// active draw data container used to store
inline ImDrawList* pDrawListActive = nullptr;
// safe draw data container
inline ImDrawList* pDrawListSafe = nullptr;
// actual draw data container used to render
inline ImDrawList* pDrawListRender = nullptr;
}

View File

@@ -0,0 +1,224 @@
#pragma once
// used: math functions
#include "math.h"
namespace EASING
{
CS_INLINE double InSine(const double t)
{
return M_SIN(1.5707963 * t);
}
CS_INLINE double OutSine(double t)
{
return 1 + M_SIN(1.5707963 * (--t));
}
CS_INLINE double InOutSine(const double t)
{
return 0.5 * (1 + M_SIN(3.1415926 * (t - 0.5)));
}
CS_INLINE double InQuad(const double t)
{
return t * t;
}
CS_INLINE double OutQuad(const double t)
{
return t * (2 - t);
}
CS_INLINE double InOutQuad(const double t)
{
return t < 0.5 ? 2 * t * t : t * (4 - 2 * t) - 1;
}
CS_INLINE double InCubic(const double t)
{
return t * t * t;
}
CS_INLINE double OutCubic(double t)
{
return 1 + (--t) * t * t;
}
CS_INLINE double InOutCubic(double t)
{
return t < 0.5 ? 4 * t * t * t : 1 + (--t) * (2 * (--t)) * (2 * t);
}
CS_INLINE double InQuart(double t)
{
t *= t;
return t * t;
}
CS_INLINE double OutQuart(double t)
{
t = (--t) * t;
return 1 - t * t;
}
CS_INLINE double InOutQuart(double t)
{
if (t < 0.5)
{
t *= t;
return 8 * t * t;
}
else
{
t = (--t) * t;
return 1 - 8 * t * t;
}
}
CS_INLINE double InQuint(const double t)
{
const double t2 = t * t;
return t * t2 * t2;
}
CS_INLINE double OutQuint(double t)
{
const double t2 = (--t) * t;
return 1 + t * t2 * t2;
}
CS_INLINE double InOutQuint(double t)
{
double t2;
if (t < 0.5)
{
t2 = t * t;
return 16 * t * t2 * t2;
}
else
{
t2 = (--t) * t;
return 1 + 16 * t * t2 * t2;
}
}
CS_INLINE double InExpo(const double t)
{
return (M_POW(2.0, 8 * t) - 1) / 255;
}
CS_INLINE double OutExpo(const double t)
{
return 1 - M_POW(2.0, -8 * t);
}
CS_INLINE double InOutExpo(const double t)
{
if (t < 0.5)
{
return (M_POW(2.0, 16 * t) - 1) / 510;
}
else
{
return 1 - 0.5 * M_POW(2.0, -16 * (t - 0.5));
}
}
CS_INLINE double InCirc(const double t)
{
return 1 - M_SQRT(1 - t);
}
CS_INLINE double OutCirc(const double t)
{
return M_SQRT(t);
}
CS_INLINE double InOutCirc(const double t)
{
if (t < 0.5)
{
return (1 - M_SQRT(1 - 2 * t)) * 0.5;
}
else
{
return (1 + M_SQRT(2 * t - 1)) * 0.5;
}
}
CS_INLINE double InBack(const double t)
{
return t * t * (2.70158 * t - 1.70158);
}
CS_INLINE double OutBack(double t)
{
return 1 + (--t) * t * (2.70158 * t + 1.70158);
}
CS_INLINE double InOutBack(double t)
{
if (t < 0.5)
{
return t * t * (7 * t - 2.5) * 2;
}
else
{
return 1 + (--t) * t * 2 * (7 * t + 2.5);
}
}
CS_INLINE double InElastic(const double t)
{
const double t2 = t * t;
return t2 * t2 * M_SIN(t * MATH::_PI * 4.5);
}
CS_INLINE double OutElastic(const double t)
{
const double t2 = (t - 1) * (t - 1);
return 1 - t2 * t2 * M_COS(t * MATH::_PI * 4.5);
}
CS_INLINE double InOutElastic(const double t)
{
double t2;
if (t < 0.45)
{
t2 = t * t;
return 8 * t2 * t2 * M_SIN(t * MATH::_PI * 9);
}
else if (t < 0.55)
{
return 0.5 + 0.75 * M_SIN(t * MATH::_PI * 4);
}
else
{
t2 = (t - 1) * (t - 1);
return 1 - 8 * t2 * t2 * M_SIN(t * MATH::_PI * 9);
}
}
CS_INLINE double InBounce(const double t)
{
return M_POW(2.0, 6 * (t - 1)) * M_ABS(M_SIN(t * MATH::_PI * 3.5));
}
CS_INLINE double OutBounce(const double t)
{
return 1 - M_POW(2.0, -6 * t) * M_ABS(M_COS(t * MATH::_PI * 3.5));
}
CS_INLINE double InOutBounce(const double t)
{
if (t < 0.5)
{
return 8 * M_POW(2.0, 8 * (t - 1)) * M_ABS(M_SIN(t * MATH::_PI * 7));
}
else
{
return 1 - 8 * M_POW(2.0, -8 * t) * M_ABS(M_SIN(t * MATH::_PI * 7));
}
}
}

View File

@@ -0,0 +1,40 @@
#pragma once
// used: [stl] uint64_t
#include <cstdint>
// used :CRT::StringLength
#include "crt.h"
using FNV1A_t = std::uint64_t;
/*
* 64-BIT FNV1A HASH
*/
namespace FNV1A
{
/* @section: [internal] constants */
constexpr FNV1A_t ullBasis = 0xCBF29CE484222325ULL;
constexpr FNV1A_t ullPrime = 0x100000001B3ULL;
/* @section: get */
/// @param[in] szString string for which you want to generate a hash
/// @param[in] uKey key of hash generation
/// @returns: calculated at compile-time hash of given string
consteval FNV1A_t HashConst(const char* szString, const FNV1A_t uKey = ullBasis) noexcept
{
return (szString[0] == '\0') ? uKey : HashConst(&szString[1], (uKey ^ static_cast<FNV1A_t>(szString[0])) * ullPrime);
}
/// @param[in] szString string for which you want to generate a hash
/// @param[in] uKey key of hash generation
/// @returns: calculated at run-time hash of given string
inline FNV1A_t Hash(const char* szString, FNV1A_t uKey = ullBasis) noexcept
{
const std::size_t nLength = CRT::StringLength(szString);
for (std::size_t i = 0U; i < nLength; ++i)
uKey = (uKey ^ szString[i]) * ullPrime;
return uKey;
}
}

View File

@@ -0,0 +1,154 @@
// used: get_x_lparam, get_y_lparam
#include <windowsx.h>
#include "inputsystem.h"
// used: menu open/panic keys
#include "../core/variables.h"
// used: wndproc hook
#include "../core/hooks.h"
// used: menu variables
#include "../core/menu.h"
// used: iinputsystem
#include "../core/interfaces.h"
#include "../sdk/interfaces/iinputsystem.h"
// used: [ext] imrect
#include "../dependencies/imgui/imgui_internal.h"
static BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
{
const auto MainWindow = [handle]()
{
return GetWindow(handle, GW_OWNER) == nullptr &&
IsWindowVisible(handle) && handle != GetConsoleWindow();
};
DWORD nPID = 0;
GetWindowThreadProcessId(handle, &nPID);
if (GetCurrentProcessId() != nPID || !MainWindow())
return TRUE;
*reinterpret_cast<HWND*>(lParam) = handle;
return FALSE;
}
bool IPT::Setup()
{
while (hWindow == nullptr)
{
EnumWindows(::EnumWindowsCallback, reinterpret_cast<LPARAM>(&hWindow));
::Sleep(200U);
}
// change window message handle to our
pOldWndProc = reinterpret_cast<WNDPROC>(SetWindowLongPtrW(hWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(H::WndProc)));
if (pOldWndProc == nullptr)
return false;
return true;
}
void IPT::Destroy()
{
MENU::bMainWindowOpened = false;
::Sleep(200U);
if (pOldWndProc != nullptr)
{
SetWindowLongPtrW(hWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(pOldWndProc));
pOldWndProc = nullptr;
}
}
bool IPT::OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// prevent process when e.g. binding something in-menu
if (wParam != C_GET(unsigned int, Vars.nMenuKey) && wParam != C_GET(unsigned int, Vars.nPanicKey) && MENU::bMainWindowOpened)
return false;
// current active key
int nKey = 0;
// current active key state
KeyState_t state = KEY_STATE_NONE;
switch (uMsg)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (wParam < 256U)
{
nKey = static_cast<int>(wParam);
state = KEY_STATE_DOWN;
}
break;
case WM_KEYUP:
case WM_SYSKEYUP:
if (wParam < 256U)
{
nKey = static_cast<int>(wParam);
state = KEY_STATE_UP;
}
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
nKey = VK_LBUTTON;
state = uMsg == WM_LBUTTONUP ? KEY_STATE_UP : KEY_STATE_DOWN;
break;
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_RBUTTONDBLCLK:
nKey = VK_RBUTTON;
state = uMsg == WM_RBUTTONUP ? KEY_STATE_UP : KEY_STATE_DOWN;
break;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
nKey = VK_MBUTTON;
state = uMsg == WM_MBUTTONUP ? KEY_STATE_UP : KEY_STATE_DOWN;
break;
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
case WM_XBUTTONDBLCLK:
nKey = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? VK_XBUTTON1 : VK_XBUTTON2);
state = uMsg == WM_XBUTTONUP ? KEY_STATE_UP : KEY_STATE_DOWN;
break;
default:
return false;
}
// save key states
if (state == KEY_STATE_UP && arrKeyState[nKey] == KEY_STATE_DOWN) // if swap states it will be pressed state
arrKeyState[nKey] = KEY_STATE_RELEASED;
else
arrKeyState[nKey] = state;
return true;
}
bool IPT::GetBindState(KeyBind_t& keyBind)
{
if (keyBind.uKey == 0U)
return false;
switch (keyBind.nMode)
{
case EKeyBindMode::HOLD:
keyBind.bEnable = IsKeyDown(keyBind.uKey);
break;
case EKeyBindMode::TOGGLE:
if (IsKeyReleased(keyBind.uKey))
keyBind.bEnable = !keyBind.bEnable;
break;
}
return keyBind.bEnable;
}
bool IPT::IsHovered(const ImVec2& vecPosition, const ImVec2& vecSize)
{
const ImVec2 vecMousePosition = ImGui::GetMousePos();
return ImRect(vecPosition, vecPosition + vecSize).Contains(vecMousePosition);
}

View File

@@ -0,0 +1,68 @@
#pragma once
// used: [win] winapi
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "../common.h"
// used: keybind_t
#include "../core/config.h"
/*
* INPUT SYSTEM
* listen and handle key states
*/
namespace IPT
{
using KeyState_t = std::uint8_t;
enum EKeyState : KeyState_t
{
KEY_STATE_NONE,
KEY_STATE_DOWN,
KEY_STATE_UP,
KEY_STATE_RELEASED
};
/* @section: values */
// current window
inline HWND hWindow = nullptr;
// saved window messages handler
inline WNDPROC pOldWndProc = nullptr;
// last processed key states
inline KeyState_t arrKeyState[256] = {};
// replace game window messages processor with our
bool Setup();
// restore window messages processor to original
void Destroy();
/* @section: callbacks */
// process input window message and save keys states in array
bool OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
/* @section: get */
/// @returns: true if keybind is active, false otherwise
bool GetBindState(KeyBind_t& keyBind);
[[nodiscard]] bool IsHovered(const ImVec2& vecPosition, const ImVec2& vecSize);
/// @returns: true if key is being held, false otherwise
[[nodiscard]] CS_INLINE bool IsKeyDown(const std::uint32_t uButtonCode)
{
return arrKeyState[uButtonCode] == KEY_STATE_DOWN;
}
/// @returns: true if key has been just released, false otherwise
[[nodiscard]] CS_INLINE bool IsKeyReleased(const std::uint32_t uButtonCode)
{
if (arrKeyState[uButtonCode] == KEY_STATE_RELEASED)
{
arrKeyState[uButtonCode] = KEY_STATE_UP;
return true;
}
return false;
}
}

View File

@@ -0,0 +1,258 @@
// used: [crt] time_t, time, localtime_s
#include <ctime>
#include "log.h"
// using: mem_stackalloc, mem_stackfree
#include "memory.h"
// used: IsPowerOfTwo
#include "math.h"
// used: GetWorkingPath
#include "../core.h"
// console write stream
static HANDLE hConsoleStream = INVALID_HANDLE_VALUE;
// file write stream
static HANDLE hFileStream = INVALID_HANDLE_VALUE;
#pragma region log_main
bool L::AttachConsole(const wchar_t* wszWindowTitle)
{
// allocate memory for console
if (::AllocConsole() != TRUE)
return false;
// open console output stream
if (hConsoleStream = ::CreateFileW(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); hConsoleStream == INVALID_HANDLE_VALUE)
return false;
// @test: unnecessary as fas as we don't use std::cout etc
if (::SetStdHandle(STD_OUTPUT_HANDLE, hConsoleStream) != TRUE)
return false;
// set console window title
if (::SetConsoleTitleW(wszWindowTitle) != TRUE)
return false;
return true;
}
void L::DetachConsole()
{
::CloseHandle(hConsoleStream);
// free allocated memory for console
if (::FreeConsole() != TRUE)
return;
// close console window
if (const HWND hConsoleWindow = ::GetConsoleWindow(); hConsoleWindow != nullptr)
::PostMessageW(hConsoleWindow, WM_CLOSE, 0U, 0L);
}
bool L::OpenFile(const wchar_t* wszFileName)
{
wchar_t wszFilePath[MAX_PATH];
if (!CORE::GetWorkingPath(wszFilePath))
return false;
CRT::StringCat(wszFilePath, wszFileName);
// @todo: append time/date to filename and always keep up to 3 files, otherwise delete with lowest date
// open file output stream
if (hFileStream = ::CreateFileW(wszFilePath, GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); hFileStream == INVALID_HANDLE_VALUE)
return false;
// insert UTF-8 BOM
::WriteFile(hFileStream, "\xEF\xBB\xBF", 3UL, nullptr, nullptr);
return true;
}
void L::CloseFile()
{
::CloseHandle(hFileStream);
}
void L::WriteMessage(const char* szMessage, const std::size_t nMessageLength)
{
#ifdef CS_LOG_CONSOLE
::WriteConsoleA(hConsoleStream, szMessage, nMessageLength, nullptr, nullptr);
#endif
#ifdef CS_LOG_FILE
::WriteFile(hFileStream, szMessage, nMessageLength, nullptr, nullptr);
#endif
}
#pragma endregion
#pragma region log_stream_control
L::Stream_t::ColorMarker_t L::SetColor(const LogColorFlags_t nColorFlags)
{
return { nColorFlags };
}
L::Stream_t::PrecisionMarker_t L::SetPrecision(const int iPrecision)
{
return { iPrecision };
}
L::Stream_t::ModeMarker_t L::AddFlags(const LogModeFlags_t nModeFlags)
{
return { nModeFlags };
}
L::Stream_t::ModeMarker_t L::RemoveFlags(const LogModeFlags_t nModeFlags)
{
return { static_cast<LogModeFlags_t>(nModeFlags | LOG_MODE_REMOVE) };
}
#pragma endregion
L::Stream_t& L::Stream_t::operator()(const ELogLevel nLevel, const char* szFileBlock)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
// reset previous flags
nModeFlags = LOG_MODE_NONE;
const char* szTypeBlock = nullptr;
[[maybe_unused]] LogColorFlags_t nTypeColorFlags = LOG_COLOR_DEFAULT;
switch (nLevel)
{
case LOG_INFO:
szTypeBlock = "[info] ";
nTypeColorFlags = LOG_COLOR_FORE_CYAN;
break;
case LOG_WARNING:
szTypeBlock = "[warning] ";
nTypeColorFlags = LOG_COLOR_FORE_YELLOW;
break;
case LOG_ERROR:
szTypeBlock = "[error] ";
nTypeColorFlags = LOG_COLOR_FORE_RED;
break;
default:
break;
}
const std::time_t time = std::time(nullptr);
std::tm timePoint;
localtime_s(&timePoint, &time);
// @todo: no new line at first use / ghetto af but cheap enough but still ghetto uhhh
char szTimeBuffer[32];
const std::size_t nTimeSize = CRT::TimeToString(szTimeBuffer, sizeof(szTimeBuffer), "\n[%d-%m-%Y %T] ", &timePoint) - bFirstPrint;
#ifdef CS_LOG_CONSOLE
::SetConsoleTextAttribute(hConsoleStream, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
::WriteConsoleA(hConsoleStream, szTimeBuffer + bFirstPrint, nTimeSize, nullptr, nullptr);
if (szFileBlock != nullptr)
{
::SetConsoleTextAttribute(hConsoleStream, FOREGROUND_INTENSITY);
::WriteConsoleA(hConsoleStream, szFileBlock, CRT::StringLength(szFileBlock), nullptr, nullptr);
}
if (szTypeBlock != nullptr)
{
::SetConsoleTextAttribute(hConsoleStream, static_cast<WORD>(nTypeColorFlags));
::WriteConsoleA(hConsoleStream, szTypeBlock, CRT::StringLength(szTypeBlock), nullptr, nullptr);
}
::SetConsoleTextAttribute(hConsoleStream, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
#endif
#ifdef CS_LOG_FILE
::WriteFile(hFileStream, szTimeBuffer + bFirstPrint, nTimeSize, nullptr, nullptr);
char szBlockBuffer[MAX_PATH] = { '\0' };
char* szCurrentBlock = szBlockBuffer;
if (szFileBlock != nullptr)
szCurrentBlock = CRT::StringCat(szCurrentBlock, szFileBlock);
if (szTypeBlock != nullptr)
szCurrentBlock = CRT::StringCat(szCurrentBlock, szTypeBlock);
if (szBlockBuffer[0] != '\0')
::WriteFile(hFileStream, szBlockBuffer, static_cast<DWORD>(szCurrentBlock - szBlockBuffer), nullptr, nullptr);
#endif
bFirstPrint = false;
#endif
return *this;
}
L::Stream_t& L::Stream_t::operator<<(const ColorMarker_t colorMarker)
{
#ifdef CS_LOG_CONSOLE
::SetConsoleTextAttribute(hConsoleStream, static_cast<WORD>(colorMarker.nColorFlags));
#endif
return *this;
}
L::Stream_t& L::Stream_t::operator<<(const PrecisionMarker_t precisionMarker)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
this->iPrecision = precisionMarker.iPrecision;
#endif
return *this;
}
L::Stream_t& L::Stream_t::operator<<(const ModeMarker_t modeMarker)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
CS_ASSERT(nModeFlags == 0U || MATH::IsPowerOfTwo(nModeFlags & LOG_MODE_INT_FORMAT_MASK)); // used conflicting format flags
if (modeMarker.nModeFlags & LOG_MODE_REMOVE)
nModeFlags &= ~modeMarker.nModeFlags;
else
nModeFlags |= modeMarker.nModeFlags;
#endif
return *this;
}
L::Stream_t& L::Stream_t::operator<<(const char* szMessage)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
WriteMessage(szMessage, CRT::StringLength(szMessage));
#endif
return *this;
}
L::Stream_t& L::Stream_t::operator<<(const wchar_t* wszMessage)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
/*
* to keep stream orientation always same, convert message to UTF-8
*
* regarding to C++ standard:
* [C++11: 27.4.1/3]:
* mixing operations on corresponding wide- and narrow-character streams follows the same semantics as mixing such operations on 'FILE's, as specified in amendation [1] of the ISO C standard
*
* [1]:
* the definition of a stream was changed to include the concept of an orientation for both text and binary streams.
* after a stream is associated with a file, but before any operations are performed on the stream, the stream is without orientation.
* if a wide-character input or output function is applied to a stream without orientation, the stream becomes wide-oriented.
* likewise, if a byte input or output operation is applied to a stream with orientation, the stream becomes byte-oriented.
* thereafter, only the 'fwide()' or 'freopen()' functions can alter the orientation of a stream.
* byte input/output functions shall not be applied to a wide-oriented stream and wide-character input/output functions shall not be applied to a byte-oriented stream.
*/
const std::size_t nMessageLength = CRT::StringLengthMultiByte(wszMessage);
char* szMessage = static_cast<char*>(MEM_STACKALLOC(nMessageLength + 1U));
CRT::StringUnicodeToMultiByte(szMessage, nMessageLength + 1U, wszMessage);
WriteMessage(szMessage, nMessageLength);
MEM_STACKFREE(szMessage);
#endif
return *this;
}
L::Stream_t& L::Stream_t::operator<<(const bool bValue)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
const char* szBoolean = ((nModeFlags & LOG_MODE_BOOL_ALPHA) ? (bValue ? "true" : "false") : (bValue ? "1" : "0"));
const std::size_t nBooleanLength = CRT::StringLength(szBoolean);
WriteMessage(szBoolean, nBooleanLength);
#endif
return *this;
}

View File

@@ -0,0 +1,327 @@
#pragma once
// used: [win] winapi
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "../common.h"
// using: stringcopy, stringcat, timetostring
#include "crt.h"
// used: sdk datatypes
#include "../sdk/datatypes/color.h"
#include "../sdk/datatypes/vector.h"
#include "../sdk/datatypes/qangle.h"
// @todo: poorly designed in case we don't need logging at all, xor continues wasteful compilation without any references | add smth like dummystream_t and unreference macro params?
#pragma region log_definitions
#ifdef _DEBUG
#if defined(CS_COMPILER_CLANG)
#define L_PRINT(LEVEL) L::stream(LEVEL, "[" __FILE_NAME__ ":" CS_STRINGIFY(__LINE__) "] ")
#else
#define L_PRINT(LEVEL) L::stream(LEVEL, L::DETAIL::MakeFileBlock<CRT::StringLength(L::DETAIL::GetFileName(__FILE__)), CRT::StringLength(CS_STRINGIFY(__LINE__))>(L::DETAIL::GetFileName(__FILE__), CS_STRINGIFY(__LINE__)).Get())
#endif
#else
#define L_PRINT(LEVEL) L::stream(LEVEL)
#endif
#pragma endregion
#pragma region log_enumerations
enum ELogLevel : std::uint8_t
{
LOG_NONE = 0,
LOG_INFO,
LOG_WARNING,
LOG_ERROR
};
using LogModeFlags_t = std::uint16_t;
enum ELogModeFlags : LogModeFlags_t
{
LOG_MODE_NONE = 0U,
// boolean formatting
LOG_MODE_BOOL_ALPHA = (1U << 0U), // switches between textual and numeric representation of booleans
// integer formatting
LOG_MODE_INT_SHOWBASE = (1U << 1U), // switches display of number base prefixes used by C++ literal constants
LOG_MODE_INT_FORMAT_HEX = (1U << 2U), // switches integer numbers hexadecimal format
LOG_MODE_INT_FORMAT_DEC = (1U << 3U), // switches integer numbers decimal format
LOG_MODE_INT_FORMAT_OCT = (1U << 4U), // switches integer numbers octal format
LOG_MODE_INT_FORMAT_BIN = (1U << 5U), // switches integer numbers binary format
LOG_MODE_INT_FORMAT_MASK = (LOG_MODE_INT_FORMAT_HEX | LOG_MODE_INT_FORMAT_DEC | LOG_MODE_INT_FORMAT_OCT | LOG_MODE_INT_FORMAT_BIN),
// floating-point formatting
LOG_MODE_FLOAT_SHOWPOINT = (1U << 6U), // switches decimal point for those numbers whose decimal part is zero
LOG_MODE_FLOAT_FORMAT_HEX = (1U << 7U), // switches floating-point numbers hexadecimal format
LOG_MODE_FLOAT_FORMAT_FIXED = (1U << 8U), // switches floating-point numbers formatting in fixed-point notation
LOG_MODE_FLOAT_FORMAT_SCIENTIFIC = (1U << 9U), // switches floating-point numbers formatting in scientific notation
LOG_MODE_FLOAT_FORMAT_MASK = (LOG_MODE_FLOAT_FORMAT_HEX | LOG_MODE_FLOAT_FORMAT_FIXED | LOG_MODE_FLOAT_FORMAT_SCIENTIFIC),
// numerical formatting
LOG_MODE_NUM_SHOWPOSITIVE = (1U << 10U), // switches display of plus sign '+' in non-negative numbers
LOG_MODE_NUM_UPPERCASE = (1U << 11U), // switches uppercase characters in numbers
/* [internal] */
LOG_MODE_REMOVE = (1U << 15U)
};
using LogColorFlags_t = std::uint16_t;
enum ELogColorFlags : LogColorFlags_t
{
LOG_COLOR_FORE_BLUE = FOREGROUND_BLUE,
LOG_COLOR_FORE_GREEN = FOREGROUND_GREEN,
LOG_COLOR_FORE_RED = FOREGROUND_RED,
LOG_COLOR_FORE_INTENSITY = FOREGROUND_INTENSITY,
LOG_COLOR_FORE_GRAY = FOREGROUND_INTENSITY,
LOG_COLOR_FORE_CYAN = FOREGROUND_BLUE | FOREGROUND_GREEN,
LOG_COLOR_FORE_MAGENTA = FOREGROUND_BLUE | FOREGROUND_RED,
LOG_COLOR_FORE_YELLOW = FOREGROUND_GREEN | FOREGROUND_RED,
LOG_COLOR_FORE_BLACK = 0U,
LOG_COLOR_FORE_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
LOG_COLOR_BACK_BLUE = BACKGROUND_BLUE,
LOG_COLOR_BACK_GREEN = BACKGROUND_GREEN,
LOG_COLOR_BACK_RED = BACKGROUND_RED,
LOG_COLOR_BACK_INTENSITY = BACKGROUND_INTENSITY,
LOG_COLOR_BACK_GRAY = BACKGROUND_INTENSITY,
LOG_COLOR_BACK_CYAN = BACKGROUND_BLUE | BACKGROUND_GREEN,
LOG_COLOR_BACK_MAGENTA = BACKGROUND_BLUE | BACKGROUND_RED,
LOG_COLOR_BACK_YELLOW = BACKGROUND_GREEN | BACKGROUND_RED,
LOG_COLOR_BACK_BLACK = 0U,
LOG_COLOR_BACK_WHITE = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
/* [internal] */
LOG_COLOR_DEFAULT = LOG_COLOR_FORE_WHITE | LOG_COLOR_BACK_BLACK
};
#pragma endregion
/*
* LOGGING
* - simple logging system with file and console output
* used for debugging and fetching values/errors at run-time
* @todo: currently not thread safe and can mess messages when used from different threads
*/
namespace L
{
namespace DETAIL
{
// @todo: constructs string per-byte in the stack, how do we can optimize this?
template <std::size_t N>
struct FileBlockStorage_t
{
template <std::size_t... I1, std::size_t... I2>
consteval explicit FileBlockStorage_t(const char* szFileName, const char* szLineNumber, std::index_sequence<I1...>, std::index_sequence<I2...>) :
szStorage{ '[', szFileName[I1]..., ':', szLineNumber[I2]..., ']', ' ', '\0' } { }
[[nodiscard]] constexpr const char* Get() const
{
return szStorage;
}
const char szStorage[N + 5U];
};
// fail-free version of 'StringCharR'
consteval const char* GetFileName(const char* szFilePath)
{
const char* szLastPath = szFilePath;
do
{
if (*szFilePath == '\\')
szLastPath = szFilePath + 1U;
} while (*szFilePath++ != '\0');
return szLastPath;
}
// helper to generate file info block for logging message at compile-time
template <std::size_t N1, std::size_t N2>
consteval auto MakeFileBlock(const char* szFileName, const char* szFileNumber) noexcept
{
return FileBlockStorage_t<N1 + N2>(szFileName, szFileNumber, std::make_index_sequence<N1>{}, std::make_index_sequence<N2>{});
}
}
/* @section: main */
// attach console to current window with write permission and given title
bool AttachConsole(const wchar_t* wszWindowTitle);
// close write streams and detach console from current window
void DetachConsole();
// open logging output file
bool OpenFile(const wchar_t* wszFileName);
// close logging output file
void CloseFile();
// write message to the file or/and console
void WriteMessage(const char* szMessage, const std::size_t nMessageLength);
// alternative of C++ 'std::cout' and other STL-like streams logging scheme
// @todo: is it faster to constantly call 'WriteMessage' instead of concatenating all of the output and print once? i dont think so, due to additional allocations, thread-safe requirements, conditions when we still should call print due to color/etc changes | but generally this should lead to better inlining and less complicated compiled code
struct Stream_t
{
// special unique return type markers to determine and handle change of those flags, just a snap for compile-time, inlined as underlying types at run-time
struct ColorMarker_t
{
LogColorFlags_t nColorFlags;
};
struct PrecisionMarker_t
{
int iPrecision;
};
struct ModeMarker_t
{
LogModeFlags_t nModeFlags;
};
// begin of each log message, puts time, file & line, level blocks
Stream_t& operator()(const ELogLevel nLevel, const char* szFileBlock = nullptr);
// manipulators
Stream_t& operator<<(ColorMarker_t);
Stream_t& operator<<(PrecisionMarker_t);
Stream_t& operator<<(ModeMarker_t);
// message
Stream_t& operator<<(const char* szMessage);
Stream_t& operator<<(const wchar_t* wszMessage);
// conversion
Stream_t& operator<<(const bool bValue);
template <typename T> requires std::is_integral_v<T>
Stream_t& operator<<(const T value)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
int iBase = 10;
const char* szPrefix = nullptr;
if (nModeFlags & LOG_MODE_INT_FORMAT_HEX)
{
iBase = 16;
szPrefix = "0x";
}
else if (nModeFlags & LOG_MODE_INT_FORMAT_OCT)
iBase = 8;
else if (nModeFlags & LOG_MODE_INT_FORMAT_BIN)
{
iBase = 2;
szPrefix = "0b";
}
// @todo: LOG_MODE_NUM_UPPERCASE not handled
char szIntegerBuffer[CRT::IntegerToString_t<std::int64_t, 2U>::MaxCount() + 2U];
char* szInteger = CRT::IntegerToString(value, szIntegerBuffer + 2U, sizeof(szIntegerBuffer) - 2U, iBase);
// @todo: after int2str rework could be simplified | or completely replaced with strformat
if (szPrefix != nullptr && (nModeFlags & LOG_MODE_INT_SHOWBASE))
{
*--szInteger = szPrefix[1];
*--szInteger = szPrefix[0];
}
if constexpr (std::is_signed_v<T>)
{
if (value >= 0 && (nModeFlags & LOG_MODE_NUM_SHOWPOSITIVE))
*--szInteger = '+';
}
const std::size_t nIntegerLength = szIntegerBuffer + sizeof(szIntegerBuffer) - szInteger - 1;
WriteMessage(szInteger, nIntegerLength);
#endif
return *this;
}
template <typename T> requires std::is_floating_point_v<T>
Stream_t& operator<<(const T value)
{
#if defined(CS_LOG_CONSOLE) || defined(CS_LOG_FILE)
//static_assert((nModeFlags & (LOG_MODE_FLOAT_FORMAT_FIXED | LOG_MODE_FLOAT_FORMAT_SCIENTIFIC)) && std::is_same_v<T, float>); // expected 'double' or 'long double'
int iDesiredPrecision = /*((nModeFlags & (LOG_MODE_FLOAT_FORMAT_FIXED | LOG_MODE_FLOAT_FORMAT_SCIENTIFIC)) ? -1 : (*/ iPrecision > 0 ? iPrecision : FLT_DIG; //));
char szFormatBuffer[8];
char* szFormat = szFormatBuffer;
*szFormat++ = '%';
if (nModeFlags & LOG_MODE_NUM_SHOWPOSITIVE)
*szFormat++ = '+';
if (nModeFlags & LOG_MODE_FLOAT_SHOWPOINT)
*szFormat++ = '#';
*szFormat++ = '.';
*szFormat++ = '*';
if constexpr (std::is_same_v<T, long double>)
*szFormat++ = 'L';
if (nModeFlags & LOG_MODE_FLOAT_FORMAT_FIXED)
*szFormat++ = 'f';
else
{
const bool bIsUpperCase = (nModeFlags & LOG_MODE_NUM_UPPERCASE);
if (nModeFlags & LOG_MODE_FLOAT_FORMAT_HEX)
*szFormat++ = bIsUpperCase ? 'A' : 'a';
else if (nModeFlags & LOG_MODE_FLOAT_FORMAT_SCIENTIFIC)
*szFormat++ = bIsUpperCase ? 'E' : 'e';
else
*szFormat++ = bIsUpperCase ? 'G' : 'g';
}
*szFormat = '\0';
char szFloatBuffer[96];
const int nFloatLength = CRT::StringPrintN(szFloatBuffer, sizeof(szFloatBuffer), szFormatBuffer, iDesiredPrecision, value);
WriteMessage(szFloatBuffer, nFloatLength);
#endif
return *this;
}
Stream_t& operator<<(const Vector_t& vecValue)
{
this->nModeFlags |= LOG_MODE_FLOAT_FORMAT_FIXED;
this->iPrecision = 3;
*this << CS_XOR("vector3d: (") << vecValue.x << CS_XOR(" | ") << vecValue.y << CS_XOR(" | ") << vecValue.z << CS_XOR(")");
return *this;
}
Stream_t& operator<<(const QAngle_t& angValue)
{
this->nModeFlags |= LOG_MODE_FLOAT_FORMAT_FIXED;
this->iPrecision = 3;
*this << CS_XOR("qangle: (") << angValue.x << CS_XOR(" | ") << angValue.y << CS_XOR(" | ") << angValue.z << CS_XOR(")");
return *this;
}
Stream_t& operator<<(const Color_t& colValue)
{
*this << CS_XOR("color: (") << static_cast<int>(colValue.r) << CS_XOR(" | ") << static_cast<int>(colValue.g) << CS_XOR(" | ") << static_cast<int>(colValue.b) << CS_XOR(" | ") << static_cast<int>(colValue.a) << CS_XOR(")");
return *this;
}
bool bFirstPrint = true;
int iPrecision = 0;
LogModeFlags_t nModeFlags = LOG_MODE_NONE;
};
/* @section: stream control */
// set console color flags for current stream, will reset on next message
Stream_t::ColorMarker_t SetColor(const LogColorFlags_t nColorFlags);
// set the decimal precision to be used to format floating-point values for current stream, will reset on next message
Stream_t::PrecisionMarker_t SetPrecision(const int m_iPrecision);
// add logging mode flags for current stream, will reset on next message
Stream_t::ModeMarker_t AddFlags(const LogModeFlags_t m_nModeFlags);
// remove logging mode flags for current stream
Stream_t::ModeMarker_t RemoveFlags(const LogModeFlags_t m_nModeFlags);
/* @section: values */
// primary logging stream
inline Stream_t stream;
}

View File

@@ -0,0 +1,30 @@
#include "math.h"
//used: getexportaddr
#include "memory.h"
bool MATH::Setup()
{
bool bSuccess = true;
const void* hTier0Lib = MEM::GetModuleBaseHandle(TIER0_DLL);
if (hTier0Lib == nullptr)
return false;
fnRandomSeed = reinterpret_cast<decltype(fnRandomSeed)>(MEM::GetExportAddress(hTier0Lib, CS_XOR("RandomSeed")));
bSuccess &= (fnRandomSeed != nullptr);
fnRandomFloat = reinterpret_cast<decltype(fnRandomFloat)>(MEM::GetExportAddress(hTier0Lib, CS_XOR("RandomFloat")));
bSuccess &= (fnRandomFloat != nullptr);
fnRandomFloatExp = reinterpret_cast<decltype(fnRandomFloatExp)>(MEM::GetExportAddress(hTier0Lib, CS_XOR("RandomFloatExp")));
bSuccess &= (fnRandomFloatExp != nullptr);
fnRandomInt = reinterpret_cast<decltype(fnRandomInt)>(MEM::GetExportAddress(hTier0Lib, CS_XOR("RandomInt")));
bSuccess &= (fnRandomInt != nullptr);
fnRandomGaussianFloat = reinterpret_cast<decltype(fnRandomGaussianFloat)>(MEM::GetExportAddress(hTier0Lib, CS_XOR("RandomGaussianFloat")));
bSuccess &= (fnRandomGaussianFloat != nullptr);
return bSuccess;
}

View File

@@ -0,0 +1,95 @@
#pragma once
#include "../common.h"
// used: std::is_integral_v
#include <type_traits>
// used: sin, cos, pow, abs, sqrt
#include <corecrt_math.h>// used: MATH::Sin, cos, MATH::Pow, abs, sqrt
// used: rand, srand
#include <cstdlib>
// used: time
#include <ctime>
// convert angle in degrees to radians
#define M_DEG2RAD(DEGREES) ((DEGREES) * (MATH::_PI / 180.f))
// convert angle in radians to degrees
#define M_RAD2DEG(RADIANS) ((RADIANS) * (180.f / MATH::_PI))
/// linearly interpolate the value between @a'X0' and @a'X1' by @a'FACTOR'
#define M_LERP(X0, X1, FACTOR) ((X0) + ((X1) - (X0)) * (FACTOR))
/// trigonometry
#define M_COS(ANGLE) cos(ANGLE)
#define M_SIN(ANGLE) sin(ANGLE)
#define M_TAN(ANGLE) tan(ANGLE)
/// power
#define M_POW(BASE, EXPONENT) pow(BASE, EXPONENT)
/// absolute value
#define M_ABS(VALUE) abs(VALUE)
/// square root
#define M_SQRT(VALUE) sqrt(VALUE)
/// floor
#define M_FLOOR(VALUE) floor(VALUE)
/*
* MATHEMATICS
* - basic trigonometry, algebraic mathematical functions and constants
*/
namespace MATH
{
/* @section: constants */
// pi value
inline constexpr float _PI = 3.141592654f;
// double of pi
inline constexpr float _2PI = 6.283185307f;
// half of pi
inline constexpr float _HPI = 1.570796327f;
// quarter of pi
inline constexpr float _QPI = 0.785398163f;
// reciprocal of double of pi
inline constexpr float _1DIV2PI = 0.159154943f;
// golden ratio
inline constexpr float _PHI = 1.618033988f;
// capture game's exports
bool Setup();
/* @section: algorithm */
/// alternative of 'std::min'
/// @returns : minimal value of the given comparable values
template <typename T>
[[nodiscard]] CS_INLINE constexpr const T& Min(const T& left, const T& right) noexcept
{
return (right < left) ? right : left;
}
/// alternative of 'std::max'
/// @returns : maximal value of the given comparable values
template <typename T>
[[nodiscard]] CS_INLINE constexpr const T& Max(const T& left, const T& right) noexcept
{
return (right > left) ? right : left;
}
/// alternative of 'std::clamp'
/// @returns : value clamped in range ['minimal' .. 'maximal']
template <typename T>
[[nodiscard]] CS_INLINE constexpr const T& Clamp(const T& value, const T& minimal, const T& maximal) noexcept
{
return (value < minimal) ? minimal : (value > maximal) ? maximal :
value;
}
/* @section: exponential */
/// @returns: true if given number is power of two, false otherwise
template <typename T> requires (std::is_integral_v<T>)
[[nodiscard]] CS_INLINE constexpr bool IsPowerOfTwo(const T value) noexcept
{
return value != 0 && (value & (value - 1)) == 0;
}
/* @section: random using game's exports */
inline int(CS_CDECL* fnRandomSeed)(int iSeed) = nullptr;
inline float(CS_CDECL* fnRandomFloat)(float flMinValue, float flMaxValue) = nullptr;
inline float(CS_CDECL* fnRandomFloatExp)(float flMinValue, float flMaxValue, float flExponent) = nullptr;
inline int(CS_CDECL* fnRandomInt)(int iMinValue, int iMaxValue) = nullptr;
inline float(CS_CDECL* fnRandomGaussianFloat)(float flMean, float flStdDev) = nullptr;
}

View File

@@ -0,0 +1,499 @@
// used: __readfsdword
#include <intrin.h>
// used: d3d11
#include <d3d11.h>
#include "memory.h"
// used: l_print
#include "log.h"
// used: chartohexint
#include "crt.h"
// used: pe64
#include "pe64.h"
bool MEM::Setup()
{
bool bSuccess = true;
const void* hDbgHelp = GetModuleBaseHandle(DBGHELP_DLL);
const void* hTier0 = GetModuleBaseHandle(TIER0_DLL);
if (hDbgHelp == nullptr || hTier0 == nullptr)
return false;
fnUnDecorateSymbolName = reinterpret_cast<decltype(fnUnDecorateSymbolName)>(GetExportAddress(hDbgHelp, CS_XOR("UnDecorateSymbolName")));
bSuccess &= (fnUnDecorateSymbolName != nullptr);
fnLoadKV3 = reinterpret_cast<decltype(fnLoadKV3)>(GetExportAddress(hTier0, CS_XOR("?LoadKV3@@YA_NPEAVKeyValues3@@PEAVCUtlString@@PEBDAEBUKV3ID_t@@2@Z")));
bSuccess &= (fnLoadKV3 != nullptr);
fnCreateMaterial = reinterpret_cast<decltype(fnCreateMaterial)>(FindPattern(MATERIAL_SYSTEM2_DLL, CS_XOR("48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 81 EC ? ? ? ? 48 8B 05")));
bSuccess &= (fnCreateMaterial != nullptr);
fnUtlBufferInit = reinterpret_cast<decltype(fnUtlBufferInit)>(GetExportAddress(hTier0, CS_XOR("??0CUtlBuffer@@QEAA@HHH@Z")));
bSuccess &= (fnUtlBufferInit != nullptr);
fnUtlBufferPutString = reinterpret_cast<decltype(fnUtlBufferPutString)>(GetExportAddress(hTier0, CS_XOR("?PutString@CUtlBuffer@@QEAAXPEBD@Z")));
bSuccess &= (fnUtlBufferPutString != nullptr);
fnUtlBufferEnsureCapacity = reinterpret_cast<decltype(fnUtlBufferEnsureCapacity)>(GetExportAddress(hTier0, CS_XOR("?EnsureCapacity@CUtlBuffer@@QEAAXH@Z")));
bSuccess &= (fnUtlBufferEnsureCapacity != nullptr);
return bSuccess;
}
#pragma region memory_allocation
/*
* overload global new/delete operators with our allocators
* - @note: ensure that all sdk classes that can be instantiated have an overloaded constructor and/or game allocator, otherwise marked as non-constructible
*/
void* __cdecl operator new(const std::size_t nSize)
{
return MEM::HeapAlloc(nSize);
}
void* __cdecl operator new[](const std::size_t nSize)
{
return MEM::HeapAlloc(nSize);
}
void __cdecl operator delete(void* pMemory) noexcept
{
MEM::HeapFree(pMemory);
}
void __cdecl operator delete[](void* pMemory) noexcept
{
MEM::HeapFree(pMemory);
}
void* MEM::HeapAlloc(const std::size_t nSize)
{
const HANDLE hHeap = ::GetProcessHeap();
return ::HeapAlloc(hHeap, 0UL, nSize);
}
void MEM::HeapFree(void* pMemory)
{
if (pMemory != nullptr)
{
const HANDLE hHeap = ::GetProcessHeap();
::HeapFree(hHeap, 0UL, pMemory);
}
}
void* MEM::HeapRealloc(void* pMemory, const std::size_t nNewSize)
{
if (pMemory == nullptr)
return HeapAlloc(nNewSize);
if (nNewSize == 0UL)
{
HeapFree(pMemory);
return nullptr;
}
const HANDLE hHeap = ::GetProcessHeap();
return ::HeapReAlloc(hHeap, 0UL, pMemory, nNewSize);
}
#pragma endregion
// @todo: move to win.cpp (or platform.cpp?) except getsectioninfo
#pragma region memory_get
void* MEM::GetModuleBaseHandle(const wchar_t* wszModuleName)
{
const _PEB* pPEB = reinterpret_cast<_PEB*>(__readgsqword(0x60));
if (wszModuleName == nullptr)
return pPEB->ImageBaseAddress;
void* pModuleBase = nullptr;
for (LIST_ENTRY* pListEntry = pPEB->Ldr->InMemoryOrderModuleList.Flink; pListEntry != &pPEB->Ldr->InMemoryOrderModuleList; pListEntry = pListEntry->Flink)
{
const _LDR_DATA_TABLE_ENTRY* pEntry = CONTAINING_RECORD(pListEntry, _LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (pEntry->FullDllName.Buffer != nullptr && CRT::StringCompare(wszModuleName, pEntry->BaseDllName.Buffer) == 0)
{
pModuleBase = pEntry->DllBase;
break;
}
}
if (pModuleBase == nullptr)
L_PRINT(LOG_ERROR) << CS_XOR("module base not found: \"") << wszModuleName << CS_XOR("\"");
return pModuleBase;
}
const wchar_t* MEM::GetModuleBaseFileName(const void* hModuleBase, const bool bGetFullPath)
{
const _PEB* pPEB = reinterpret_cast<_PEB*>(__readgsqword(0x60));
if (hModuleBase == nullptr)
hModuleBase = pPEB->ImageBaseAddress;
::EnterCriticalSection(pPEB->LoaderLock);
const wchar_t* wszModuleName = nullptr;
for (LIST_ENTRY* pListEntry = pPEB->Ldr->InMemoryOrderModuleList.Flink; pListEntry != &pPEB->Ldr->InMemoryOrderModuleList; pListEntry = pListEntry->Flink)
{
const _LDR_DATA_TABLE_ENTRY* pEntry = CONTAINING_RECORD(pListEntry, _LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (pEntry->DllBase == hModuleBase)
{
wszModuleName = bGetFullPath ? pEntry->FullDllName.Buffer : pEntry->BaseDllName.Buffer;
break;
}
}
::LeaveCriticalSection(pPEB->LoaderLock);
return wszModuleName;
}
void* MEM::GetExportAddress(const void* hModuleBase, const char* szProcedureName)
{
const auto pBaseAddress = static_cast<const std::uint8_t*>(hModuleBase);
const auto pIDH = static_cast<const IMAGE_DOS_HEADER*>(hModuleBase);
if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
return nullptr;
const auto pINH = reinterpret_cast<const IMAGE_NT_HEADERS64*>(pBaseAddress + pIDH->e_lfanew);
if (pINH->Signature != IMAGE_NT_SIGNATURE)
return nullptr;
const IMAGE_OPTIONAL_HEADER64* pIOH = &pINH->OptionalHeader;
const std::uintptr_t nExportDirectorySize = pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
const std::uintptr_t uExportDirectoryAddress = pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (nExportDirectorySize == 0U || uExportDirectoryAddress == 0U)
{
L_PRINT(LOG_ERROR) << CS_XOR("module has no exports: \"") << GetModuleBaseFileName(hModuleBase) << CS_XOR("\"");
return nullptr;
}
const auto pIED = reinterpret_cast<const IMAGE_EXPORT_DIRECTORY*>(pBaseAddress + uExportDirectoryAddress);
const auto pNamesRVA = reinterpret_cast<const std::uint32_t*>(pBaseAddress + pIED->AddressOfNames);
const auto pNameOrdinalsRVA = reinterpret_cast<const std::uint16_t*>(pBaseAddress + pIED->AddressOfNameOrdinals);
const auto pFunctionsRVA = reinterpret_cast<const std::uint32_t*>(pBaseAddress + pIED->AddressOfFunctions);
// Perform binary search to find the export by name
std::size_t nRight = pIED->NumberOfNames, nLeft = 0U;
while (nRight != nLeft)
{
// Avoid INT_MAX/2 overflow
const std::size_t uMiddle = nLeft + ((nRight - nLeft) >> 1U);
const int iResult = CRT::StringCompare(szProcedureName, reinterpret_cast<const char*>(pBaseAddress + pNamesRVA[uMiddle]));
if (iResult == 0)
{
const std::uint32_t uFunctionRVA = pFunctionsRVA[pNameOrdinalsRVA[uMiddle]];
#ifdef _DEBUG
L_PRINT(LOG_INFO) << CS_XOR("export found: \"") << reinterpret_cast<const char*>(pBaseAddress + pNamesRVA[uMiddle]) << CS_XOR("\" in \"") << GetModuleBaseFileName(hModuleBase) << CS_XOR("\" at: ") << L::AddFlags(LOG_MODE_INT_SHOWBASE | LOG_MODE_INT_FORMAT_HEX) << uFunctionRVA;
#else
L_PRINT(LOG_INFO) << CS_XOR("export found: ") << szProcedureName;
#endif // _DEBUG
// Check if it's a forwarded export
if (uFunctionRVA >= uExportDirectoryAddress && uFunctionRVA - uExportDirectoryAddress < nExportDirectorySize)
{
// Forwarded exports are not supported
break;
}
return const_cast<std::uint8_t*>(pBaseAddress) + uFunctionRVA;
}
if (iResult > 0)
nLeft = uMiddle + 1;
else
nRight = uMiddle;
}
L_PRINT(LOG_ERROR) << CS_XOR("export not found: ") << szProcedureName;
// Export not found
return nullptr;
}
bool MEM::GetSectionInfo(const void* hModuleBase, const char* szSectionName, std::uint8_t** ppSectionStart, std::size_t* pnSectionSize)
{
const auto pBaseAddress = static_cast<const std::uint8_t*>(hModuleBase);
const auto pIDH = static_cast<const IMAGE_DOS_HEADER*>(hModuleBase);
if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
return false;
const auto pINH = reinterpret_cast<const IMAGE_NT_HEADERS*>(pBaseAddress + pIDH->e_lfanew);
if (pINH->Signature != IMAGE_NT_SIGNATURE)
return false;
const IMAGE_SECTION_HEADER* pISH = IMAGE_FIRST_SECTION(pINH);
// go through all code sections
for (WORD i = 0U; i < pINH->FileHeader.NumberOfSections; i++, pISH++)
{
// @test: use case insensitive comparison instead?
if (CRT::StringCompareN(szSectionName, reinterpret_cast<const char*>(pISH->Name), IMAGE_SIZEOF_SHORT_NAME) == 0)
{
if (ppSectionStart != nullptr)
*ppSectionStart = const_cast<std::uint8_t*>(pBaseAddress) + pISH->VirtualAddress;
if (pnSectionSize != nullptr)
*pnSectionSize = pISH->SizeOfRawData;
return true;
}
}
L_PRINT(LOG_ERROR) << CS_XOR("code section not found: \"") << szSectionName << CS_XOR("\"");
return false;
}
#pragma endregion
#pragma region memory_search
std::uint8_t* MEM::FindPattern(const wchar_t* wszModuleName, const char* szPattern)
{
// convert pattern string to byte array
const std::size_t nApproximateBufferSize = (CRT::StringLength(szPattern) >> 1U) + 1U;
std::uint8_t* arrByteBuffer = static_cast<std::uint8_t*>(MEM_STACKALLOC(nApproximateBufferSize));
char* szMaskBuffer = static_cast<char*>(MEM_STACKALLOC(nApproximateBufferSize));
PatternToBytes(szPattern, arrByteBuffer, szMaskBuffer);
// @test: use search with straight in-place conversion? do not think it will be faster, cuz of bunch of new checks that gonna be performed for each iteration
return FindPattern(wszModuleName, reinterpret_cast<const char*>(arrByteBuffer), szMaskBuffer);
}
std::uint8_t* MEM::FindPattern(const wchar_t* wszModuleName, const char* szBytePattern, const char* szByteMask)
{
const void* hModuleBase = GetModuleBaseHandle(wszModuleName);
if (hModuleBase == nullptr)
{
L_PRINT(LOG_ERROR) << CS_XOR("failed to get module handle for: \"") << wszModuleName << CS_XOR("\"");
return nullptr;
}
const auto pBaseAddress = static_cast<const std::uint8_t*>(hModuleBase);
const auto pIDH = static_cast<const IMAGE_DOS_HEADER*>(hModuleBase);
if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
{
L_PRINT(LOG_ERROR) << CS_XOR("failed to get module size, image is invalid");
return nullptr;
}
const auto pINH = reinterpret_cast<const IMAGE_NT_HEADERS*>(pBaseAddress + pIDH->e_lfanew);
if (pINH->Signature != IMAGE_NT_SIGNATURE)
{
L_PRINT(LOG_ERROR) << CS_XOR("failed to get module size, image is invalid");
return nullptr;
}
const std::uint8_t* arrByteBuffer = reinterpret_cast<const std::uint8_t*>(szBytePattern);
const std::size_t nByteCount = CRT::StringLength(szByteMask);
std::uint8_t* pFoundAddress = nullptr;
// perform little overhead to keep all patterns unique
#ifdef CS_PARANOID_PATTERN_UNIQUENESS
const std::vector<std::uint8_t*> vecFoundOccurrences = FindPatternAllOccurrencesEx(pBaseAddress, pINH->OptionalHeader.SizeOfImage, arrByteBuffer, nByteCount, szByteMask);
// notify user about non-unique pattern
if (!vecFoundOccurrences.empty())
{
// notify user about non-unique pattern
if (vecFoundOccurrences.size() > 1U)
{
char* szPattern = static_cast<char*>(MEM_STACKALLOC((nByteCount << 1U) + nByteCount));
[[maybe_unused]] const std::size_t nConvertedPatternLength = BytesToPattern(arrByteBuffer, nByteCount, szPattern);
L_PRINT(LOG_WARNING) << CS_XOR("found more than one occurrence with \"") << szPattern << CS_XOR("\" pattern, consider updating it!");
MEM_STACKFREE(szPattern);
}
// return first found occurrence
pFoundAddress = vecFoundOccurrences[0];
}
#else
// @todo: we also can go through code sections and skip noexec pages, but will it really improve performance? / or at least for all occurrences search
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header
#if 0
IMAGE_SECTION_HEADER* pCurrentSection = IMAGE_FIRST_SECTION(pINH);
for (WORD i = 0U; i != pINH->FileHeader.NumberOfSections; i++)
{
// check does page have executable code
if (pCurrentSection->Characteristics & IMAGE_SCN_CNT_CODE || pCurrentSection->Characteristics & IMAGE_SCN_MEM_EXECUTE)
{
pFoundAddress = FindPatternEx(pBaseAddress + pCurrentSection->VirtualAddress, pCurrentSection->SizeOfRawData, arrByteBuffer, nByteCount, szByteMask);
if (pFoundAddress != nullptr)
break;
}
++pCurrentSection;
}
#else
pFoundAddress = FindPatternEx(pBaseAddress, pINH->OptionalHeader.SizeOfImage, arrByteBuffer, nByteCount, szByteMask);
#endif
#endif
if (pFoundAddress == nullptr)
{
char* szPattern = static_cast<char*>(MEM_STACKALLOC((nByteCount << 1U) + nByteCount));
[[maybe_unused]] const std::size_t nConvertedPatternLength = BytesToPattern(arrByteBuffer, nByteCount, szPattern);
L_PRINT(LOG_ERROR) << CS_XOR("pattern not found: \"") << szPattern << CS_XOR("\"");
MEM_STACKFREE(szPattern);
}
return pFoundAddress;
}
// @todo: msvc poorly optimizes this, it looks even better w/o optimization at all
std::uint8_t* MEM::FindPatternEx(const std::uint8_t* pRegionStart, const std::size_t nRegionSize, const std::uint8_t* arrByteBuffer, const std::size_t nByteCount, const char* szByteMask)
{
std::uint8_t* pCurrentAddress = const_cast<std::uint8_t*>(pRegionStart);
const std::uint8_t* pRegionEnd = pRegionStart + nRegionSize - nByteCount;
const bool bIsMaskUsed = (szByteMask != nullptr);
while (pCurrentAddress < pRegionEnd)
{
// check the first byte before entering the loop, otherwise if there two consecutive bytes of first byte in the buffer, we may skip both and fail the search
if ((bIsMaskUsed && *szByteMask == '?') || *pCurrentAddress == *arrByteBuffer)
{
if (nByteCount == 1)
return pCurrentAddress;
// compare the least byte sequence and continue on wildcard or skip forward on first mismatched byte
std::size_t nComparedBytes = 0U;
while ((bIsMaskUsed && szByteMask[nComparedBytes + 1U] == '?') || pCurrentAddress[nComparedBytes + 1U] == arrByteBuffer[nComparedBytes + 1U])
{
// check does byte sequence match
if (++nComparedBytes == nByteCount - 1U)
return pCurrentAddress;
}
// skip non suitable bytes
pCurrentAddress += nComparedBytes;
}
++pCurrentAddress;
}
return nullptr;
}
std::vector<std::uint8_t*> MEM::FindPatternAllOccurrencesEx(const std::uint8_t* pRegionStart, const std::size_t nRegionSize, const std::uint8_t* arrByteBuffer, const std::size_t nByteCount, const char* szByteMask)
{
const std::uint8_t* pRegionEnd = pRegionStart + nRegionSize - nByteCount;
const bool bIsMaskUsed = (szByteMask != nullptr);
// container for addresses of the all found occurrences
std::vector<std::uint8_t*> vecOccurrences = {};
for (std::uint8_t* pCurrentByte = const_cast<std::uint8_t*>(pRegionStart); pCurrentByte < pRegionEnd; ++pCurrentByte)
{
// do a first byte check before entering the loop, otherwise if there two consecutive bytes of first byte in the buffer, we may skip both and fail the search
if ((!bIsMaskUsed || *szByteMask != '?') && *pCurrentByte != *arrByteBuffer)
continue;
// check for bytes sequence match
bool bSequenceMatch = true;
for (std::size_t i = 1U; i < nByteCount; i++)
{
// compare sequence and continue on wildcard or skip forward on first mismatched byte
if ((!bIsMaskUsed || szByteMask[i] != '?') && pCurrentByte[i] != arrByteBuffer[i])
{
// skip non suitable bytes
pCurrentByte += i - 1U;
bSequenceMatch = false;
break;
}
}
// check did we found address
if (bSequenceMatch)
vecOccurrences.push_back(pCurrentByte);
}
return vecOccurrences;
}
#pragma endregion
#pragma region memory_extra
std::size_t MEM::PatternToBytes(const char* szPattern, std::uint8_t* pOutByteBuffer, char* szOutMaskBuffer)
{
std::uint8_t* pCurrentByte = pOutByteBuffer;
while (*szPattern != '\0')
{
// check is a wildcard
if (*szPattern == '?')
{
++szPattern;
#ifdef CS_PARANOID
CS_ASSERT(*szPattern == '\0' || *szPattern == ' ' || *szPattern == '?'); // we're expect that next character either terminating null, whitespace or part of double wildcard (note that it's required if your pattern written without whitespaces)
#endif
// ignore that
*pCurrentByte++ = 0U;
*szOutMaskBuffer++ = '?';
}
// check is not space
else if (*szPattern != ' ')
{
// convert two consistent numbers in a row to byte value
std::uint8_t uByte = static_cast<std::uint8_t>(CRT::CharToHexInt(*szPattern) << 4);
++szPattern;
#ifdef CS_PARANOID
CS_ASSERT(*szPattern != '\0' && *szPattern != '?' && *szPattern != ' '); // we're expect that byte always represented by two numbers in a row
#endif
uByte |= static_cast<std::uint8_t>(CRT::CharToHexInt(*szPattern));
*pCurrentByte++ = uByte;
*szOutMaskBuffer++ = 'x';
}
++szPattern;
}
// zero terminate both buffers
*pCurrentByte = 0U;
*szOutMaskBuffer = '\0';
return pCurrentByte - pOutByteBuffer;
}
std::size_t MEM::BytesToPattern(const std::uint8_t* pByteBuffer, const std::size_t nByteCount, char* szOutBuffer)
{
char* szCurrentPattern = szOutBuffer;
for (std::size_t i = 0U; i < nByteCount; i++)
{
// manually convert byte to chars
const char* szHexByte = &CRT::_TWO_DIGITS_HEX_LUT[pByteBuffer[i] * 2U];
*szCurrentPattern++ = szHexByte[0];
*szCurrentPattern++ = szHexByte[1];
*szCurrentPattern++ = ' ';
}
*--szCurrentPattern = '\0';
return szCurrentPattern - szOutBuffer;
}
#pragma endregion

View File

@@ -0,0 +1,150 @@
#pragma once
// used: memory api
#include <memory>
// used: std::vector
#include <vector>
#include "../common.h"
#pragma region memory_definitions
#pragma warning(push)
#pragma warning(disable: 6255) // '_alloca' indicates failure by raising a stack overflow exception. consider using '_malloca' instead
#define MEM_STACKALLOC(SIZE) _malloca(SIZE)
#pragma warning(pop)
#define MEM_STACKFREE(MEMORY) static_cast<void>(0)
#define MEM_PAD(SIZE) \
private: \
char CS_CONCATENATE(pad_0, __COUNTER__)[SIZE]; \
public:
#pragma endregion
class CUtlBuffer;
class CKeyValues3;
struct KV3ID_t;
namespace MEM
{
bool Setup();
/* @section: allocation */
// allocate a block of memory from a heap
[[nodiscard]] void* HeapAlloc(const std::size_t nSize);
// free a memory block allocated from a heap
void HeapFree(void* pMemory);
// reallocate a block of memory from a heap
// @note: we're expect this to allocate instead when passed null, and free if size is null
void* HeapRealloc(void* pMemory, const std::size_t nNewSize);
/* @section: get */
/// alternative of 'GetModuleHandle()'
/// @param[in] wszModuleName module name to search base handle for, null means current process
/// @returns: base handle of module with given name if it exist, null otherwise
[[nodiscard]] void* GetModuleBaseHandle(const wchar_t* wszModuleName);
/// alternative of 'GetModuleFileName()'
/// @param[in] hModuleBase module base to search filename for, null means current process
/// @returns: name of given module if it's valid, null otherwise
[[nodiscard]] const wchar_t* GetModuleBaseFileName(const void* hModuleBase, const bool bGetFullPath = false);
/// alternative of 'GetProcAddress()'
/// @remarks: doesn't support forwarded exports, this means you may need to manual call 'LoadLibrary'/'FreeLibrary' for export library
/// @returns: pointer to exported procedure
[[nodiscard]] void* GetExportAddress(const void* hModuleBase, const char* szProcedureName);
/// @param[in] szSectionName section to get info of (e.g. ".rdata", ".text", etc)
/// @param[out] ppSectionStart output for section start address
/// @param[out] pnSectionSize output for section size
/// @returns: true if code section has been found, false otherwise
[[nodiscard]] bool GetSectionInfo(const void* hModuleBase, const char* szSectionName, std::uint8_t** ppSectionStart, std::size_t* pnSectionSize);
/// get absolute address from relative address
/// @param[in] pRelativeAddress pointer to relative address, e.g. destination address from JMP, JE, JNE and others instructions
/// @param[in] nPreOffset offset before relative address
/// @param[in] nPostOffset offset after relative address
/// @returns: pointer to absolute address
template <typename T = std::uint8_t>
[[nodiscard]] T* GetAbsoluteAddress(T* pRelativeAddress, int nPreOffset = 0x0, int nPostOffset = 0x0)
{
pRelativeAddress += nPreOffset;
pRelativeAddress += sizeof(std::int32_t) + *reinterpret_cast<std::int32_t*>(pRelativeAddress);
pRelativeAddress += nPostOffset;
return pRelativeAddress;
}
/// resolve rip relative address
/// @param[in] nAddressBytes as byte for the address we want to resolve
/// @param[in] nRVAOffset offset of the relative address
/// @param[in] nRIPOffset offset of the instruction pointer
/// @returns: pointer to resolved address
[[nodiscard]] CS_INLINE std::uint8_t* ResolveRelativeAddress(std::uint8_t* nAddressBytes, std::uint32_t nRVAOffset, std::uint32_t nRIPOffset)
{
std::uint32_t nRVA = *reinterpret_cast<std::uint32_t*>(nAddressBytes + nRVAOffset);
std::uint64_t nRIP = reinterpret_cast<std::uint64_t>(nAddressBytes) + nRIPOffset;
return reinterpret_cast<std::uint8_t*>(nRVA + nRIP);
}
/// get pointer to function of virtual-function table
/// @returns: pointer to virtual function
template <typename T = void*>
[[nodiscard]] CS_INLINE T GetVFunc(const void* thisptr, std::size_t nIndex)
{
return (*static_cast<T* const*>(thisptr))[nIndex];
}
/// call virtual function of specified class at given index
/// @note: reference and const reference arguments must be forwarded as pointers or wrapped with 'std::ref'/'std::cref' calls!
/// @returns: result of virtual function call
template <typename T, std::size_t nIndex, class CBaseClass, typename... Args_t>
static CS_INLINE T CallVFunc(CBaseClass* thisptr, Args_t... argList)
{
using VirtualFn_t = T(__thiscall*)(const void*, decltype(argList)...);
return (*reinterpret_cast<VirtualFn_t* const*>(reinterpret_cast<std::uintptr_t>(thisptr)))[nIndex](thisptr, argList...);
}
/* @section: search */
/// ida style pattern byte comparison in a specific mo dule
/// @param[in] wszModuleName module name where to search for pattern
/// @param[in] szPattern ida style pattern, e.g. "55 8B 40 ? 30", wildcard can be either '?' or "??", bytes always presented by two numbers in a row [00 .. FF], whitespaces can be omitted (wildcards in this case should be two-character)
/// @returns: pointer to address of the first found occurrence with equal byte sequence on success, null otherwise
[[nodiscard]] std::uint8_t* FindPattern(const wchar_t* wszModuleName, const char* szPattern);
/// naive style pattern byte comparison in a specific module
/// @param[in] wszModuleName module name where to search for pattern
/// @param[in] szBytePattern naive style pattern, e.g. "\x55\x8B\x40\x00\x30", wildcard bytes value ignored
/// @param[in] szByteMask wildcard mask for byte array, e.g. "xxx?x", should always correspond to bytes count
/// @returns: pointer to address of the first found occurrence with equal byte sequence on success, null otherwise
[[nodiscard]] std::uint8_t* FindPattern(const wchar_t* wszModuleName, const char* szBytePattern, const char* szByteMask);
/// pattern byte comparison in the specific region
/// @param[in] arrByteBuffer byte sequence to search
/// @param[in] nByteCount count of search bytes
/// @param[in] szByteMask [optional] wildcard mask for byte array
/// @returns: pointer to address of the first found occurrence with equal byte sequence on success, null otherwise
[[nodiscard]] std::uint8_t* FindPatternEx(const std::uint8_t* pRegionStart, const std::size_t nRegionSize, const std::uint8_t* arrByteBuffer, const std::size_t nByteCount, const char* szByteMask = nullptr);
/// pattern byte comparison in the specific region
/// @param[in] arrByteBuffer byte sequence to search
/// @param[in] nByteCount count of search bytes
/// @param[in] szByteMask [optional] wildcard mask for byte array
/// @returns: pointers to addresses of the all found occurrences with equal byte sequence on success, empty otherwise
[[nodiscard]] std::vector<std::uint8_t*> FindPatternAllOccurrencesEx(const std::uint8_t* pRegionStart, const std::size_t nRegionSize, const std::uint8_t* arrByteBuffer, const std::size_t nByteCount, const char* szByteMask = nullptr);
/// class RTTI virtual table search in a specific module
/// @returns: pointer to the found virtual table on success, null otherwise
/* @section: extra */
/// convert ida-style pattern to byte array
/// @param[in] szPattern ida-style pattern, e.g. "55 8B 40 ? 30", wildcard can be either '?' or "??", bytes are always presented by two numbers in a row [00 .. FF], blank delimiters are ignored and not necessary (wildcard in this case should be two-character)
/// @param[out] pOutByteBuffer output for converted, zero-terminated byte array
/// @param[out] szOutMaskBuffer output for wildcard, zero-terminated byte mask
/// @returns: count of the converted bytes from the pattern
std::size_t PatternToBytes(const char* szPattern, std::uint8_t* pOutByteBuffer, char* szOutMaskBuffer);
/// convert byte array to ida-style pattern
/// @param[in] pByteBuffer buffer of bytes to convert
/// @param[in] nByteCount count of bytes to convert
/// @param[out] szOutBuffer output for converted pattern
/// @returns: length of the converted ida-style pattern, not including the terminating null
std::size_t BytesToPattern(const std::uint8_t* pByteBuffer, const std::size_t nByteCount, char* szOutBuffer);
/* @section: game exports */
inline unsigned long(CS_STDCALL* fnUnDecorateSymbolName)(const char* szName, char* pszOutput, unsigned long nMaxStringLength, unsigned long dwFlags) = nullptr;
inline bool(CS_FASTCALL* fnLoadKV3)(CKeyValues3*, void*, const char*, const KV3ID_t*, const char*);
inline std::int64_t(CS_FASTCALL* fnCreateMaterial)(void*, void*, const char*, void*, unsigned int, unsigned int);
inline void(CS_FASTCALL* fnUtlBufferInit)(CUtlBuffer*, int, int, int);
inline void(CS_FASTCALL* fnUtlBufferPutString)(CUtlBuffer*, const char*);
inline void(CS_FASTCALL* fnUtlBufferEnsureCapacity)(CUtlBuffer*, int);
}

View File

@@ -0,0 +1,144 @@
#include "notify.h"
// used: cheat variables
#include "../core/variables.h"
// used: menu::bMainWindowOpened
#include "../core/menu.h"
// used: [resources] font awesome icons definitions
#include "../../resources/font_awesome_5.h"
// used: easingg library
#include "easing.h"
inline static const float GetTime() noexcept
{
return static_cast<float>(clock() / 1000.f);
}
inline static bool IsEmptyOrNullptr(const char* szText)
{
return szText == nullptr || szText[0] == '\0';
}
NOTIFY::NotificationData_t::NotificationData_t(ENotificationType nType, const char* szFormat, ...) :
nType(nType), flCreateionTime(GetTime()), animHandler(&EASING::InQuad, &EASING::OutQuad)
{
va_list args;
va_start(args, szFormat);
stbsp_vsnprintf(this->szBuffer, sizeof(szBuffer), szFormat, args);
va_end(args);
}
const Color_t& NOTIFY::NotificationData_t::GetTypeColor() const
{
switch (nType)
{
case N_TYPE_INFO:
// cyan
return Color_t(0, 255, 255);
case N_TYPE_SUCCESS:
// green
return Color_t(0, 255, 0);
case N_TYPE_WARNING:
// yellow
return Color_t(255, 255, 0);
case N_TYPE_ERROR:
// red
return Color_t(255, 0, 0);
default:
// white
return Color_t(255, 255, 255);
}
}
const char* NOTIFY::NotificationData_t::Data() const
{
return this->szBuffer;
}
const char* NOTIFY::NotificationData_t::GetIcon() const
{
switch (nType)
{
case N_TYPE_INFO:
return ICON_FA_INFO;
case N_TYPE_SUCCESS:
return ICON_FA_CHECK;
case N_TYPE_WARNING:
return ICON_FA_EXCLAMATION;
case N_TYPE_ERROR:
return ICON_FA_TIMES;
default:
return nullptr;
}
}
const float NOTIFY::NotificationData_t::GetTimeDelta(const float flCurrentTime) const
{
return flCurrentTime - this->flCreateionTime;
}
void NOTIFY::Push(const NotificationData_t& notification)
{
vecNotifications.push_back(notification);
}
void NOTIFY::_Remove(size_t nIndex)
{
vecNotifications.erase(vecNotifications.begin() + nIndex);
}
void NOTIFY::Render()
{
if (vecNotifications.empty())
return;
ImGuiStyle& style = ImGui::GetStyle();
ImGuiIO& io = ImGui::GetIO();
// padding with menu watermark
float flPaddingY = (MENU::bMainWindowOpened && C_GET(bool, Vars.bWatermark)) ? ImGui::GetFrameHeight() : 0.f;
for (size_t i = 0U; i < vecNotifications.size(); i++)
{
NotificationData_t* pData = &vecNotifications[i];
// shouldn't happen, but maybe it does
if (IsEmptyOrNullptr(pData->Data()))
continue;
// handling animation
const float flTimeDelta = pData->GetTimeDelta(GetTime());
pData->animHandler.Update(io.DeltaTime, style.AnimationSpeed);
if (flTimeDelta >= (_MAX_TIME - 0.25f))
pData->animHandler.SetSwitch(false);
else if (flTimeDelta <= 0.25f)
pData->animHandler.SetSwitch(true);
const float flAnimValue = pData->animHandler.GetValue(1.f);
// if animation is done, remove notification
if (!pData->animHandler.GetSwitch())
{
_Remove(i);
continue;
}
// render frame and notification
CRT::String_t<32U> szWindowName(CS_XOR("notification##%d"), i);
ImGui::SetNextWindowPos(ImVec2(style.WindowPadding.x * flAnimValue, flPaddingY * flAnimValue), ImGuiCond_Always);
ImGui::Begin(szWindowName.Data(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing);
{
if (const char* szIcon = pData->GetIcon(); szIcon != nullptr)
{
ImGui::TextColored(pData->GetTypeColor().GetVec4(flAnimValue), szIcon);
ImGui::SameLine();
}
ImGui::TextColored(C_GET(ColorPickerVar_t, Vars.colPrimtv0).colValue.GetVec4(flAnimValue), pData->Data());
flPaddingY += ImGui::GetWindowHeight();
}
ImGui::End();
}
}

View File

@@ -0,0 +1,75 @@
#pragma once
// used: [stl] vector
#include <vector>
// used: draw wrapper
#include "draw.h"
#pragma region notify_definitions
#define NOFITY_TEXT_SIZE 64U // max size of notification text
// @todo: use ImStyle?
#define NOTIFY_ANIMATION_TIME 15.0 // time in ms to show/hide notification
#define NOTIFY_DELETE_TIME 30.0 // time in ms to delete notification
#pragma endregion
#pragma region notify_enumerations
using NotificationType_t = int;
enum ENotificationType : NotificationType_t
{
N_TYPE_DEFAULT = 0,
N_TYPE_INFO,
N_TYPE_SUCCESS,
N_TYPE_WARNING,
N_TYPE_ERROR,
N_TYPE_MAX
};
using NotificationState_t = int;
enum ENotificationState : NotificationState_t
{
N_STATE_START = 0,
N_STATE_STAY,
N_STATE_END,
N_STATE_EXPIRED,
N_STATE_MAX
};
#pragma endregion
namespace NOTIFY
{
struct NotificationData_t
{
NotificationData_t(ENotificationType nType, const char* szFormat, ...);
/// @return color of notification type
const Color_t& GetTypeColor() const;
/// @return c-type string of notification text
const char* Data() const;
/// @return icon of notification type
const char* GetIcon() const;
/// @return time difference between creation and current time
const float GetTimeDelta(const float flCurrentTime) const;
int nType = 0;
char szBuffer[NOFITY_TEXT_SIZE];
float flCreateionTime = 0.0;
AnimationHandler_t animHandler = AnimationHandler_t();
};
/* @section: main */
// push notification to queue
void Push(const NotificationData_t& notification);
// pop notification from queue
void _Remove(size_t nIndex);
// render notifications
void Render();
/* @section: values */
// maximum time to show notification
inline constexpr float _MAX_TIME = 5.f;
// maximum count of notifications
inline std::vector<NotificationData_t> vecNotifications = {};
}

View File

@@ -0,0 +1,592 @@
#pragma once
// used: [win] winapi
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#pragma region winapi_nt_types
using NTSTATUS = LONG;
using MEMORY_INFORMATION_CLASS = INT;
#pragma endregion
#pragma region winapi_nt_definitions
#define NtCurrentProcess() (reinterpret_cast<HANDLE>(-1))
#define NtCurrentThread() (reinterpret_cast<HANDLE>(-2))
/*
* NT_SUCCESS = [0x00000000 .. 0x3FFFFFFF]
* NT_INFORMATION = [0x40000000 .. 0x7FFFFFFF]
* NT_WARNING = [0x80000000 .. 0xBFFFFFFF]
* NT_ERROR = [0xC0000000 .. 0xFFFFFFFF]
*/
#define NT_SUCCESS(STATUS) (static_cast<NTSTATUS>(STATUS) >= 0)
#define NT_INFORMATION(STATUS) ((static_cast<ULONG>(STATUS) >> 30UL) == 1UL)
#define NT_WARNING(STATUS) ((static_cast<ULONG>(STATUS) >> 30UL) == 2UL)
#define NT_ERROR(STATUS) ((static_cast<ULONG>(STATUS) >> 30UL) == 3UL)
#pragma endregion
#pragma region winapi_nt
// @credits: https://www.vergiliusproject.com/kernels/x86/Windows%2010
typedef struct _UNICODE_STRING
{
USHORT Length; // 0x0
USHORT MaximumLength; // 0x2
WCHAR* Buffer; // 0x8
} UNICODE_STRING, *PUNICODE_STRING;
static_assert(sizeof(_UNICODE_STRING) == 0x10);
struct _RTL_BALANCED_NODE
{
union
{
struct _RTL_BALANCED_NODE* Children[2]; //0x0
struct
{
struct _RTL_BALANCED_NODE* Left; //0x0
struct _RTL_BALANCED_NODE* Right; //0x8
};
};
union
{
struct
{
UCHAR Red : 1; //0x10
UCHAR Balance : 2; //0x10
};
ULONGLONG ParentValue; //0x10
};
};
static_assert(sizeof(_RTL_BALANCED_NODE) == 0x18);
struct _LDR_DATA_TABLE_ENTRY
{
struct _LIST_ENTRY InLoadOrderLinks; //0x0
struct _LIST_ENTRY InMemoryOrderLinks; //0x10
struct _LIST_ENTRY InInitializationOrderLinks; //0x20
VOID* DllBase; //0x30
VOID* EntryPoint; //0x38
ULONG SizeOfImage; //0x40
struct _UNICODE_STRING FullDllName; //0x48
struct _UNICODE_STRING BaseDllName; //0x58
union
{
UCHAR FlagGroup[4]; //0x68
ULONG Flags; //0x68
struct
{
ULONG PackagedBinary : 1; //0x68
ULONG MarkedForRemoval : 1; //0x68
ULONG ImageDll : 1; //0x68
ULONG LoadNotificationsSent : 1; //0x68
ULONG TelemetryEntryProcessed : 1; //0x68
ULONG ProcessStaticImport : 1; //0x68
ULONG InLegacyLists : 1; //0x68
ULONG InIndexes : 1; //0x68
ULONG ShimDll : 1; //0x68
ULONG InExceptionTable : 1; //0x68
ULONG ReservedFlags1 : 2; //0x68
ULONG LoadInProgress : 1; //0x68
ULONG LoadConfigProcessed : 1; //0x68
ULONG EntryProcessed : 1; //0x68
ULONG ProtectDelayLoad : 1; //0x68
ULONG ReservedFlags3 : 2; //0x68
ULONG DontCallForThreads : 1; //0x68
ULONG ProcessAttachCalled : 1; //0x68
ULONG ProcessAttachFailed : 1; //0x68
ULONG CorDeferredValidate : 1; //0x68
ULONG CorImage : 1; //0x68
ULONG DontRelocate : 1; //0x68
ULONG CorILOnly : 1; //0x68
ULONG ChpeImage : 1; //0x68
ULONG ChpeEmulatorImage : 1; //0x68
ULONG ReservedFlags5 : 1; //0x68
ULONG Redirected : 1; //0x68
ULONG ReservedFlags6 : 2; //0x68
ULONG CompatDatabaseProcessed : 1; //0x68
};
};
USHORT ObsoleteLoadCount; //0x6c
USHORT TlsIndex; //0x6e
struct _LIST_ENTRY HashLinks; //0x70
ULONG TimeDateStamp; //0x80
struct _ACTIVATION_CONTEXT* EntryPointActivationContext; //0x88
VOID* Lock; //0x90
struct _LDR_DDAG_NODE* DdagNode; //0x98
struct _LIST_ENTRY NodeModuleLink; //0xa0
struct _LDRP_LOAD_CONTEXT* LoadContext; //0xb0
VOID* ParentDllBase; //0xb8
VOID* SwitchBackContext; //0xc0
_RTL_BALANCED_NODE BaseAddressIndexNode; //0xc8
_RTL_BALANCED_NODE MappingInfoIndexNode; //0xe0
ULONGLONG OriginalBase; //0xf8
union _LARGE_INTEGER LoadTime; //0x100
ULONG BaseNameHashValue; //0x108
enum _LDR_DLL_LOAD_REASON LoadReason; //0x10c
ULONG ImplicitPathOptions; //0x110
ULONG ReferenceCount; //0x114
ULONG DependentLoadFlags; //0x118
UCHAR SigningLevel; //0x11c
ULONG CheckSum; //0x120
VOID* ActivePatchImageBase; //0x128
enum _LDR_HOT_PATCH_STATE HotPatchState; //0x130
};
static_assert(sizeof(_LDR_DATA_TABLE_ENTRY) == 0x138);
struct _PEB_LDR_DATA
{
ULONG Length; //0x0
UCHAR Initialized; //0x4
VOID* SsHandle; //0x8
struct _LIST_ENTRY InLoadOrderModuleList; //0x10
struct _LIST_ENTRY InMemoryOrderModuleList; //0x20
struct _LIST_ENTRY InInitializationOrderModuleList; //0x30
VOID* EntryInProgress; //0x40
UCHAR ShutdownInProgress; //0x48
VOID* ShutdownThreadId; //0x50
};
static_assert(sizeof(_PEB_LDR_DATA) == 0x58);
struct _CURDIR
{
struct _UNICODE_STRING DosPath; //0x0
VOID* Handle; //0x10
};
static_assert(sizeof(_CURDIR) == 0x18);
struct _STRING
{
USHORT Length; //0x0
USHORT MaximumLength; //0x2
CHAR* Buffer; //0x8
};
static_assert(sizeof(_STRING) == 0x10);
struct _RTL_DRIVE_LETTER_CURDIR
{
USHORT Flags; //0x0
USHORT Length; //0x2
ULONG TimeStamp; //0x4
struct _STRING DosPath; //0x8
};
static_assert(sizeof(_RTL_DRIVE_LETTER_CURDIR) == 0x18);
struct _RTL_USER_PROCESS_PARAMETERS
{
ULONG MaximumLength; //0x0
ULONG Length; //0x4
ULONG Flags; //0x8
ULONG DebugFlags; //0xc
VOID* ConsoleHandle; //0x10
ULONG ConsoleFlags; //0x18
VOID* StandardInput; //0x20
VOID* StandardOutput; //0x28
VOID* StandardError; //0x30
struct _CURDIR CurrentDirectory; //0x38
struct _UNICODE_STRING DllPath; //0x50
struct _UNICODE_STRING ImagePathName; //0x60
struct _UNICODE_STRING CommandLine; //0x70
VOID* Environment; //0x80
ULONG StartingX; //0x88
ULONG StartingY; //0x8c
ULONG CountX; //0x90
ULONG CountY; //0x94
ULONG CountCharsX; //0x98
ULONG CountCharsY; //0x9c
ULONG FillAttribute; //0xa0
ULONG WindowFlags; //0xa4
ULONG ShowWindowFlags; //0xa8
struct _UNICODE_STRING WindowTitle; //0xb0
struct _UNICODE_STRING DesktopInfo; //0xc0
struct _UNICODE_STRING ShellInfo; //0xd0
struct _UNICODE_STRING RuntimeData; //0xe0
struct _RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32]; //0xf0
ULONGLONG EnvironmentSize; //0x3f0
ULONGLONG EnvironmentVersion; //0x3f8
VOID* PackageDependencyData; //0x400
ULONG ProcessGroupId; //0x408
ULONG LoaderThreads; //0x40c
struct _UNICODE_STRING RedirectionDllName; //0x410
struct _UNICODE_STRING HeapPartitionName; //0x420
ULONGLONG* DefaultThreadpoolCpuSetMasks; //0x430
ULONG DefaultThreadpoolCpuSetMaskCount; //0x438
ULONG DefaultThreadpoolThreadMaximum; //0x43c
ULONG HeapMemoryTypeMask; //0x440
};
static_assert(sizeof(_RTL_USER_PROCESS_PARAMETERS) == 0x448);
struct _PEB
{
UCHAR InheritedAddressSpace; //0x0
UCHAR ReadImageFileExecOptions; //0x1
UCHAR BeingDebugged; //0x2
union
{
UCHAR BitField; //0x3
struct
{
UCHAR ImageUsesLargePages : 1; //0x3
UCHAR IsProtectedProcess : 1; //0x3
UCHAR IsImageDynamicallyRelocated : 1; //0x3
UCHAR SkipPatchingUser32Forwarders : 1; //0x3
UCHAR IsPackagedProcess : 1; //0x3
UCHAR IsAppContainer : 1; //0x3
UCHAR IsProtectedProcessLight : 1; //0x3
UCHAR IsLongPathAwareProcess : 1; //0x3
};
};
UCHAR Padding0[4]; //0x4
VOID* Mutant; //0x8
VOID* ImageBaseAddress; //0x10
struct _PEB_LDR_DATA* Ldr; //0x18
struct _RTL_USER_PROCESS_PARAMETERS* ProcessParameters; //0x20
VOID* SubSystemData; //0x28
VOID* ProcessHeap; //0x30
struct _RTL_CRITICAL_SECTION* FastPebLock; //0x38
union _SLIST_HEADER* volatile AtlThunkSListPtr; //0x40
VOID* IFEOKey; //0x48
union
{
ULONG CrossProcessFlags; //0x50
struct
{
ULONG ProcessInJob : 1; //0x50
ULONG ProcessInitializing : 1; //0x50
ULONG ProcessUsingVEH : 1; //0x50
ULONG ProcessUsingVCH : 1; //0x50
ULONG ProcessUsingFTH : 1; //0x50
ULONG ProcessPreviouslyThrottled : 1; //0x50
ULONG ProcessCurrentlyThrottled : 1; //0x50
ULONG ProcessImagesHotPatched : 1; //0x50
ULONG ReservedBits0 : 24; //0x50
};
};
UCHAR Padding1[4]; //0x54
union
{
VOID* KernelCallbackTable; //0x58
VOID* UserSharedInfoPtr; //0x58
};
ULONG SystemReserved; //0x60
ULONG AtlThunkSListPtr32; //0x64
VOID* ApiSetMap; //0x68
ULONG TlsExpansionCounter; //0x70
UCHAR Padding2[4]; //0x74
struct _RTL_BITMAP* TlsBitmap; //0x78
ULONG TlsBitmapBits[2]; //0x80
VOID* ReadOnlySharedMemoryBase; //0x88
VOID* SharedData; //0x90
VOID** ReadOnlyStaticServerData; //0x98
VOID* AnsiCodePageData; //0xa0
VOID* OemCodePageData; //0xa8
VOID* UnicodeCaseTableData; //0xb0
ULONG NumberOfProcessors; //0xb8
ULONG NtGlobalFlag; //0xbc
union _LARGE_INTEGER CriticalSectionTimeout; //0xc0
ULONGLONG HeapSegmentReserve; //0xc8
ULONGLONG HeapSegmentCommit; //0xd0
ULONGLONG HeapDeCommitTotalFreeThreshold; //0xd8
ULONGLONG HeapDeCommitFreeBlockThreshold; //0xe0
ULONG NumberOfHeaps; //0xe8
ULONG MaximumNumberOfHeaps; //0xec
VOID** ProcessHeaps; //0xf0
VOID* GdiSharedHandleTable; //0xf8
VOID* ProcessStarterHelper; //0x100
ULONG GdiDCAttributeList; //0x108
UCHAR Padding3[4]; //0x10c
struct _RTL_CRITICAL_SECTION* LoaderLock; //0x110
ULONG OSMajorVersion; //0x118
ULONG OSMinorVersion; //0x11c
USHORT OSBuildNumber; //0x120
USHORT OSCSDVersion; //0x122
ULONG OSPlatformId; //0x124
ULONG ImageSubsystem; //0x128
ULONG ImageSubsystemMajorVersion; //0x12c
ULONG ImageSubsystemMinorVersion; //0x130
UCHAR Padding4[4]; //0x134
ULONGLONG ActiveProcessAffinityMask; //0x138
ULONG GdiHandleBuffer[60]; //0x140
VOID(*PostProcessInitRoutine)
(); //0x230
struct _RTL_BITMAP* TlsExpansionBitmap; //0x238
ULONG TlsExpansionBitmapBits[32]; //0x240
ULONG SessionId; //0x2c0
UCHAR Padding5[4]; //0x2c4
union _ULARGE_INTEGER AppCompatFlags; //0x2c8
union _ULARGE_INTEGER AppCompatFlagsUser; //0x2d0
VOID* pShimData; //0x2d8
VOID* AppCompatInfo; //0x2e0
struct _UNICODE_STRING CSDVersion; //0x2e8
struct _ACTIVATION_CONTEXT_DATA* ActivationContextData; //0x2f8
struct _ASSEMBLY_STORAGE_MAP* ProcessAssemblyStorageMap; //0x300
struct _ACTIVATION_CONTEXT_DATA* SystemDefaultActivationContextData; //0x308
struct _ASSEMBLY_STORAGE_MAP* SystemAssemblyStorageMap; //0x310
ULONGLONG MinimumStackCommit; //0x318
VOID* SparePointers[2]; //0x320
VOID* PatchLoaderData; //0x330
struct _CHPEV2_PROCESS_INFO* ChpeV2ProcessInfo; //0x338
ULONG AppModelFeatureState; //0x340
ULONG SpareUlongs[2]; //0x344
USHORT ActiveCodePage; //0x34c
USHORT OemCodePage; //0x34e
USHORT UseCaseMapping; //0x350
USHORT UnusedNlsField; //0x352
VOID* WerRegistrationData; //0x358
VOID* WerShipAssertPtr; //0x360
VOID* EcCodeBitMap; //0x368
VOID* pImageHeaderHash; //0x370
union
{
ULONG TracingFlags; //0x378
struct
{
ULONG HeapTracingEnabled : 1; //0x378
ULONG CritSecTracingEnabled : 1; //0x378
ULONG LibLoaderTracingEnabled : 1; //0x378
ULONG SpareTracingBits : 29; //0x378
};
};
UCHAR Padding6[4]; //0x37c
ULONGLONG CsrServerReadOnlySharedMemoryBase; //0x380
ULONGLONG TppWorkerpListLock; //0x388
struct _LIST_ENTRY TppWorkerpList; //0x390
VOID* WaitOnAddressHashTable[128]; //0x3a0
VOID* TelemetryCoverageHeader; //0x7a0
ULONG CloudFileFlags; //0x7a8
ULONG CloudFileDiagFlags; //0x7ac
CHAR PlaceholderCompatibilityMode; //0x7b0
CHAR PlaceholderCompatibilityModeReserved[7]; //0x7b1
struct _LEAP_SECOND_DATA* LeapSecondData; //0x7b8
union
{
ULONG LeapSecondFlags; //0x7c0
struct
{
ULONG SixtySecondEnabled : 1; //0x7c0
ULONG Reserved : 31; //0x7c0
};
};
ULONG NtGlobalFlag2; //0x7c4
ULONGLONG ExtendedFeatureDisableMask; //0x7c8
};
static_assert(sizeof(_PEB) == 0x7d0);
struct _CLIENT_ID
{
PVOID UniqueProcess; // 0x0
PVOID UniqueThread; // 0x8
};
static_assert(sizeof(_CLIENT_ID) == 0x10);
struct _GDI_TEB_BATCH
{
ULONG Offset : 31; //0x0
ULONG HasRenderingCommand : 1; //0x0
ULONGLONG HDC; //0x8
ULONG Buffer[310]; //0x10
};
static_assert(sizeof(_GDI_TEB_BATCH) == 0x4E8);
struct _ACTIVATION_CONTEXT_STACK
{
struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame; //0x0
struct _LIST_ENTRY FrameListCache; //0x8
ULONG Flags; //0x18
ULONG NextCookieSequenceNumber; //0x1c
ULONG StackId; //0x20
};
static_assert(sizeof(_ACTIVATION_CONTEXT_STACK) == 0x28);
struct _TEB
{
struct _NT_TIB NtTib; //0x0
VOID* EnvironmentPointer; //0x38
struct _CLIENT_ID ClientId; //0x40
VOID* ActiveRpcHandle; //0x50
VOID* ThreadLocalStoragePointer; //0x58
struct _PEB* ProcessEnvironmentBlock; //0x60
ULONG LastErrorValue; //0x68
ULONG CountOfOwnedCriticalSections; //0x6c
VOID* CsrClientThread; //0x70
VOID* Win32ThreadInfo; //0x78
ULONG User32Reserved[26]; //0x80
ULONG UserReserved[5]; //0xe8
VOID* WOW32Reserved; //0x100
ULONG CurrentLocale; //0x108
ULONG FpSoftwareStatusRegister; //0x10c
VOID* ReservedForDebuggerInstrumentation[16]; //0x110
VOID* SystemReserved1[30]; //0x190
CHAR PlaceholderCompatibilityMode; //0x280
UCHAR PlaceholderHydrationAlwaysExplicit; //0x281
CHAR PlaceholderReserved[10]; //0x282
ULONG ProxiedProcessId; //0x28c
struct _ACTIVATION_CONTEXT_STACK _ActivationStack; //0x290
UCHAR WorkingOnBehalfTicket[8]; //0x2b8
LONG ExceptionCode; //0x2c0
UCHAR Padding0[4]; //0x2c4
struct _ACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; //0x2c8
ULONGLONG InstrumentationCallbackSp; //0x2d0
ULONGLONG InstrumentationCallbackPreviousPc; //0x2d8
ULONGLONG InstrumentationCallbackPreviousSp; //0x2e0
ULONG TxFsContext; //0x2e8
UCHAR InstrumentationCallbackDisabled; //0x2ec
UCHAR UnalignedLoadStoreExceptions; //0x2ed
UCHAR Padding1[2]; //0x2ee
struct _GDI_TEB_BATCH GdiTebBatch; //0x2f0
struct _CLIENT_ID RealClientId; //0x7d8
VOID* GdiCachedProcessHandle; //0x7e8
ULONG GdiClientPID; //0x7f0
ULONG GdiClientTID; //0x7f4
VOID* GdiThreadLocalInfo; //0x7f8
ULONGLONG Win32ClientInfo[62]; //0x800
VOID* glDispatchTable[233]; //0x9f0
ULONGLONG glReserved1[29]; //0x1138
VOID* glReserved2; //0x1220
VOID* glSectionInfo; //0x1228
VOID* glSection; //0x1230
VOID* glTable; //0x1238
VOID* glCurrentRC; //0x1240
VOID* glContext; //0x1248
ULONG LastStatusValue; //0x1250
UCHAR Padding2[4]; //0x1254
struct _UNICODE_STRING StaticUnicodeString; //0x1258
WCHAR StaticUnicodeBuffer[261]; //0x1268
UCHAR Padding3[6]; //0x1472
VOID* DeallocationStack; //0x1478
VOID* TlsSlots[64]; //0x1480
struct _LIST_ENTRY TlsLinks; //0x1680
VOID* Vdm; //0x1690
VOID* ReservedForNtRpc; //0x1698
VOID* DbgSsReserved[2]; //0x16a0
ULONG HardErrorMode; //0x16b0
UCHAR Padding4[4]; //0x16b4
VOID* Instrumentation[11]; //0x16b8
struct _GUID ActivityId; //0x1710
VOID* SubProcessTag; //0x1720
VOID* PerflibData; //0x1728
VOID* EtwTraceData; //0x1730
VOID* WinSockData; //0x1738
ULONG GdiBatchCount; //0x1740
union
{
struct _PROCESSOR_NUMBER CurrentIdealProcessor; //0x1744
ULONG IdealProcessorValue; //0x1744
struct
{
UCHAR ReservedPad0; //0x1744
UCHAR ReservedPad1; //0x1745
UCHAR ReservedPad2; //0x1746
UCHAR IdealProcessor; //0x1747
};
};
ULONG GuaranteedStackBytes; //0x1748
UCHAR Padding5[4]; //0x174c
VOID* ReservedForPerf; //0x1750
VOID* ReservedForOle; //0x1758
ULONG WaitingOnLoaderLock; //0x1760
UCHAR Padding6[4]; //0x1764
VOID* SavedPriorityState; //0x1768
ULONGLONG ReservedForCodeCoverage; //0x1770
VOID* ThreadPoolData; //0x1778
VOID** TlsExpansionSlots; //0x1780
struct _CHPEV2_CPUAREA_INFO* ChpeV2CpuAreaInfo; //0x1788
VOID* Unused; //0x1790
ULONG MuiGeneration; //0x1798
ULONG IsImpersonating; //0x179c
VOID* NlsCache; //0x17a0
VOID* pShimData; //0x17a8
ULONG HeapData; //0x17b0
UCHAR Padding7[4]; //0x17b4
VOID* CurrentTransactionHandle; //0x17b8
struct _TEB_ACTIVE_FRAME* ActiveFrame; //0x17c0
VOID* FlsData; //0x17c8
VOID* PreferredLanguages; //0x17d0
VOID* UserPrefLanguages; //0x17d8
VOID* MergedPrefLanguages; //0x17e0
ULONG MuiImpersonation; //0x17e8
union
{
volatile USHORT CrossTebFlags; //0x17ec
USHORT SpareCrossTebBits : 16; //0x17ec
};
union
{
USHORT SameTebFlags; //0x17ee
struct
{
USHORT SafeThunkCall : 1; //0x17ee
USHORT InDebugPrint : 1; //0x17ee
USHORT HasFiberData : 1; //0x17ee
USHORT SkipThreadAttach : 1; //0x17ee
USHORT WerInShipAssertCode : 1; //0x17ee
USHORT RanProcessInit : 1; //0x17ee
USHORT ClonedThread : 1; //0x17ee
USHORT SuppressDebugMsg : 1; //0x17ee
USHORT DisableUserStackWalk : 1; //0x17ee
USHORT RtlExceptionAttached : 1; //0x17ee
USHORT InitialThread : 1; //0x17ee
USHORT SessionAware : 1; //0x17ee
USHORT LoadOwner : 1; //0x17ee
USHORT LoaderWorker : 1; //0x17ee
USHORT SkipLoaderInit : 1; //0x17ee
USHORT SkipFileAPIBrokering : 1; //0x17ee
};
};
VOID* TxnScopeEnterCallback; //0x17f0
VOID* TxnScopeExitCallback; //0x17f8
VOID* TxnScopeContext; //0x1800
ULONG LockCount; //0x1808
LONG WowTebOffset; //0x180c
VOID* ResourceRetValue; //0x1810
VOID* ReservedForWdf; //0x1818
ULONGLONG ReservedForCrt; //0x1820
struct _GUID EffectiveContainerId; //0x1828
ULONGLONG LastSleepCounter; //0x1838
ULONG SpinCallCount; //0x1840
UCHAR Padding8[4]; //0x1844
ULONGLONG ExtendedFeatureDisableMask; //0x1848
};
static_assert(sizeof(_TEB) == 0x1850);
#pragma endregion