We rise from the ashes

This commit is contained in:
CallowBlack 2022-05-17 03:13:41 +03:00
parent 9ed47e90f6
commit 05d87c4a2f
827 changed files with 165281 additions and 8035 deletions

4
.gitignore vendored
View File

@ -360,4 +360,6 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd
enc_temp_folder/

21
.gitmodules vendored Normal file
View File

@ -0,0 +1,21 @@
[submodule "cheat-base/vendor/simpleIni"]
path = cheat-base/vendor/simpleIni
url = https://github.com/brofield/simpleini.git
[submodule "cheat-base/vendor/fmt"]
path = cheat-base/vendor/fmt
url = https://github.com/fmtlib/fmt.git
[submodule "cheat-base/vendor/magic_enum"]
path = cheat-base/vendor/magic_enum
url = https://github.com/Neargye/magic_enum.git
[submodule "cheat-library/vendor/protobuf"]
path = cheat-library/vendor/protobuf
url = https://github.com/protocolbuffers/protobuf.git
[submodule "cheat-library/vendor/json"]
path = cheat-base/vendor/json
url = https://github.com/nlohmann/json.git
[submodule "cheat-base/vendor/stb"]
path = cheat-base/vendor/stb
url = https://github.com/nothings/stb.git
[submodule "cheat-base/vendor/imgui"]
path = cheat-base/vendor/imgui
url = https://github.com/CallowBlack/imgui-brightness-fix.git

137
README.md Normal file
View File

@ -0,0 +1,137 @@
<h1 align="center">Akebi GC</h1>
The great software for some game that exploiting anime girls (and boys).
<hr>
<h1 align="center">Getting Started</h1>
### Building from source
It is reccomended to use [Visual Studio 2022.](https://visualstudio.microsoft.com/)
As well as setting up **`cheat-library`** as startup project.
**The following is a recommended procedure, but others may be used.**
1. Clone repository with `git clone --recurse-submodules https://github.com/Akebi-Group/Akebi-GC.git`
1. Open `Akebi-GC/akebi-gc.sln`
1. Build solution `akebi-gc.sln`.
### Release
1. Head over to the releases page
1. Download the latest binaries
### Usage
(1-2 are optional if you didn't build from source)
1. Open `/bin`
1. Open Compiled version (debug, release)
1. Insure that `CLibrary.dll` is in the same folder that `injector.exe`.
1. Run `injector.exe`.
<h1 align="center">Features</h1>
#### General
- Protection Bypass
- In-Game GUI
- Hotkeys
#### Player
- God Mode
- Unlimited Stamina
- Dumb Enemies (Enemies don't attack)
- Player
- Multiply Attacks
- No Cooldown Skill/Ultimate
- No Cooldown Sprint
#### World
- Auto Loot
- Auto Talk
- Killaura
- Auto Tree Farm
- Mob Vacuum
- Auto Fish
#### Teleport
- Chest/Oculi Teleport (Teleports to nearest)
- Map Teleport (Teleport to mark on map)
#### Visuals
- ESP
- Interactive Map
- Elemental Sight
#### Debugging
- Entity List
- Position Info
- FPS Graph
- Packet Sniffer
<h1 align="center">Demo</h1>
<details>
<summary>Map Teleportation</summary>
<img src="https://github.com/CallowBlack/gif-demos/blob/main/genshin-cheat/map-teleport-demo.gif"/>
</details>
<details>
<summary>Noclip</summary>
<img src="https://github.com/CallowBlack/gif-demos/blob/main/genshin-cheat/noclip-demo.gif"/>
</details>
<details>
<summary>TP to Oculi</summary>
<img src="https://github.com/CallowBlack/gif-demos/blob/main/genshin-cheat/oculi-teleport-demo.gif"/>
</details>
<details>
<summary>TP to Chests</summary>
<img src="https://github.com/CallowBlack/gif-demos/blob/main/genshin-cheat/chest-teleport-demo.gif"/>
</details>
<details>
<summary>Rapid Fire</summary>
<img src="https://github.com/CallowBlack/gif-demos/blob/main/genshin-cheat/rapid-fire-demo.gif"/>
</details>
<details>
<summary>Auto Talk</summary>
<img src="https://github.com/CallowBlack/gif-demos/blob/main/genshin-cheat/auto-talk-demo.gif"/>
</details>
<h1 align="center">Roadmap</h1>
- [ ] Cutscene Skipping
- [ ] Create database for chests, oculi, etc.
<h1 align="center">Contributing</h1>
## Adding a feature
1. Fork the Project
1. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
1. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
1. Push to the Branch (`git push origin feature/AmazingFeature`)
1. Open a Pull Request
## Suggestions
Open an issue with the title of the suggesstion you want to make.
In the description, make sure it is descriptive enough so our devs can understand what you want and how you want it.
## Bugs
Welcome to the short explanation for bug reporting, as well as the bug report template.
1. Find a bug and write down what happened, as well as your first thoughts on what you think caused it.
2. Try to reproduce the bug. For this you need to understand what actually happened, leading up to the bug and when the actual bug happened. To make sure you get all this information correctly taking various forms of documentations, such as video, screenshots etc is essential. These steps makes it a lot easier to try and figure out what actually happened. Try to replicate the scenario where the bug appeared, as close to the original as possible. What we would recommend for this step is using the bug reporting template which can be found on page 2 and simply adding the information you have / find in there.
3. can it be reproduced? Yes or no. If yes: Explain in as much detail as possible what happens when the bug occurs and why it occurs. Try and explain it as cleanly and as concise as possible to make sure that the coders dont have to read an essay to understand what could be a simple bug with a simple fix. For this, remember that information is very subjective so it is much better to over communicate than to risk confusion. If no: Try to provide as much information about the bug as possible, so that the testers will be able to replicate the scenario in which the bug occurred more easily so we can try to reproduce the bug.
4. Tell us which version you are using. Otherwise we would be getting bug reports on the same issue, that has been infact fixed in the latest commits. copy the SHA / Version Number of the latest commit when you built the mod. For example: `bd17a00ec388f3b93624280cde9e1c66e740edf9` / Release 0.7
Notes: Please remember to always record your testing sessions on your local hard drive and then upload them unlisted to youtube to conserve memory space on your computer and to give us easy access to your replays. This is to ensure that the optimal amount of documentation is available for the bug testers and coders to use as a guideline for either replicating scenarios, reproducing bugs or fixing them.
TL:DR Record all your stuff while playing the mod and report any bugs to the issues section of this repository.
### Bug reporting template
Title: e.g. “Instantly kill enemy with Shackles“
Description: “Game crashed if x, y, z“
-- Footer --
Date Occured: 5 / 3 / 2022
Is it reproducible: Yes / Occasionally / No
Latest Commit used: `bd17a00ec388f3b93624280cde9e1c66e740edf9`
Release Version: 0.7

65
akebi-gc.sln Normal file
View File

@ -0,0 +1,65 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "injector", "injector\injector.vcxproj", "{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cheat-base", "cheat-base\cheat-base.vcxproj", "{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cheat-library", "cheat-library\cheat-library.vcxproj", "{CE178784-CB96-45CA-AE16-FC0DA1126970}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release_WithScanner|x64 = Release_WithScanner|x64
Release_WithScanner|x86 = Release_WithScanner|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x64.ActiveCfg = Debug|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x64.Build.0 = Debug|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x86.ActiveCfg = Debug|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Debug|x86.Build.0 = Debug|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release_WithScanner|x64.ActiveCfg = Release_WS|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release_WithScanner|x64.Build.0 = Release_WS|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release_WithScanner|x86.ActiveCfg = Release_WithScanner|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release_WithScanner|x86.Build.0 = Release_WithScanner|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x64.ActiveCfg = Release|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x64.Build.0 = Release|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x86.ActiveCfg = Release|x64
{F578B30C-8DE6-4741-99E4-1D30D2ACDAC4}.Release|x86.Build.0 = Release|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Debug|x64.ActiveCfg = Debug|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Debug|x64.Build.0 = Debug|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Debug|x86.ActiveCfg = Debug|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Debug|x86.Build.0 = Debug|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release_WithScanner|x64.ActiveCfg = Release_WS|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release_WithScanner|x64.Build.0 = Release_WS|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release_WithScanner|x86.ActiveCfg = Release_WithScanner|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release_WithScanner|x86.Build.0 = Release_WithScanner|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release|x64.ActiveCfg = Release|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release|x64.Build.0 = Release|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release|x86.ActiveCfg = Release|x64
{ADB35022-823B-4DC0-B495-3EFEFBD3A82F}.Release|x86.Build.0 = Release|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Debug|x64.ActiveCfg = Debug|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Debug|x64.Build.0 = Debug|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Debug|x86.ActiveCfg = Debug|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Debug|x86.Build.0 = Debug|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release_WithScanner|x64.ActiveCfg = Release_WS|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release_WithScanner|x64.Build.0 = Release_WS|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release_WithScanner|x86.ActiveCfg = Release_WithScanner|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release_WithScanner|x86.Build.0 = Release_WithScanner|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release|x64.ActiveCfg = Release|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release|x64.Build.0 = Release|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release|x86.ActiveCfg = Release|x64
{CE178784-CB96-45CA-AE16-FC0DA1126970}.Release|x86.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0F485A89-A340-4742-97E7-923E14A929A1}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,282 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release_WS|x64">
<Configuration>Release_WS</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{adb35022-823b-4dc0-b495-3efefbd3a82f}</ProjectGuid>
<RootNamespace>cheat-base</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>cheat-base</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)bin\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)bin\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)bin\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_AMD64_;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)framework\;$(ProjectDir)src\;$(ProjectDir)vendor\detours\;$(ProjectDir)vendor\fmt\include\;$(ProjectDir)vendor\imgui\;$(ProjectDir)vendor\magic_enum\include\;$(ProjectDir)vendor\simpleIni\;$(ProjectDir)vendor\json\single_include\;$(ProjectDir)vendor\imgui-notify-v2\;$(ProjectDir)vendor\stb\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<Lib>
<AdditionalDependencies>detours-x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>$(ProjectDir)/vendor/detours/;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_AMD64_;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)framework\;$(ProjectDir)src\;$(ProjectDir)vendor\detours\;$(ProjectDir)vendor\fmt\include\;$(ProjectDir)vendor\imgui\;$(ProjectDir)vendor\magic_enum\include\;$(ProjectDir)vendor\simpleIni\;$(ProjectDir)vendor\json\single_include\;$(ProjectDir)vendor\imgui-notify-v2\;$(ProjectDir)vendor\stb\</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<Lib>
<AdditionalDependencies>detours-x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>$(ProjectDir)/vendor/detours/;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_AMD64_;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)framework\;$(ProjectDir)src\;$(ProjectDir)vendor\detours\;$(ProjectDir)vendor\fmt\include\;$(ProjectDir)vendor\imgui\;$(ProjectDir)vendor\magic_enum\include\;$(ProjectDir)vendor\simpleIni\;$(ProjectDir)vendor\json\single_include\;$(ProjectDir)vendor\imgui-notify-v2\;$(ProjectDir)vendor\stb\</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<Lib>
<AdditionalDependencies>detours-x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>$(ProjectDir)/vendor/detours/;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="src\cheat-base\config\converters.h" />
<ClInclude Include="src\cheat-base\config\Field.h" />
<ClInclude Include="src\cheat-base\config\fields.h" />
<ClInclude Include="src\cheat-base\config\FieldSerialize.h" />
<ClInclude Include="src\cheat-base\config\fields\Enum.h" />
<ClInclude Include="src\cheat-base\config\fields\Toggle.h" />
<ClInclude Include="src\cheat-base\config\internal\FieldBase.h" />
<ClInclude Include="src\cheat-base\config\internal\FieldEntry.h" />
<ClInclude Include="src\cheat-base\config\internal\FieldSerialize.h" />
<ClInclude Include="src\cheat-base\config\Serializable.h" />
<ClInclude Include="src\cheat-base\config\FieldBase.h" />
<ClInclude Include="framework\framework.h" />
<ClInclude Include="framework\pch.h" />
<ClInclude Include="src\cheat-base\config\config.h" />
<ClInclude Include="src\cheat-base\globals.h" />
<ClInclude Include="src\cheat-base\events\event.hpp" />
<ClInclude Include="src\cheat-base\events\handlers\abstracteventhandler.hpp" />
<ClInclude Include="src\cheat-base\events\handlers\eventhandlerptr.h" />
<ClInclude Include="src\cheat-base\events\handlers\functoreventhandler.hpp" />
<ClInclude Include="src\cheat-base\events\handlers\handlercast.hpp" />
<ClInclude Include="src\cheat-base\events\handlers\helpers\innerholder.hpp" />
<ClInclude Include="src\cheat-base\events\handlers\helpers\objectsaver.hpp" />
<ClInclude Include="src\cheat-base\events\handlers\methodeventhandler.hpp" />
<ClInclude Include="src\cheat-base\events\helpers\is_equatable.hpp" />
<ClInclude Include="src\cheat-base\events\joins\abstracteventjoin.h" />
<ClInclude Include="src\cheat-base\events\joins\eventjoinwrapper.h" />
<ClInclude Include="src\cheat-base\events\joins\eventjoinwrapper.hpp" />
<ClInclude Include="src\cheat-base\events\joins\handlereventjoin.h" />
<ClInclude Include="src\cheat-base\events\joins\handlereventjoin.hpp" />
<ClInclude Include="src\cheat-base\ResourceLoader.h" />
<ClInclude Include="src\cheat-base\Hotkey.h" />
<ClInclude Include="src\cheat-base\render\ImageLoader.h" />
<ClInclude Include="src\cheat-base\PatternScanner.h" />
<ClInclude Include="src\cheat-base\cheat\CheatManagerBase.h" />
<ClInclude Include="src\cheat-base\cheat\Feature.h" />
<ClInclude Include="src\cheat-base\cheat\misc\Settings.h" />
<ClInclude Include="src\cheat-base\render\backend\dx11-hook.h" />
<ClInclude Include="src\cheat-base\render\gui-util.h" />
<ClInclude Include="src\cheat-base\render\renderer.h" />
<ClInclude Include="src\cheat-base\HookManager.h" />
<ClInclude Include="src\cheat-base\Patch.h" />
<ClInclude Include="src\cheat-base\thread-safe.h" />
<ClInclude Include="src\cheat-base\util.h" />
<ClInclude Include="src\cheat-base\Logger.h" />
<ClInclude Include="src\cheat-base\PipeTransfer.h" />
<ClInclude Include="vendor\detours\detours.h" />
<ClInclude Include="vendor\detours\detver.h" />
<ClInclude Include="vendor\fmt\include\fmt\args.h" />
<ClInclude Include="vendor\fmt\include\fmt\chrono.h" />
<ClInclude Include="vendor\fmt\include\fmt\color.h" />
<ClInclude Include="vendor\fmt\include\fmt\compile.h" />
<ClInclude Include="vendor\fmt\include\fmt\core.h" />
<ClInclude Include="vendor\fmt\include\fmt\format-inl.h" />
<ClInclude Include="vendor\fmt\include\fmt\format.h" />
<ClInclude Include="vendor\fmt\include\fmt\locale.h" />
<ClInclude Include="vendor\fmt\include\fmt\os.h" />
<ClInclude Include="vendor\fmt\include\fmt\ostream.h" />
<ClInclude Include="vendor\fmt\include\fmt\printf.h" />
<ClInclude Include="vendor\fmt\include\fmt\ranges.h" />
<ClInclude Include="vendor\fmt\include\fmt\xchar.h" />
<ClInclude Include="vendor\imgui-notify-v2\fa_solid_900.h" />
<ClInclude Include="vendor\imgui-notify-v2\font_awesome_5.h" />
<ClInclude Include="vendor\imgui-notify-v2\imgui_notify.h" />
<ClInclude Include="vendor\magic_enum\include\magic_enum.hpp" />
<ClInclude Include="vendor\simpleIni\SimpleIni.h" />
<ClInclude Include="vendor\stb\stb_image.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\cheat-base\config\config.cpp" />
<ClCompile Include="src\cheat-base\globals.cpp" />
<ClCompile Include="src\cheat-base\events\joins\abstracteventjoin.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="src\cheat-base\events\joins\eventjoinwrapper.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="src\cheat-base\ResourceLoader.cpp" />
<ClCompile Include="src\cheat-base\Hotkey.cpp" />
<ClCompile Include="src\cheat-base\render\ImageLoader.cpp" />
<ClCompile Include="src\cheat-base\PatternScanner.cpp" />
<ClCompile Include="src\cheat-base\cheat\CheatManagerBase.cpp" />
<ClCompile Include="src\cheat-base\cheat\misc\Settings.cpp" />
<ClCompile Include="src\cheat-base\render\backend\dx11-hook.cpp" />
<ClCompile Include="src\cheat-base\render\gui-util.cpp" />
<ClCompile Include="src\cheat-base\render\renderer.cpp" />
<ClCompile Include="src\cheat-base\Patch.cpp" />
<ClCompile Include="src\cheat-base\Logger.cpp" />
<ClCompile Include="src\cheat-base\util.cpp" />
<ClCompile Include="framework\pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="src\cheat-base\PipeTransfer.cpp" />
<ClCompile Include="vendor\fmt\src\format.cc">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="vendor\fmt\src\os.cc">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_WS|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,279 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework\framework.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="framework\pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\PipeTransfer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\Logger.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\args.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\chrono.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\color.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\compile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\core.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\format.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\format-inl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\locale.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\os.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\ostream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\printf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\ranges.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\fmt\include\fmt\xchar.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\magic_enum\include\magic_enum.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\simpleIni\SimpleIni.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\detours\detours.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\detours\detver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\HookManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\Patch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\thread-safe.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\render\gui-util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\render\renderer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\render\backend\dx11-hook.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\cheat\CheatManagerBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\cheat\Feature.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\cheat\misc\Settings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\PatternScanner.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\Hotkey.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\stb\stb_image.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\render\ImageLoader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\ResourceLoader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\FieldBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\Serializable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\fields.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\FieldSerialize.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\internal\FieldEntry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\internal\FieldSerialize.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\Field.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\converters.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\fields\Enum.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\internal\FieldBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\imgui-notify-v2\fa_solid_900.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\imgui-notify-v2\font_awesome_5.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vendor\imgui-notify-v2\imgui_notify.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\config\fields\Toggle.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\handlers\helpers\innerholder.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\handlers\helpers\objectsaver.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\handlers\abstracteventhandler.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\handlers\eventhandlerptr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\handlers\functoreventhandler.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\handlers\handlercast.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\handlers\methodeventhandler.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\helpers\is_equatable.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\joins\abstracteventjoin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\joins\eventjoinwrapper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\joins\eventjoinwrapper.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\joins\handlereventjoin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\joins\handlereventjoin.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\events\event.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cheat-base\globals.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\cheat-base\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="framework\pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\PipeTransfer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\Logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\Patch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\render\gui-util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\render\renderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\render\backend\dx11-hook.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\cheat\CheatManagerBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vendor\fmt\src\os.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vendor\fmt\src\format.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\cheat\misc\Settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\PatternScanner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\Hotkey.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\render\ImageLoader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\ResourceLoader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\config\config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\events\joins\abstracteventjoin.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\events\joins\eventjoinwrapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cheat-base\globals.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers

View File

@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@ -0,0 +1,47 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#include <magic_enum.hpp>
#include <nlohmann/json.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <unordered_set>
#include <queue>
#include <sstream>
#include <mutex>
#include <optional>
#include <Windows.h>
#include <imgui.h>
#include <imconfig.h>
#include <backends/imgui_impl_dx11.h>
#include <imgui_notify.h>
#include <SimpleIni.h>
#include <fmt/format.h>
#include <detours.h>
#include <cheat-base/Logger.h>
#include <cheat-base/events/event.hpp>
#include <cheat-base/events/handlers/methodeventhandler.hpp>
#include <cheat-base/events/handlers/functoreventhandler.hpp>
#include <cheat-base/events/joins/handlereventjoin.hpp>
#include <cheat-base/events/joins/eventjoinwrapper.hpp>
#include <cheat-base/globals.h>
#endif //PCH_H

View File

@ -0,0 +1,78 @@
#pragma once
#include <map>
#include <detours.h>
#define CALL_ORIGIN(function, ...) \
HookManager::call(function, __func__, __VA_ARGS__)
class HookManager
{
public:
template <typename Fn>
static void install(Fn func, Fn handler)
{
enable(func, handler);
holderMap[reinterpret_cast<void*>(handler)] = reinterpret_cast<void*>(func);
}
template <typename Fn>
[[nodiscard]] static Fn getOrigin(Fn handler, const char* callerName = nullptr) noexcept
{
if (holderMap.count(reinterpret_cast<void*>(handler)) == 0) {
LOG_WARNING("Origin not found for handler: %s. Maybe racing bug.", callerName == nullptr ? "<Unknown>" : callerName);
return nullptr;
}
return reinterpret_cast<Fn>(holderMap[reinterpret_cast<void*>(handler)]);
}
template <typename Fn>
[[nodiscard]] static void detach(Fn handler) noexcept
{
disable(handler);
holderMap.erase(reinterpret_cast<void*>(handler));
}
template <typename RType, typename... Params>
[[nodiscard]] static RType call(RType(*handler)(Params...), const char* callerName = nullptr, Params... params)
{
auto origin = getOrigin(handler, callerName);
if (origin != nullptr)
return origin(params...);
return RType();
}
static void detachAll() noexcept
{
for (const auto &[key, value] : holderMap)
{
disable(key);
}
holderMap.clear();
}
private:
inline static std::map<void*, void*> holderMap{};
template <typename Fn>
static void disable(Fn handler)
{
Fn origin = getOrigin(handler);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)origin, handler);
DetourTransactionCommit();
}
template <typename Fn>
static void enable(Fn& func, Fn handler)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)func, handler);
DetourTransactionCommit();
}
};

View File

@ -0,0 +1,395 @@
#include <pch.h>
#include "Hotkey.h"
#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
static ImGuiKey LegacyToInput(short key)
{
switch (key)
{
case VK_TAB: return ImGuiKey_Tab;
case VK_LEFT: return ImGuiKey_LeftArrow;
case VK_RIGHT: return ImGuiKey_RightArrow;
case VK_UP: return ImGuiKey_UpArrow;
case VK_DOWN: return ImGuiKey_DownArrow;
case VK_PRIOR: return ImGuiKey_PageUp;
case VK_NEXT: return ImGuiKey_PageDown;
case VK_HOME: return ImGuiKey_Home;
case VK_END: return ImGuiKey_End;
case VK_INSERT: return ImGuiKey_Insert;
case VK_DELETE: return ImGuiKey_Delete;
case VK_BACK: return ImGuiKey_Backspace;
case VK_SPACE: return ImGuiKey_Space;
case VK_RETURN: return ImGuiKey_Enter;
case VK_ESCAPE: return ImGuiKey_Escape;
case VK_OEM_7: return ImGuiKey_Apostrophe;
case VK_OEM_COMMA: return ImGuiKey_Comma;
case VK_OEM_MINUS: return ImGuiKey_Minus;
case VK_OEM_PERIOD: return ImGuiKey_Period;
case VK_OEM_2: return ImGuiKey_Slash;
case VK_OEM_1: return ImGuiKey_Semicolon;
case VK_OEM_PLUS: return ImGuiKey_Equal;
case VK_OEM_4: return ImGuiKey_LeftBracket;
case VK_OEM_5: return ImGuiKey_Backslash;
case VK_OEM_6: return ImGuiKey_RightBracket;
case VK_OEM_3: return ImGuiKey_GraveAccent;
case VK_CAPITAL: return ImGuiKey_CapsLock;
case VK_SCROLL: return ImGuiKey_ScrollLock;
case VK_NUMLOCK: return ImGuiKey_NumLock;
case VK_SNAPSHOT: return ImGuiKey_PrintScreen;
case VK_PAUSE: return ImGuiKey_Pause;
case VK_NUMPAD0: return ImGuiKey_Keypad0;
case VK_NUMPAD1: return ImGuiKey_Keypad1;
case VK_NUMPAD2: return ImGuiKey_Keypad2;
case VK_NUMPAD3: return ImGuiKey_Keypad3;
case VK_NUMPAD4: return ImGuiKey_Keypad4;
case VK_NUMPAD5: return ImGuiKey_Keypad5;
case VK_NUMPAD6: return ImGuiKey_Keypad6;
case VK_NUMPAD7: return ImGuiKey_Keypad7;
case VK_NUMPAD8: return ImGuiKey_Keypad8;
case VK_NUMPAD9: return ImGuiKey_Keypad9;
case VK_DECIMAL: return ImGuiKey_KeypadDecimal;
case VK_DIVIDE: return ImGuiKey_KeypadDivide;
case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;
case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;
case VK_ADD: return ImGuiKey_KeypadAdd;
case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;
case VK_LSHIFT: return ImGuiKey_LeftShift;
case VK_LCONTROL: return ImGuiKey_LeftCtrl;
case VK_LMENU: return ImGuiKey_LeftAlt;
case VK_LWIN: return ImGuiKey_LeftSuper;
case VK_RSHIFT: return ImGuiKey_RightShift;
case VK_RCONTROL: return ImGuiKey_RightCtrl;
case VK_RMENU: return ImGuiKey_RightAlt;
case VK_RWIN: return ImGuiKey_RightSuper;
case VK_APPS: return ImGuiKey_Menu;
case '0': return ImGuiKey_0;
case '1': return ImGuiKey_1;
case '2': return ImGuiKey_2;
case '3': return ImGuiKey_3;
case '4': return ImGuiKey_4;
case '5': return ImGuiKey_5;
case '6': return ImGuiKey_6;
case '7': return ImGuiKey_7;
case '8': return ImGuiKey_8;
case '9': return ImGuiKey_9;
case 'A': return ImGuiKey_A;
case 'B': return ImGuiKey_B;
case 'C': return ImGuiKey_C;
case 'D': return ImGuiKey_D;
case 'E': return ImGuiKey_E;
case 'F': return ImGuiKey_F;
case 'G': return ImGuiKey_G;
case 'H': return ImGuiKey_H;
case 'I': return ImGuiKey_I;
case 'J': return ImGuiKey_J;
case 'K': return ImGuiKey_K;
case 'L': return ImGuiKey_L;
case 'M': return ImGuiKey_M;
case 'N': return ImGuiKey_N;
case 'O': return ImGuiKey_O;
case 'P': return ImGuiKey_P;
case 'Q': return ImGuiKey_Q;
case 'R': return ImGuiKey_R;
case 'S': return ImGuiKey_S;
case 'T': return ImGuiKey_T;
case 'U': return ImGuiKey_U;
case 'V': return ImGuiKey_V;
case 'W': return ImGuiKey_W;
case 'X': return ImGuiKey_X;
case 'Y': return ImGuiKey_Y;
case 'Z': return ImGuiKey_Z;
case VK_F1: return ImGuiKey_F1;
case VK_F2: return ImGuiKey_F2;
case VK_F3: return ImGuiKey_F3;
case VK_F4: return ImGuiKey_F4;
case VK_F5: return ImGuiKey_F5;
case VK_F6: return ImGuiKey_F6;
case VK_F7: return ImGuiKey_F7;
case VK_F8: return ImGuiKey_F8;
case VK_F9: return ImGuiKey_F9;
case VK_F10: return ImGuiKey_F10;
case VK_F11: return ImGuiKey_F11;
case VK_F12: return ImGuiKey_F12;
case VK_LBUTTON: return ImGuiMouseButton_Left;
case VK_RBUTTON: return ImGuiMouseButton_Right;
case VK_MBUTTON: return ImGuiMouseButton_Middle;
case VK_XBUTTON1: return 3;
case VK_XBUTTON2: return 4;
default: return ImGuiKey_None;
}
}
static short InputToLegacy(ImGuiKey inputkey)
{
auto& io = ImGui::GetIO();
if (inputkey > 4)
return io.KeyMap[inputkey];
switch (inputkey)
{
case ImGuiMouseButton_Left:
return VK_LBUTTON;
case ImGuiMouseButton_Right:
return VK_RBUTTON;
case ImGuiMouseButton_Middle:
return VK_MBUTTON;
case 3:
return VK_XBUTTON1;
case 4:
return VK_XBUTTON2;
}
LOG_CRIT("Failed to find legacy input");
return -1;
}
static bool IsKeyDown(ImGuiKey key)
{
if (key > 6)
return ImGui::IsKeyDown(key);
switch (key)
{
case 1:
case 2:
return ImGui::IsMouseDown(key - 1);
case 4:
case 5:
case 6:
return ImGui::IsMouseDown(key - 2);
}
return false;
}
static bool IsKeyReleased(ImGuiKey key)
{
if (key > 6)
return ImGui::IsKeyReleased(key);
switch (key)
{
case 1:
case 2:
return ImGui::IsMouseReleased(key - 1);
case 4:
case 5:
case 6:
return ImGui::IsMouseReleased(key - 2);
}
return false;
}
void FixModKey(short& legacyKey)
{
// Can cause incorrect input when both keys pressed, need to fix!
switch (legacyKey)
{
case VK_CONTROL:
{
if (IsKeyDown(ImGuiKey_LeftCtrl))
legacyKey = VK_LCONTROL;
else if (IsKeyDown(ImGuiKey_RightCtrl))
legacyKey = VK_RCONTROL;
return;
}
case VK_SHIFT:
{
if (IsKeyDown(ImGuiKey_LeftShift))
legacyKey = VK_LSHIFT;
else if (IsKeyDown(ImGuiKey_RightShift))
legacyKey = VK_RSHIFT;
return;
}
}
}
Hotkey::Hotkey() : PressedEvent(m_PressedEvent), m_PressedEvent()
{
events::KeyUpEvent += MY_METHOD_HANDLER(Hotkey::OnKeyUp);
}
Hotkey::Hotkey(std::vector<short> legacyKeys) : Hotkey()
{
for (short legacyKey : legacyKeys)
{
this->m_Keys.insert(legacyKey);
}
}
Hotkey::Hotkey(short key) : Hotkey()
{
this->m_Keys.insert(key);
}
Hotkey::Hotkey(const Hotkey& other) : Hotkey()
{
m_Keys = {other.m_Keys};
}
Hotkey::~Hotkey()
{
events::KeyUpEvent -= MY_METHOD_HANDLER(Hotkey::OnKeyUp);
}
Hotkey& Hotkey::operator=(Hotkey&& hotkey) noexcept
{
m_Keys = std::move(hotkey.m_Keys);
return *this;
}
Hotkey& Hotkey::operator=(Hotkey& hotkey) noexcept
{
m_Keys = hotkey.m_Keys;
return *this;
}
bool Hotkey::operator-(const Hotkey& c2)
{
for (short key : m_Keys)
{
if (c2.m_Keys.count(key) == 0)
return true;
}
return false;
}
bool Hotkey::operator!=(const Hotkey& c2) const
{
return !(*this == c2);
}
bool Hotkey::operator==(const Hotkey& c2) const
{
return m_Keys == c2.m_Keys;
}
std::string GetKeyName(short key)
{
if (key > 5)
return ImGui::GetKeyName(key);
switch (key)
{
case ImGuiMouseButton_Left:
return "LMB";
case ImGuiMouseButton_Right:
return "RMB";
case ImGuiMouseButton_Middle:
return "MMB";
case 3:
return "Mouse X1";
case 4:
return "Mouse X2";
}
return "Unknown";
}
Hotkey::operator std::string() const
{
if (IsEmpty())
return "None";
std::stringstream hotkeyNameStream;
for (auto it = m_Keys.begin(); it != m_Keys.end(); it++)
{
if (it != m_Keys.begin())
hotkeyNameStream << " + ";
hotkeyNameStream << GetKeyName(LegacyToInput(*it));
}
return hotkeyNameStream.str();
}
bool Hotkey::IsPressed() const
{
for (short key : m_Keys)
{
if (!IsKeyDown(key))
return false;
}
return true;
}
bool Hotkey::IsPressed(short legacyKey) const
{
FixModKey(legacyKey);
if (m_Keys.count(legacyKey) == 0)
return false;
std::unordered_set<short> keysClone = m_Keys;
keysClone.erase(legacyKey);
for (short key : keysClone)
{
bool result = IsKeyDown(key);
if (!result)
return false;
}
return true;
}
bool Hotkey::IsReleased() const
{
bool released = false;
for (short key : m_Keys)
{
if (IsKeyReleased(key))
{
released = true;
continue;
}
if (!IsKeyDown(key))
return false;
}
return released;
}
bool Hotkey::IsEmpty() const
{
return m_Keys.size() == 0;
}
std::vector<short> Hotkey::GetKeys() const
{
return std::vector<short>(m_Keys.begin(), m_Keys.end());
}
Hotkey Hotkey::GetPressedHotkey()
{
Hotkey hotkey{};
auto& io = ImGui::GetIO();
for (ImGuiKey i = ImGuiKey_NamedKey_BEGIN; i < ImGuiKey_NamedKey_END - 4; i++)
{
bool isKeyDown = io.KeysDown[i];
if (isKeyDown)
hotkey.m_Keys.insert(InputToLegacy(i));
}
for (ImGuiKey i = 0; i < ImGuiMouseButton_COUNT; i++)
{
bool isMouseButtonDown = io.MouseDown[i];
if (isMouseButtonDown)
hotkey.m_Keys.insert(InputToLegacy(i));
}
return hotkey;
}
void Hotkey::OnKeyUp(short key, bool& canceled)
{
if (IsPressed(key))
m_PressedEvent();
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <string>
#include <unordered_set>
#include <cheat-base/events/event.hpp>
class Hotkey
{
public:
Hotkey();
Hotkey(const Hotkey& other);
Hotkey(short key);
Hotkey(std::vector<short> keys);
~Hotkey();
Hotkey& operator=(Hotkey& hotkey) noexcept;
Hotkey& operator=(Hotkey&& hotkey) noexcept;
bool operator== (const Hotkey& c2) const;
bool operator!= (const Hotkey& c2) const;
bool operator-(const Hotkey& c2);
bool IsPressed() const;
bool IsPressed(short keyDown) const;
bool IsReleased() const;
bool IsEmpty() const;
std::vector<short> GetKeys() const;
operator std::string() const;
static Hotkey GetPressedHotkey();
IEvent<>& PressedEvent;
private:
TEvent<> m_PressedEvent;
std::unordered_set<short> m_Keys;
void OnKeyUp(short key, bool& canceled);
};

View File

@ -0,0 +1,143 @@
#include <pch.h>
#include "Logger.h"
#include <Windows.h>
#include <iostream>
#include <chrono>
#include <cstdarg>
#include <fstream>
#include <filesystem>
#include <cheat-base/util.h>
Logger::Level Logger::s_FileLogLevel = Logger::Level::None;
Logger::Level Logger::s_ConsoleLogLevel = Logger::Level::None;
std::string Logger::directory = "";
std::string Logger::logfilepath = "";
std::mutex Logger::_mutex{};
void Logger::SetLevel(Level level, LoggerType type)
{
switch (type)
{
case Logger::LoggerType::Any:
s_FileLogLevel = level;
s_ConsoleLogLevel = level;
break;
case Logger::LoggerType::ConsoleLogger:
s_ConsoleLogLevel = level;
break;
case Logger::LoggerType::FileLogger:
s_FileLogLevel = level;
break;
default:
break;
}
}
Logger::Level Logger::GetLevel(Logger::LoggerType type)
{
switch (type)
{
case Logger::LoggerType::Any:
return s_FileLogLevel < s_ConsoleLogLevel ? s_FileLogLevel : s_ConsoleLogLevel;
case Logger::LoggerType::ConsoleLogger:
return s_ConsoleLogLevel;
case Logger::LoggerType::FileLogger:
return s_FileLogLevel;
default:
return Logger::Level::None;
}
}
void LogToFile(std::string& filepath, std::string& msg)
{
std::ofstream myfile;
myfile.open(filepath, std::ios::out | std::ios::app | std::ios::binary);
myfile << msg << std::endl;
myfile.close();
}
struct Prefix
{
char color;
const char* text;
};
Prefix GetLevelPrefix(Logger::Level level)
{
switch (level)
{
case Logger::Level::Critical:
return { 0x04, "Critical" };
case Logger::Level::Error:
return { 0x0C, "Error" };
case Logger::Level::Warning:
return { 0x06, "Warning" };
case Logger::Level::Info:
return { 0x02, "Info" };
case Logger::Level::Debug:
return { 0x0B, "Debug" };
case Logger::Level::Trace:
return { 0x08, "Trace" };
default:
return { 0x00, "" };
}
}
void Logger::Log(Logger::Level logLevel, const char* filepath, int line, const char* fmt, ...)
{
if (Logger::s_ConsoleLogLevel == Logger::Level::None && Logger::s_FileLogLevel == Logger::Level::None)
return;
auto filename = std::filesystem::path(filepath).filename().string();
auto prefix = GetLevelPrefix(logLevel);
char buffer[1024];
va_list args;
va_start(args, fmt);
vsprintf_s(buffer, fmt, args);
va_end(args);
if (Logger::s_ConsoleLogLevel != Logger::Level::None && Logger::s_ConsoleLogLevel >= logLevel)
{
const std::lock_guard<std::mutex> lock(_mutex);
auto logLineConsole = util::string_format("[%s:%d] %s", filename.c_str(), line, buffer);
std::cout << "[";
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, prefix.color);
std::cout << prefix.text;
SetConsoleTextAttribute(hConsole, 15);
std::cout << "] " << logLineConsole << std::endl;
}
if (Logger::s_FileLogLevel != Logger::Level::None && Logger::s_FileLogLevel >= logLevel)
{
const std::lock_guard<std::mutex> lock(_mutex);
auto rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
struct tm gmtm;
gmtime_s(&gmtm, &rawTime);
auto logLineFile = util::string_format("[%02d:%02d:%02d] [%s] [%s:%d] %s", gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec,
prefix.text, filename.c_str(), line, buffer);
LogToFile(Logger::logfilepath, logLineFile);
}
}
void Logger::PrepareFileLogging(std::string directory)
{
auto rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
struct tm gmtm;
gmtime_s(&gmtm, &rawTime);
Logger::directory = directory;
if (!std::filesystem::is_directory(directory))
std::filesystem::create_directories(directory);
Logger::logfilepath = util::string_format("%s\\log_%04d-%02d-%02d_%02d-%02d.txt", directory.c_str(),
1900 + gmtm.tm_year, gmtm.tm_mon, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min);
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <string>
#include <mutex>
#define EXTLOG(level, fmt, ...) Logger::Log(level, __FILE__, __LINE__, fmt, __VA_ARGS__)
#define LOG_CRIT(fmt, ...) EXTLOG(Logger::Level::Critical, fmt, __VA_ARGS__)
#define LOG_ERROR(fmt, ...) EXTLOG(Logger::Level::Error, fmt, __VA_ARGS__)
#define LOG_WARNING(fmt, ...) EXTLOG(Logger::Level::Warning, fmt, __VA_ARGS__)
#define LOG_INFO(fmt, ...) EXTLOG(Logger::Level::Info, fmt, __VA_ARGS__)
#define LOG_DEBUG(fmt, ...) EXTLOG(Logger::Level::Debug, fmt, __VA_ARGS__)
#define LOG_TRACE(fmt, ...) EXTLOG(Logger::Level::Trace, fmt, __VA_ARGS__)
class Logger
{
public:
enum class Level
{
None,
Critical,
Error,
Warning,
Info,
Debug,
Trace
};
enum class LoggerType
{
Any,
ConsoleLogger,
FileLogger
};
static void SetLevel(Level level, LoggerType type = LoggerType::Any);
static Level GetLevel(LoggerType type);
static void Log(Level logLevel, const char* filename, int line, const char* fmt, ...);
static void PrepareFileLogging(std::string directory);
private:
static Level s_FileLogLevel;
static Level s_ConsoleLogLevel;
static std::mutex _mutex;
static std::string directory;
static std::string logfilepath;
};

View File

@ -0,0 +1,95 @@
#include <pch.h>
#include "Patch.h"
#include <cheat-base/util.h>
bool Patch::Install(uint64_t address, std::vector<uint8_t> value)
{
if (patches.count(address) > 0)
{
LOG_ERROR("Failed to install patch: patch already installed.");
return false;
}
auto oldValue = WriteMemory(address, value);
if (oldValue == nullptr)
return false;
patches[address] = oldValue;
return true;
}
bool Patch::Restore(uint64_t address)
{
if (patches.count(address) == 0)
{
LOG_ERROR("Failed to restore patch: not found patch to target address 0x%016X", address);
return false;
}
auto restoreValue = patches[address];
auto oldValue = WriteMemory(address, *restoreValue);
if (oldValue == nullptr)
return false;
patches.erase(address);
delete restoreValue;
delete oldValue;
return true;
}
std::vector<uint8_t>* Patch::WriteMemory(uint64_t address, std::vector<uint8_t> value)
{
MEMORY_BASIC_INFORMATION information{};
auto size = VirtualQuery(reinterpret_cast<void*>(address), &information, sizeof(information));
if (size < sizeof(information))
{
LOG_LAST_ERROR("Failed to get page information");
return nullptr;
}
if (information.State != MEM_COMMIT)
{
LOG_ERROR("Page at target address isn't MEM_COMMIT (0x%016X)", address);
return nullptr;
}
DWORD oldProtection = -1;
if ((information.AllocationProtect & PAGE_READWRITE) == 0 && (information.AllocationProtect & PAGE_EXECUTE_READWRITE) == 0)
{
if (VirtualProtect(reinterpret_cast<void*>(address), value.size(), PAGE_EXECUTE_READWRITE, &oldProtection) == FALSE)
{
LOG_LAST_ERROR("Failed to change page protection");
return nullptr;
}
}
auto oldValue = new std::vector<uint8_t>(value.size());
auto errorCode = memcpy_s(oldValue->data(), value.size(), reinterpret_cast<void*>(address), value.size());
if (errorCode != 0)
{
LOG_ERROR("Failed to get origin value from memory at 0x%016X. Error code: %d", address, errorCode);
delete oldValue;
return nullptr;
}
errorCode = memcpy_s(reinterpret_cast<void*>(address), value.size(), value.data(), value.size());
if (errorCode != 0)
{
LOG_ERROR("Failed to rewrite target memory at 0x%016X. Error code: %d", address, errorCode);
delete oldValue;
return nullptr;
}
if (oldProtection != -1)
{
DWORD temp = 0;
if (VirtualProtect(reinterpret_cast<void*>(address), value.size(), oldProtection, &temp) == FALSE)
{
LOG_LAST_ERROR("Failed to restore page protection");
}
}
return oldValue;
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include <map>
#define OPatch(offset, value) Patch::Install(il2cppi_get_base_address() + offset, value)
#define OUnpatch(offset) Patch::Restore(il2cppi_get_base_address() + offset)
#define TogglePatch(field, targetField, offset, patchBytes) if (field == &targetField) { if (targetField.GetValue()) OPatch(offset, patchBytes); else OUnpatch(offset); return; }
class Patch
{
public:
// Installing patch to target address.
// In detail: replaces memory in target address with specified in 'value'
// saves old memory for future restore
// Return true if successfull.
static bool Install(uint64_t address, std::vector<uint8_t> value);
// Restoring old memory in this address, if it was patched.
// Return true if successfull.
static bool Restore(uint64_t address);
private:
inline static std::map<uint64_t, std::vector<uint8_t>*> patches{};
static std::vector<uint8_t>* WriteMemory(uint64_t address, std::vector<uint8_t> value);
};

View File

@ -0,0 +1,908 @@
#include "pch.h"
#include "PatternScanner.h"
#include <psapi.h>
#include <fstream>
#include <functional>
#include <cheat-base/util.h>
PatternScanner::PatternScanner() :
m_CacheChanged(false)
{
}
void PatternScanner::ParseSignatureFile(const std::string& signaturesContent)
{
nlohmann::json siganturesJson;
try
{
siganturesJson = nlohmann::json::parse(signaturesContent);
}
catch (nlohmann::json::parse_error* e)
{
LOG_ERROR("Failed to parse siganature json content. Error byte %d", e->byte);
return;
}
ParseSignatureJson(&siganturesJson);
}
bool PatternScanner::IsUpdated()
{
return m_CacheChanged;
}
void PatternScanner::ParseSignatureJson(void* signatureJson)
{
nlohmann::json& jsonContent = *reinterpret_cast<nlohmann::json*>(signatureJson);
for (auto& moduleEntry : jsonContent.items())
{
std::string moduleName = moduleEntry.key();
if (m_ModulePatterns.count(moduleName) == 0)
m_ModulePatterns[moduleName] = {};
auto& functionPatterns = m_ModulePatterns[moduleName];
for (auto& functionEntry : moduleEntry.value().items())
{
std::string functionName = functionEntry.key();
functionPatterns[functionName] = {};
auto& container = functionPatterns[functionName];
auto& patternInfo = functionEntry.value();
for (auto& xref : patternInfo["xref"])
container.xrefs.push_back({ xref["sig"], xref["offset"] });
for (auto& pattern : patternInfo["signatures"])
container.signatures.push_back(pattern);
}
}
}
uintptr_t PatternScanner::GetOffsetInt(const nlohmann::json& value)
{
std::uintptr_t offset = 0;
if (value.is_string())
{
std::string strValue = value;
offset = strtoul(strValue.c_str(), nullptr, 16);
}
else if (value.is_number_unsigned())
{
offset = value;
}
return offset;
}
std::string PatternScanner::GetOffsetStr(uintptr_t offset)
{
std::stringstream ss;
ss << std::hex << offset;
return ss.str();
}
void PatternScanner::Save(const std::filesystem::path& filename)
{
std::ofstream outputStream(filename, std::ios::out);
if (!outputStream.is_open())
{
LOG_ERROR("Failed to open file '%s' to save offsets.", filename.c_str());
return;
}
std::string output;
Save(output);
outputStream << output;
outputStream.close();
}
void PatternScanner::Save(std::string& outContent)
{
if (!m_CacheChanged)
outContent = m_LoadCache;
nlohmann::json modulesInfo{};
SaveJson(modulesInfo);
outContent = modulesInfo.dump();
}
void PatternScanner::SaveJson(nlohmann::json& outObject)
{
for (auto& [moduleName, functionsOffsets] : m_CacheOffsets)
{
SaveModuleHash(moduleName, outObject[moduleName]["hash"]);
auto& functionsObject = outObject[moduleName]["functions"];
for (auto& [functionName, offset] : functionsOffsets)
{
functionsObject[functionName] = GetOffsetStr(offset);
}
}
}
bool PatternScanner::Load(const std::filesystem::path& filename)
{
std::ifstream inputStream(filename, std::ios::in);
if (!inputStream.is_open())
{
LOG_ERROR("Failed to open file '%s' for load offsets.", filename.c_str());
return false;
}
std::stringstream buffer;
buffer << inputStream.rdbuf();
return Load(buffer.str());
}
bool PatternScanner::Load(const std::string& content)
{
nlohmann::json contentJson;
try
{
contentJson = nlohmann::json::parse(content);
}
catch (nlohmann::json::parse_error* e)
{
LOG_ERROR("Failed to parse siganature json content. Error byte %d", e->byte);
return false;
}
return LoadJson(contentJson);
m_LoadCache = content;
}
bool PatternScanner::LoadJson(const nlohmann::json& object)
{
bool result = true;
for (auto& moduleEntry : object.items())
{
std::string moduleName = moduleEntry.key();
auto& moduleJson = moduleEntry.value();
if (!IsValidModuleHash(moduleName, moduleJson["hash"]))
{
LOG_WARNING("Module '%s' hash don't match with saved one. Seems module was updated.", moduleName.c_str());
result = false;
continue;
}
if (m_CacheOffsets.count(moduleName) == 0)
m_CacheOffsets[moduleName] = {};
auto& functionsOffsets = m_CacheOffsets[moduleName];
for (auto& funcOffsetEntry : moduleJson["functions"].items())
{
functionsOffsets[funcOffsetEntry.key()] = GetOffsetInt(funcOffsetEntry.value());
}
}
return result;
}
PatternScanner::ModuleInfo& PatternScanner::GetModuleInfo(const std::string& modulePath)
{
static std::map<std::string, ModuleInfo> s_ModuleInfoCache;
std::string moduleName = std::filesystem::path(modulePath).filename().string();
if (s_ModuleInfoCache.count(moduleName) > 0)
return s_ModuleInfoCache[moduleName];
HMODULE hModule = GetModuleHandle(moduleName.c_str());
if (hModule == NULL)
{
LOG_LAST_ERROR("Failed to find module '%s'.", moduleName.c_str());
std::system("pause");
exit(0);
}
s_ModuleInfoCache[moduleName] = GetModuleInfo(hModule);
return s_ModuleInfoCache[moduleName];
}
PatternScanner::ModuleInfo& PatternScanner::GetModuleInfo(HMODULE hModule)
{
static std::map<HMODULE, ModuleInfo> s_ModuleInfoCache;
if (hModule == NULL)
{
LOG_CRIT("hModule is NULL.");
std::system("pause");
exit(0);
}
if (s_ModuleInfoCache.count(hModule) > 0)
return s_ModuleInfoCache[hModule];
MODULEINFO nativeInfo{};
BOOL result = GetModuleInformation(GetCurrentProcess(), hModule, &nativeInfo, sizeof(nativeInfo));
if (result == FALSE)
{
LOG_LAST_ERROR("Failed get info about module at 0x%p.", hModule);
std::system("pause");
exit(0);
}
s_ModuleInfoCache[hModule] = {};
auto& moduleInfo = s_ModuleInfoCache[hModule];
moduleInfo.handle = hModule;
moduleInfo.base = (uintptr_t)hModule;
moduleInfo.size = (uintptr_t)nativeInfo.SizeOfImage;
char buffer[MAX_PATH] = {};
result = GetModuleFileNameA(hModule, buffer, sizeof(buffer));
if (result == FALSE)
{
LOG_LAST_ERROR("Failed get filename module at 0x%p.", hModule);
std::system("pause");
exit(0);
}
moduleInfo.filePath = buffer;
LOG_DEBUG("Module %s bound 0x%p-0x%p.", moduleInfo.filePath.c_str(),
moduleInfo.base, moduleInfo.base + moduleInfo.size);
uintptr_t currentAddress = moduleInfo.base;
uintptr_t endAddress = moduleInfo.base + moduleInfo.size;
while (currentAddress <= endAddress)
{
MEMORY_BASIC_INFORMATION memoryInfo{};
auto byteCount = VirtualQuery((LPCVOID)currentAddress, &memoryInfo, sizeof(memoryInfo));
if (byteCount == 0)
{
LOG_LAST_ERROR("Failed get memory info for address 0x%p.", currentAddress);
break;
}
currentAddress = (uintptr_t)memoryInfo.BaseAddress + memoryInfo.RegionSize;
auto protection = memoryInfo.AllocationProtect;
if (protection != PAGE_EXECUTE && protection != PAGE_EXECUTE_READ &&
protection != PAGE_EXECUTE_READWRITE && protection != PAGE_EXECUTE_WRITECOPY)
continue;
moduleInfo.execRegions.push_back({ (uintptr_t)memoryInfo.BaseAddress, memoryInfo.RegionSize });
}
return moduleInfo;
}
void PatternScanner::AddOffset(const std::string& moduleName, const std::string& name, uintptr_t offset)
{
if (m_CacheOffsets.count(moduleName) == 0)
m_CacheOffsets[moduleName] = {};
m_CacheOffsets[moduleName][name] = offset;
m_CacheChanged = true;
}
size_t ComputeChecksum(const std::string& filename)
{
std::ifstream file(filename, std::ios::in | std::ios::binary);
if (!file.is_open())
{
LOG_ERROR("Failed to compute file json: %s", filename.c_str());
return 0;
}
size_t sum = 0;
size_t word = 0;
while (file.read(reinterpret_cast<char*>(&word), sizeof(word))) {
sum += word;
}
if (file.gcount()) {
word &= (~0U >> ((sizeof(size_t) - file.gcount()) * 8));
sum += word;
}
return sum;
}
int64_t PatternScanner::GetModuleTimestamp(const std::string& moduleName)
{
auto& moduleInfo = GetModuleInfo(moduleName);
auto write_time = std::filesystem::last_write_time(moduleInfo.filePath);
return write_time.time_since_epoch().count();
}
int64_t PatternScanner::GetModuleTimestamp(HMODULE hModule)
{
auto& moduleInfo = GetModuleInfo(hModule);
auto write_time = std::filesystem::last_write_time(moduleInfo.filePath);
return write_time.time_since_epoch().count();
}
bool PatternScanner::IsValidModuleHash(const std::string& moduleName, const nlohmann::json& hashObject)
{
auto& info = GetModuleInfo(moduleName);
return IsValidModuleHash(info.handle, hashObject);
}
bool PatternScanner::IsValidModuleHash(HMODULE hModule, const nlohmann::json& hashObject)
{
if (!hashObject.contains("timestamp") || !hashObject.contains("checksum"))
return false;
int64_t currTimestamp = GetModuleTimestamp(hModule);
int64_t timestamp = hashObject["timestamp"];
size_t checksum = hashObject["checksum"];
// To increase speed, we don't check checksum if timestamp matches
if (timestamp == currTimestamp)
{
m_ComputedHashes[hModule] = checksum;
return true;
}
size_t currChecksum = m_ComputedHashes.count(hModule) > 0 ? m_ComputedHashes[hModule] : ComputeChecksum(GetModuleInfo(hModule).filePath);
m_ComputedHashes[hModule] = currChecksum;
return checksum == currChecksum;
}
void PatternScanner::SaveModuleHash(const std::string& moduleName, nlohmann::json& outObject)
{
auto& info = GetModuleInfo(moduleName);
SaveModuleHash(info.handle, outObject);
}
void PatternScanner::SaveModuleHash(HMODULE hModule, nlohmann::json& outObject)
{
auto& moduleInfo = GetModuleInfo(hModule);
auto write_time = std::filesystem::last_write_time(moduleInfo.filePath);
int64_t timestamp = write_time.time_since_epoch().count();
size_t checksum = m_ComputedHashes.count(hModule) > 0 ? m_ComputedHashes[hModule] : ComputeChecksum(moduleInfo.filePath);
outObject["timestamp"] = timestamp;
outObject["checksum"] = checksum;
m_ComputedHashes[hModule] = checksum;
}
void PatternScanner::SearchAll()
{
for (auto& [moduleName, methodsSignatures] : m_ModulePatterns)
{
for (auto& [methodName, sigInfo] : methodsSignatures)
{
LOG_DEBUG("Searching %s::%s", moduleName.c_str(), methodName.c_str());
auto searchResult = Search(moduleName, methodName);
if (searchResult == 0)
LOG_WARNING("Not found");
else
LOG_DEBUG("Found function at %s + %p", moduleName.c_str(), searchResult);
}
}
}
uintptr_t PatternScanner::Search(const std::string& name)
{
for (auto& [moduleName, modulePatternsData] : m_ModulePatterns)
{
if (modulePatternsData.count(name) > 0)
return Search(moduleName, name, modulePatternsData[name]);
}
return 0;
}
uintptr_t PatternScanner::Search(const std::string& moduleName, const std::string& name)
{
uintptr_t moduleBase = GetModuleInfo(moduleName).base;
if (m_CacheOffsets.count(moduleName) > 0 && m_CacheOffsets[moduleName].count(name) > 0)
{
uintptr_t offset = m_CacheOffsets[moduleName][name];
return offset != 0 ? moduleBase + offset : 0;
}
if (m_ModulePatterns.count(moduleName) > 0 && m_ModulePatterns[moduleName].count(name) > 0)
return Search(moduleName, name, m_ModulePatterns[moduleName][name]);
AddOffset(moduleName, name, 0);
return 0;
}
uintptr_t PatternScanner::Search(const std::string& moduleName, const std::string& name, const PatternInfo& info)
{
AddressCounter counter;
uintptr_t moduleBase = GetModuleInfo(moduleName).base;
for (auto& pattern : info.signatures)
{
auto address = SearchFunction(moduleName, pattern);
if (address == 0)
continue;
counter.Add(address);
}
for (auto& xrefPattern : info.xrefs)
{
auto address = SearchXref(moduleName, xrefPattern);
if (address == 0)
continue;
counter.Add(address);
}
uintptr_t address = counter.GetMax();
AddOffset(moduleName, name, address == 0 ? 0 : address - moduleBase);
return address;
}
uintptr_t PatternScanner::SearchFunction(const std::string& moduleName, const std::string& pattern)
{
auto address = SearchInModule(moduleName, pattern);
if (address == 0)
return 0;
return FindFunctionEntry(address);
}
uintptr_t PatternScanner::SearchXref(const std::string& moduleName, const OffsetSignature& xrefPattern)
{
HMODULE hModule = GetModuleInfo(moduleName).handle;
return SearchXref(hModule, xrefPattern);
}
uintptr_t PatternScanner::SearchXref(HMODULE hModule, const OffsetSignature& xrefPattern)
{
auto address = SearchInModule(hModule, xrefPattern.pattern);
if (!address)
return 0;
uint8_t callOpcode = util::ReadMapped<uint8_t>((void*)address, xrefPattern.offset, true);
int opcodeOffset = 0;
switch (callOpcode)
{
case 0xE8:
case 0xE9:
opcodeOffset = 1;
break;
case 0x48:
case 0x4C:
opcodeOffset = 3;
break;
default:
LOG_WARNING("Trying find xref to not supported long call (opcode 0x%x)", callOpcode);
return 0;
}
int callOffset = util::ReadMapped<int>((void*)address, xrefPattern.offset + opcodeOffset, true);
uintptr_t dataAddress = address + xrefPattern.offset + 4 + opcodeOffset + callOffset;
//if (!IsFunctionEntry(functionAddress))
//{
// LOG_WARNING("Xref calc function address failed. There is no function at 0x%p.", functionAddress);
// return {};
//}
return dataAddress;
}
uintptr_t PatternScanner::SearchInModule(const std::string& moduleName, const std::string& pattern)
{
auto& moduleInfo = GetModuleInfo(moduleName);
auto tokens = util::StringSplit(" ", pattern);
std::vector<std::optional<uint8_t>> bytePattern;
bytePattern.reserve(tokens.size());
for (auto& token : tokens)
{
std::optional<uint8_t> value = token == "??" ? std::optional<uint8_t>() : std::stoi(token, 0, 16);
bytePattern.push_back(value);
}
uint8_t countFound = 0;
uint64_t address = 0;
for (auto& region : moduleInfo.execRegions)
{
auto regionSearchResult = SearchInRange(region.base, region.base + region.size, bytePattern);
if (regionSearchResult.status == SRStatus::NotFound)
continue;
if (regionSearchResult.status == SRStatus::NotUnique)
{
LOG_WARNING("Pattern ununique '%s'.", pattern.c_str());
return {};
}
countFound++;
if (countFound > 1)
{
LOG_WARNING("Pattern ununique '%s'.", pattern.c_str());
return {};
}
address = regionSearchResult.value;
}
if (countFound == 0)
LOG_WARNING("Pattern not found '%s'.", pattern.c_str());
return address;
}
uintptr_t PatternScanner::SearchInModule(HMODULE hModule, const std::string& pattern)
{
char buffer[MAX_PATH] = {};
auto count = GetModuleFileNameA(hModule, buffer, sizeof(buffer));
if (count == 0)
{
LOG_ERROR("Failed to get module name for handle 0x%p.", hModule);
return {};
}
return SearchInModule(buffer, pattern);
}
UINT32 get_first_bit_set(UINT32 x)
{
// Generates a single BSF instruction
unsigned long ret;
_BitScanForward(&ret, x);
return (UINT32)ret;
}
UINT32 clear_leftmost_set(UINT32 value)
{
// Generates a single BLSR instruction
return value & (value - 1);
}
int memcmp_mask(const BYTE* buffer1, const BYTE* buffer2, const BYTE* mask2, size_t count)
{
while (count--)
{
if (*mask2)
{
if (*buffer1 != *buffer2)
return -1;
}
buffer1++, buffer2++, mask2++;
};
return 0;
}
struct Signature
{
std::vector<uint8_t> bytes;
std::vector<uint8_t> mask;
bool hasWildcards = false;
Signature(const std::vector<std::optional<uint8_t>>& sig)
{
for (auto& item : sig)
{
if (!item)
{
bytes.push_back(0xCC);
mask.push_back(0x00);
hasWildcards = true;
continue;
}
bytes.push_back(*item);
mask.push_back(0xFF);
}
}
};
// Find signiture pattern in memory
PBYTE FindSignatureAVX2(PBYTE data, size_t size, const Signature& sig)
{
const auto* pat = sig.bytes.data();
size_t patLen = sig.bytes.size();
size_t patLen1 = (patLen - 1);
size_t patLen2 = (patLen - 2);
// Fill 'first' and 'last' with the first and last pattern byte respectively
const __m256i first = _mm256_set1_epi8(pat[0]);
const __m256i last = _mm256_set1_epi8(pat[patLen1]);
if (!sig.hasWildcards)
{
// A little faster without wildcards
// Scan 32 bytes at the time..
for (size_t i = 0; i + 32 + patLen1 < size; i += 32)
{
// Load in the next 32 bytes of input first and last
// Can use align 32 bit read for first since the input is page aligned
const __m256i block_first = _mm256_load_si256((const __m256i*) (data + i));
const __m256i block_last = _mm256_loadu_si256((const __m256i*) (data + i + patLen1));
// Compare first and last data to get 32byte masks
const __m256i eq_first = _mm256_cmpeq_epi8(first, block_first);
const __m256i eq_last = _mm256_cmpeq_epi8(last, block_last);
// AND the equality masks and into a 32 bit mask
UINT32 mask = _mm256_movemask_epi8(_mm256_and_si256(eq_first, eq_last));
// Do pattern compare between first and last position if we got our first and last at this data position
while (mask != 0)
{
UINT32 bitpos = get_first_bit_set(mask);
if (memcmp(data + i + bitpos + 1, pat + 1, patLen2) == 0)
return data + i + bitpos;
mask = clear_leftmost_set(mask);
};
}
}
else
{
// Pattern scan with wildcards mask
const BYTE* msk = sig.mask.data();
for (size_t i = 0; i + patLen1 + 32 < size; i += 32)
{
const __m256i block_first = _mm256_load_si256((const __m256i*) (data + i));
const __m256i block_last = _mm256_loadu_si256((const __m256i*) (data + i + patLen1));
const __m256i eq_first = _mm256_cmpeq_epi8(first, block_first);
const __m256i eq_last = _mm256_cmpeq_epi8(last, block_last);
UINT32 mask = _mm256_movemask_epi8(_mm256_and_si256(eq_first, eq_last));
// Do a byte pattern w/mask compare between first and last position if we got our first and last
while (mask != 0)
{
UINT32 bitpos = get_first_bit_set(mask);
if (memcmp_mask(data + i + bitpos + 1, pat + 1, msk + 1, patLen2) == 0)
return data + i + bitpos;
mask = clear_leftmost_set(mask);
};
}
}
return NULL;
}
PBYTE FindSignature(PBYTE input, size_t inputLen, const Signature& sig)
{
if (!sig.hasWildcards)
{
// If no wildcards, faster to use a memcmp() type
const BYTE* pat = sig.bytes.data();
const BYTE* end = (input + inputLen);
const BYTE first = *pat;
size_t sigLen = sig.bytes.size();
// Setup last in the pattern length byte quick for rejection test
size_t lastIdx = (sigLen - 1);
BYTE last = pat[lastIdx];
for (PBYTE ptr = input; ptr < end; ++ptr)
{
if ((ptr[0] == first) && (ptr[lastIdx] == last))
{
if (memcmp(ptr + 1, pat + 1, sigLen - 2) == 0)
return ptr;
}
}
}
else
{
const BYTE* pat = sig.bytes.data();
const BYTE* msk = sig.mask.data();
const BYTE* end = (input + inputLen);
const BYTE first = *pat;
size_t sigLen = sig.bytes.size();
size_t lastIdx = (sigLen - 1);
BYTE last = pat[lastIdx];
for (PBYTE ptr = input; ptr < end; ++ptr)
{
if ((ptr[0] == first) && (ptr[lastIdx] == last))
{
const BYTE* patPtr = pat + 1;
const BYTE* mskPtr = msk + 1;
const BYTE* memPtr = ptr + 1;
BOOL found = TRUE;
for (int i = 0; (i < sigLen - 2) && (memPtr < end); ++mskPtr, ++patPtr, ++memPtr, i++)
{
if (!*mskPtr)
continue;
if (*memPtr != *patPtr)
{
found = FALSE;
break;
}
}
if (found)
return ptr;
}
}
}
return 0;
}
PatternScanner::SearchResult PatternScanner::SearchSignatureAVX2(PBYTE input, size_t inputLen, const std::vector<std::optional<uint8_t>>& pattern)
{
Signature sig = Signature(pattern);
size_t sigSize = sig.bytes.size();
size_t len = inputLen;
size_t count = 0;
inputLen -= sigSize;
PBYTE match = FindSignatureAVX2(input, len, sig);
uintptr_t firstMatch = (uintptr_t)match;
while (match)
{
if (++count >= 2)
break;
++match;
len = (inputLen - (int)(match - input));
if (len < sigSize)
break;
match = FindSignatureAVX2(match, len, sig);
};
SearchResult result {};
result.value = (uintptr_t)firstMatch;
switch (count)
{
case 0: result.status = SRStatus::NotFound; break;
case 1: result.status = SRStatus::Unique; break;
default: result.status = SRStatus::NotUnique; break;
};
return result;
}
PatternScanner::SearchResult PatternScanner::SearchSignature(PBYTE input, size_t inputLen, const std::vector<std::optional<uint8_t>>& pattern)
{
Signature sig = Signature(pattern);
size_t sigSize = sig.bytes.size();
size_t len = inputLen;
size_t count = 0;
inputLen -= sigSize;
// Search for signature match..
PBYTE match = FindSignature(input, len, sig);
uintptr_t firstMatch = (uintptr_t)match;
while (match)
{
// Stop now if we've hit two matches
if (++count >= 2)
break;
++match;
len = (inputLen - (int)(match - input));
if (len < sigSize)
break;
// Next search
match = FindSignature(match, len, sig);
};
SearchResult result{};
result.value = (uintptr_t)firstMatch;
switch (count)
{
case 0: result.status = SRStatus::NotFound; break;
case 1: result.status = SRStatus::Unique; break;
default: result.status = SRStatus::NotUnique; break;
};
return result;
}
bool TestAVX2Support()
{
enum { EAX, EBX, ECX, EDX };
int regs[4];
// Highest Function Parameter
__cpuid(regs, 0);
if (regs[EAX] >= 7)
{
// Extended Features
__cpuid(regs, 7);
return (regs[EBX] & /*AVX2*/ (1 << 5)) != 0;
}
return false;
}
PatternScanner::SearchResult PatternScanner::SearchInRange(uintptr_t start, uintptr_t end, const std::vector<std::optional<uint8_t>>& pattern)
{
bool hasAVX2 = TestAVX2Support();
if (hasAVX2)
{
auto result = SearchSignatureAVX2((PBYTE)start, end - start, pattern);
return result;
}
static bool warnOnce = true;
if (warnOnce)
{
warnOnce = false;
LOG_WARNING("Using non-AVX2 reference search *\n");
}
return SearchSignature((PBYTE)start, end - start, pattern);
/*const uint8_t* rStart = (const uint8_t*)start;
const uint8_t* rEnd = (const uint8_t*)end;
auto comparer = [](uint8_t val1, std::optional<uint8_t> val2)
{
return (!val2 || val1 == *val2);
};
SearchResult sResult = { SRStatus::NotFound, 0 };
while (true)
{
const uint8_t* res = std::search(rStart, rEnd, pattern.begin(), pattern.end(), comparer);
if (res >= rEnd)
break;
if (sResult.status != SRStatus::NotFound)
return { SRStatus::NotUnique, 0 };
sResult = { SRStatus::Unique, (uint64_t)res };
rStart = res + pattern.size();
}
return sResult;*/
}
bool PatternScanner::IsFunctionEntry(uintptr_t functionAddress)
{
auto address = FindFunctionEntry(functionAddress);
if (functionAddress == 0)
return false;
return functionAddress == functionAddress;
}
uintptr_t PatternScanner::FindFunctionEntry(uintptr_t address)
{
// TODO: Implement function asm head find. Maybe with use Zydis.
return 0;
}
PatternScanner::AddressCounter::AddressCounter() {}
void PatternScanner::AddressCounter::Add(uintptr_t address)
{
if (m_Counts.count(address) == 0)
m_Counts[address] = 0;
m_Counts[address]++;
}
uintptr_t PatternScanner::AddressCounter::GetMax()
{
if (m_Counts.size() == 0)
return 0;
using pair_type = decltype(m_Counts)::value_type;
auto maxEntry = std::max_element(m_Counts.begin(), m_Counts.end(),
[](const pair_type& a, const pair_type& b)
{
return a.second < b.second;
});
return maxEntry->first;
}

View File

@ -0,0 +1,138 @@
#pragma once
#include <string>
#include <optional>
#include <map>
#include <filesystem>
#include <cheat-base/util.h>
class PatternScanner
{
public:
PatternScanner();
uintptr_t Search(const std::string& name);
virtual uintptr_t Search(const std::string& moduleName, const std::string& name);
virtual void SearchAll();
void Save(const std::filesystem::path& filename);
void Save(std::string& outContent);
bool Load(const std::filesystem::path& filename);
bool Load(const std::string& content);
virtual void SaveJson(nlohmann::json& outObject);
virtual bool LoadJson(const nlohmann::json& object);
void ParseSignatureFile(const std::string& signaturesContent);
bool IsUpdated();
bool IsValidModuleHash(HMODULE HMODULE, const nlohmann::json& hashObject);
bool IsValidModuleHash(const std::string& moduleName, const nlohmann::json& hashObject);
int64_t GetModuleTimestamp(const std::string& moduleName);
int64_t GetModuleTimestamp(HMODULE hModule);
protected:
class AddressCounter
{
public:
AddressCounter();
void Add(uintptr_t address);
uintptr_t GetMax();
private:
std::map<uintptr_t, size_t> m_Counts;
};
struct OffsetSignature
{
std::string pattern;
uint32_t offset;
};
struct PatternInfo
{
std::vector<std::string> signatures;
std::vector<OffsetSignature> xrefs;
};
std::map<std::string, std::map<std::string, PatternInfo>> m_ModulePatterns;
std::map<std::string, std::map<std::string, uintptr_t>> m_CacheOffsets;
bool m_CacheChanged;
std::string m_LoadCache;
std::map<HMODULE, int64_t> m_ComputedHashes;
struct RegionInfo
{
uintptr_t base;
size_t size;
};
struct ModuleInfo
{
HMODULE handle = 0;
uintptr_t base = 0;
size_t size = 0;
std::string filePath;
std::vector<RegionInfo> execRegions;
};
void AddOffset(const std::string& moduleName, const std::string& name, uintptr_t offset);
void SaveModuleHash(HMODULE hModule, nlohmann::json& outObject);
void SaveModuleHash(const std::string& moduleName, nlohmann::json& outObject);
ModuleInfo& GetModuleInfo(HMODULE hModule);
ModuleInfo& GetModuleInfo(const std::string& moduleName);
virtual void ParseSignatureJson(void* signatureJson);
virtual uintptr_t Search(const std::string& moduleName, const std::string& name, const PatternInfo& info);
uintptr_t SearchFunction(const std::string& moduleName, const std::string& pattern);
uintptr_t SearchXref(const std::string& moduleName, const OffsetSignature& xrefPattern);
uintptr_t SearchXref(HMODULE hModule, const OffsetSignature& xrefPattern);
uintptr_t SearchInModule(const std::string& moduleName, const std::string& pattern);
uintptr_t SearchInModule(HMODULE hModule, const std::string& pattern);
uintptr_t GetOffsetInt(const nlohmann::json& value);
std::string GetOffsetStr(uintptr_t offset);
template<typename R>
std::optional<R> SearchValue(HMODULE hModule, const std::string& pattern, uint32_t codeOffset)
{
auto address = SearchInModule(hModule, pattern);
if (address == 0)
return {};
int offset = util::ReadMapped<int>((void*)address, codeOffset, true);
return reinterpret_cast<R>(address + offset + codeOffset + sizeof(int));
}
enum class SRStatus
{
Unique,
NotUnique,
NotFound
};
struct SearchResult
{
SRStatus status;
uintptr_t value;
};
SearchResult SearchSignature(PBYTE input, size_t inputLen, const std::vector<std::optional<uint8_t>>& sig);
SearchResult SearchSignatureAVX2(PBYTE input, size_t inputLen, const std::vector<std::optional<uint8_t>>& sig);
SearchResult SearchInRange(uintptr_t start, uintptr_t end, const std::vector<std::optional<uint8_t>>& pattern);
virtual bool IsFunctionEntry(uintptr_t address);
virtual uintptr_t FindFunctionEntry(uintptr_t address);
};

View File

@ -0,0 +1,87 @@
#include <pch.h>
#include "PipeTransfer.h"
#include <iostream>
#include <sstream>
#include <cheat-base/util.h>
PipeTransfer::PipeTransfer(const std::string& name)
{
std::stringstream ss;
ss << "\\\\.\\pipe\\" << name;
this->m_Name = ss.str();
this->m_Pipe = 0;
}
PipeTransfer::~PipeTransfer()
{
if (m_Pipe)
CloseHandle(m_Pipe);
}
bool PipeTransfer::Create()
{
if (m_Pipe)
CloseHandle(m_Pipe);
m_Pipe = CreateNamedPipe(m_Name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 256 * 1024, 16, INFINITE, NULL);
return IsPipeOpened();
}
bool PipeTransfer::IsPipeOpened()
{
return m_Pipe && m_Pipe != INVALID_HANDLE_VALUE;
}
bool PipeTransfer::Connect()
{
if (IsPipeOpened())
CloseHandle(m_Pipe);
m_Pipe = CreateFile(m_Name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
return IsPipeOpened();
}
bool PipeTransfer::WaitForConnection()
{
return ConnectNamedPipe(m_Pipe, nullptr);
}
void PipeTransfer::ReadBytes(void* buffer, size_t size)
{
if (size == 0 || !IsPipeOpened()) return;
DWORD readCount = 0;
auto result = ReadFile(m_Pipe, buffer, size, &readCount, nullptr);
if (!result || readCount < size)
{
LOG_LAST_ERROR("Failed read from pipe.");
CloseHandle(m_Pipe);
m_Pipe = 0;
}
}
void PipeTransfer::WriteBytes(void* buffer, size_t size)
{
if (size == 0 || !IsPipeOpened()) return;
DWORD writenCount = 0;
auto result = WriteFile(m_Pipe, buffer, size, &writenCount, nullptr);
if (!result || writenCount < size)
{
LOG_LAST_ERROR("Failed write to pipe.");
CloseHandle(m_Pipe);
m_Pipe = 0;
}
}
void PipeTransfer::ReadObject(PipeSerializedObject& object)
{
object.Read(this);
}
void PipeTransfer::WriteObject(PipeSerializedObject& object)
{
object.Write(this);
}

View File

@ -0,0 +1,82 @@
#pragma once
#include <string>
#include <vector>
typedef unsigned char byte;
class PipeTransfer;
class PipeSerializedObject
{
public:
virtual void Write(PipeTransfer* transfer) = 0;
virtual void Read(PipeTransfer* transfer) = 0;
};
class PipeTransfer
{
public:
PipeTransfer(const std::string& name);
~PipeTransfer();
bool Create();
bool Connect();
bool WaitForConnection();
bool IsPipeOpened();
void ReadBytes(void* buffer, size_t size);
void WriteBytes(void* buffer, size_t size);
void ReadObject(PipeSerializedObject& object);
void WriteObject(PipeSerializedObject& object);
template<class T>
void Read(T& value)
{
ReadBytes(&value, sizeof(T));
}
template<class T>
void Write(const T& val)
{
WriteBytes(const_cast<T*>(&val), sizeof(T));
}
template<>
void Read(std::vector<byte>& vector)
{
size_t size; Read(size);
vector.clear();
vector.resize(size);
ReadBytes(vector.data(), size);
}
template<>
void Write(const std::vector<byte>& value)
{
Write<size_t>(value.size());
WriteBytes(const_cast<byte*>(value.data()), value.size());
}
template<>
void Read(std::string& value)
{
size_t size; Read(size);
value.clear();
value.resize(size);
ReadBytes(value.data(), size);
}
template<>
void Write(const std::string& value)
{
Write<size_t>(value.length());
WriteBytes(const_cast<char*>(value.data()), value.length());
}
private:
std::string m_Name;
HANDLE m_Pipe;
};

View File

@ -0,0 +1,49 @@
#include "pch.h"
#include "ResourceLoader.h"
#include "util.h"
std::string ResourceLoader::Load(const char* name, const char* type)
{
LPBYTE pData = nullptr;
DWORD size = 0;
if (!LoadEx(name, type, pData, size))
{
LOG_LAST_ERROR("Failed to load resource %s", name);
return {};
}
return std::string(reinterpret_cast<char*>(pData), size);
}
std::string ResourceLoader::Load(int resID, const char* type)
{
return ResourceLoader::Load(MAKEINTRESOURCE(resID), type);
}
bool ResourceLoader::LoadEx(const char* name, const char* type, LPBYTE& pDest, DWORD& size)
{
if (s_Handle == nullptr)
return false;
HRSRC hResource = FindResource(s_Handle, name, type);
if (hResource) {
HGLOBAL hGlob = LoadResource(s_Handle, hResource);
if (hGlob) {
size = SizeofResource(s_Handle, hResource);
pDest = static_cast<LPBYTE>(LockResource(hGlob));
if (size > 0 && pDest)
return true;
}
}
return false;
}
bool ResourceLoader::LoadEx(int resId, const char* type, LPBYTE& pDest, DWORD& size)
{
return ResourceLoader::LoadEx(MAKEINTRESOURCE(resId), type, pDest, size);
}
void ResourceLoader::SetModuleHandle(HMODULE handle)
{
s_Handle = handle;
}

View File

@ -0,0 +1,16 @@
#pragma once
class ResourceLoader
{
public:
static std::string Load(const char* name, const char* type);
static std::string Load(int resID, const char* type);
static bool LoadEx(const char* name, const char* type, LPBYTE& pDest, DWORD& size);
static bool LoadEx(int resId, const char* type, LPBYTE& pDest, DWORD& size);
static void SetModuleHandle(HMODULE handle);
private:
inline static HMODULE s_Handle = nullptr;
};

View File

@ -0,0 +1,551 @@
#include <pch.h>
#include "CheatManagerBase.h"
#include <misc/cpp/imgui_stdlib.h>
#include <cheat-base/render/renderer.h>
#include <cheat-base/render/gui-util.h>
#include <cheat-base/cheat/misc/Settings.h>
namespace cheat
{
void CheatManagerBase::Init(LPBYTE pFontData, DWORD dFontDataSize)
{
renderer::Init(pFontData, dFontDataSize);
events::RenderEvent += MY_METHOD_HANDLER(CheatManagerBase::OnRender);
events::KeyUpEvent += MY_METHOD_HANDLER(CheatManagerBase::OnKeyUp);
events::WndProcEvent += MY_METHOD_HANDLER(CheatManagerBase::OnWndProc);
}
CheatManagerBase::CheatManagerBase():
NF(m_SelectedSection, "", "General", 0),
m_IsBlockingInput(true),
m_IsPrevCursorActive(false)
{
}
void CheatManagerBase::DrawExternal() const
{
for (auto& feature : m_Features)
{
ImGui::PushID(&feature);
feature->DrawExternal();
ImGui::PopID();
}
}
void CheatManagerBase::DrawMenu()
{
if (m_ModuleOrder.empty())
return;
static std::string* current = &m_ModuleOrder[m_SelectedSection];
ImGui::SetNextWindowSize(ImVec2(600, 300), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("CCGenshin (By Callow)"))
{
ImGui::End();
return;
}
ImGui::BeginGroup();
if (ImGui::Checkbox("Block key/mouse", &m_IsBlockingInput))
{
renderer::SetInputLock(this, m_IsBlockingInput);
}
if (ImGui::BeginListBox("##listbox 2", ImVec2(175, -FLT_MIN)))
{
size_t index = 0;
for (auto& moduleName : m_ModuleOrder)
{
const bool is_selected = (current == &moduleName);
if (ImGui::Selectable(moduleName.c_str(), is_selected))
{
current = &moduleName;
m_SelectedSection = index;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
index++;
}
ImGui::EndListBox();
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
DrawProfileLine();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
ImGui::BeginChild("ChildR", ImVec2(0, 0), true, window_flags);
auto& sections = m_FeatureMap[*current];
auto emptyName = std::string();
if (sections.count(emptyName) > 0)
DrawMenuSection(emptyName, sections[""]);
for (auto& [sectionName, features] : sections)
{
if (sectionName.empty())
continue;
DrawMenuSection(sectionName, features);
}
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::EndGroup();
ImGui::End();
}
void CheatManagerBase::DrawMenuSection(const std::string& sectionName, const std::vector<Feature*>& features) const
{
if (!sectionName.empty())
BeginGroupPanel(sectionName.c_str(), ImVec2(-1, 0));
for (auto& feature : features)
{
ImGui::PushID(&feature);
feature->DrawMain();
ImGui::PopID();
}
if (!sectionName.empty())
EndGroupPanel();
}
void CheatManagerBase::DrawProfileGlobalActivities()
{
if (ImGui::Button("Add new profile"))
{
std::unordered_set<std::string> profileNameSet = { config::GetProfiles().begin(), config::GetProfiles().end() };
size_t index = 0;
std::string name {};
do
{
index++;
std::string newName = fmt::format("Profile #{}", index);
if (profileNameSet.count(newName) == 0)
name = newName;
} while (name.empty());
config::CreateProfile(name, false);
}
}
void CheatManagerBase::DrawProfileEntryActivities(const std::string& profileName)
{
bool isPopupOpen = ImGui::IsRenamePopupOpened();
if (isPopupOpen)
ImGui::BeginDisabled();
if (ImGui::SmallButton("Rnm"))
ImGui::OpenRenamePopup(profileName);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Rename");
if (isPopupOpen)
ImGui::EndDisabled();
std::string nameBuffer;
if (ImGui::DrawRenamePopup(nameBuffer))
{
config::RenameProfile(profileName, nameBuffer);
}
ImGui::SameLine();
if (ImGui::SmallButton("Del"))
config::RemoveProfile(profileName);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Delete");
}
void CheatManagerBase::DrawProfileEntry(const std::string& profileName)
{
ImGui::Text(profileName.c_str());
}
void CheatManagerBase::DrawProfileTableHeader()
{
ImGui::TableSetupColumn("Name");
}
int CheatManagerBase::GetProfileTableColumnCount()
{
return 1;
}
void CheatManagerBase::DrawProfileConfiguration()
{
static ImGuiTableFlags flags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollY;
if (ImGui::BeginTable("ProfileTable", GetProfileTableColumnCount() + 1, flags,
ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), 0.0f))
{
DrawProfileTableHeader();
ImGui::TableSetupColumn("Actions");
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableHeadersRow();
// Copy profiles names
auto profiles = config::GetProfiles();
for (auto& profile : profiles)
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushID(profile.c_str());
DrawProfileEntry(profile);
ImGui::TableNextColumn();
DrawProfileEntryActivities(profile);
ImGui::PopID();
}
ImGui::EndTable();
}
DrawProfileGlobalActivities();
}
void CheatManagerBase::DrawProfileLine()
{
if (m_IsProfileConfigurationShowed)
ImGui::BeginDisabled();
bool buttonPressed = ImGui::Button("Configure...");
if (m_IsProfileConfigurationShowed)
ImGui::EndDisabled();
if (buttonPressed)
m_IsProfileConfigurationShowed = !m_IsProfileConfigurationShowed;
ImGui::SameLine();
auto& profiles = config::GetProfiles();
auto& currentProfile = config::CurrentProfileName();
constexpr float width = 200.0f;
ImGui::SetNextItemWidth(width);
if (ImGui::BeginCombo("Profile", currentProfile.c_str()))
{
for (auto& name : profiles)
{
bool is_selected = (currentProfile == name);
if (ImGui::Selectable(name.c_str(), is_selected))
config::ChangeProfile(name);
if (ImGui::IsItemHovered() && CalcWidth(name) > width)
ShowHelpText(name.c_str());
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
void CheatManagerBase::DrawStatus() const
{
// Drawing status window
ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse;
auto& settings = feature::Settings::GetInstance();
if (!settings.f_StatusMove)
flags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
ImGui::Begin("Cheat status", nullptr, flags);
static ImGuiTableFlags tabFlags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
if (ImGui::BeginTable("activesTable", 1, tabFlags))
{
ImGui::TableSetupColumn("Active features");
ImGui::TableHeadersRow();
int row = 0;
for (auto& feature : m_Features)
{
if (feature->NeedStatusDraw())
{
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
feature->DrawStatus();
ImU32 row_bg_color = ImGui::GetColorU32(
ImVec4(0.2f + row * 0.1f, 0.1f + row * 0.05f, 0.1f + row * 0.03f, 0.85f));
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, row_bg_color);
row++;
}
}
ImGui::EndTable();
}
ImGui::End();
}
void CheatManagerBase::DrawInfo()
{
auto& settings = feature::Settings::GetInstance();
// Drawing status window
ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse;
if (!settings.f_InfoMove)
flags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
auto checkLambda = [](const Feature* feat) { return feat->NeedInfoDraw(); };
bool showAny = std::any_of(m_Features.begin(), m_Features.end(), checkLambda);
if (!showAny && !settings.f_StatusMove)
return;
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.04f, 0.05f, 0.05f, 0.90f));
ImGui::Begin("Info window", nullptr, flags);
ImGui::PopStyleColor();
if (!showAny)
{
ImGui::Text("Nothing here");
ImGui::End();
return;
}
for (auto& moduleName : m_ModuleOrder)
{
auto& sections = m_FeatureMap[moduleName];
bool moduleShowAny = std::any_of(sections.begin(), sections.end(),
[](const auto& iter)
{
return std::any_of(iter.second.begin(), iter.second.end(),
[](const auto feat)
{
return feat->NeedInfoDraw();
});
}
);
if (!moduleShowAny)
continue;
BeginGroupPanel(moduleName.c_str(), ImVec2(-1, 0));
for (auto& [sectionName, features] : sections)
{
for (auto& feature : features)
{
if (!feature->NeedInfoDraw())
continue;
ImGui::PushID(&feature);
feature->DrawInfo();
ImGui::PopID();
}
}
EndGroupPanel();
}
ImGui::End();
}
void CheatManagerBase::DrawFps()
{
auto& settings = feature::Settings::GetInstance();
ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing
| ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize;
if (!settings.f_FpsMove)
flags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
if (ImGui::Begin("FPS", nullptr, flags))
{
ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate);
ImGui::End();
}
}
void CheatManagerBase::DrawNotifications()
{
ImGui::RenderNotifications();
}
void CheatManagerBase::OnRender()
{
auto& settings = feature::Settings::GetInstance();
DrawExternal();
if (s_IsMenuShowed)
DrawMenu();
if (m_IsProfileConfigurationShowed)
{
ImGui::SetNextWindowSize({ 0, ImGui::GetTextLineHeightWithSpacing() * 11 }, ImGuiCond_FirstUseEver);
if (ImGui::Begin("Config profile configuration", &m_IsProfileConfigurationShowed))
DrawProfileConfiguration();
ImGui::End();
}
if (settings.f_StatusShow)
DrawStatus();
if (settings.f_InfoShow)
DrawInfo();
if (settings.f_FpsShow)
DrawFps();
if (settings.f_NotificationsShow)
DrawNotifications();
if (settings.f_MenuKey.value().IsReleased() && !ImGui::IsAnyItemActive())
ToggleMenuShow();
}
void CheatManagerBase::CheckToggles(short key) const
{
if (s_IsMenuShowed || renderer::IsInputLocked())
return;
auto& settings = feature::Settings::GetInstance();
if (!settings.f_HotkeysEnabled)
return;
for (auto& field : config::GetFields<config::Toggle<Hotkey>>())
{
auto& toggle = field.value();
if (toggle.value.IsPressed(key))
{
toggle.enabled = !toggle.enabled;
field.FireChanged();
std::string title = fmt::format("{}: {}", field.friendName(), (toggle ? "Enabled" : "Disabled"));
ImGuiToast toast(ImGuiToastType_None, settings.f_NotificationsDelay);
toast.set_title(title.c_str());
ImGui::InsertNotification(toast);
}
}
}
bool menuToggled = false;
void CheatManagerBase::ToggleMenuShow()
{
s_IsMenuShowed = !s_IsMenuShowed;
renderer::SetInputLock(this, s_IsMenuShowed && m_IsBlockingInput);
menuToggled = true;
}
void CheatManagerBase::OnKeyUp(short key, bool& cancelled)
{
auto& settings = feature::Settings::GetInstance();
if (!settings.f_MenuKey.value().IsPressed(key))
{
CheckToggles(key);
return;
}
}
void CheatManagerBase::OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool& canceled)
{
if (!menuToggled)
return;
menuToggled = false;
if (s_IsMenuShowed)
{
m_IsPrevCursorActive = CursorGetVisibility();
if (!m_IsPrevCursorActive)
CursorSetVisibility(true);
}
else if (!m_IsPrevCursorActive)
CursorSetVisibility(false);
}
bool CheatManagerBase::IsMenuShowed()
{
return s_IsMenuShowed;
}
void CheatManagerBase::PushFeature(Feature* feature)
{
m_Features.push_back(feature);
auto& info = feature->GetGUIInfo();
if (m_FeatureMap.count(info.moduleName) == 0)
{
m_FeatureMap[info.moduleName] = {};
m_ModuleOrder.push_back(info.moduleName);
}
auto& sectionMap = m_FeatureMap[info.moduleName];
std::string sectionName = info.isGroup ? info.name : std::string();
if (sectionMap.count(sectionName) == 0)
sectionMap[sectionName] = {};
auto& featureList = sectionMap[sectionName];
featureList.push_back(feature);
}
void CheatManagerBase::AddFeature(Feature* feature)
{
PushFeature(feature);
}
void CheatManagerBase::AddFeatures(std::vector<Feature*> features)
{
for (auto& feature : features)
{
PushFeature(feature);
}
}
void CheatManagerBase::SetModuleOrder(std::vector<std::string> moduleOrder)
{
std::unordered_set<std::string> moduleSet;
moduleSet.insert(m_ModuleOrder.begin(), m_ModuleOrder.end());
m_ModuleOrder.clear();
for (auto& moduleName : moduleOrder)
{
if (m_FeatureMap.count(moduleName) == 0)
continue;
m_ModuleOrder.push_back(moduleName);
moduleSet.erase(moduleName);
}
for (auto& moduleName : moduleSet)
{
m_ModuleOrder.push_back(moduleName);
}
}
}

View File

@ -0,0 +1,76 @@
#pragma once
#include <cheat-base/cheat/Feature.h>
#include <cheat-base/config/Config.h>
#include <cheat-base/events/event.hpp>
#include <vector>
#include <map>
#include <string>
#include <Windows.h>
namespace cheat
{
class CheatManagerBase
{
public:
static bool IsMenuShowed();
//static CheatManagerBase& GetInstance();
CheatManagerBase(CheatManagerBase const&) = delete;
void operator=(CheatManagerBase const&) = delete;
void AddFeature(Feature* feature);
void AddFeatures(std::vector<Feature*> features);
void SetModuleOrder(std::vector<std::string> moduleOrder);
void OnKeyUp(short key, bool& cancelled);
void OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool& cancelled);
void OnRender();
void Init(LPBYTE pFontData, DWORD dFontDataSize);
virtual void CursorSetVisibility(bool visibility) = 0;
virtual bool CursorGetVisibility() = 0;
protected:
config::Field<size_t> m_SelectedSection;
std::vector<Feature*> m_Features;
std::vector<std::string> m_ModuleOrder;
std::map<std::string, std::map<std::string, std::vector<Feature*>>> m_FeatureMap;
inline static bool s_IsMenuShowed = false;
bool m_IsBlockingInput;
bool m_IsPrevCursorActive;
bool m_IsProfileConfigurationShowed;
explicit CheatManagerBase();
void DrawExternal() const;
void DrawMenu();
void DrawMenuSection(const std::string& sectionName, const std::vector<Feature*>& features) const;
virtual void DrawProfileGlobalActivities();
virtual void DrawProfileEntryActivities(const std::string&profileName);
virtual void DrawProfileEntry(const std::string& profileName);
virtual void DrawProfileTableHeader();
virtual int GetProfileTableColumnCount();
virtual void DrawProfileConfiguration();
virtual void DrawProfileLine();
virtual void DrawStatus() const;
virtual void DrawInfo();
void DrawFps();
static void DrawNotifications();
void PushFeature(Feature* feature);
void CheckToggles(short key) const;
void ToggleMenuShow();
};
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <string>
namespace cheat
{
struct FeatureGUIInfo
{
std::string name;
std::string moduleName;
bool isGroup;
};
class Feature
{
public:
Feature(Feature const&) = delete;
void operator=(Feature const&) = delete;
// GUI handlers
virtual const FeatureGUIInfo& GetGUIInfo() const = 0;
virtual void DrawMain() = 0;
virtual bool NeedStatusDraw() const { return false; };
virtual void DrawStatus() { };
virtual bool NeedInfoDraw() const { return false; };
virtual void DrawInfo() { };
virtual void DrawExternal() { };
protected:
Feature() { };
};
}

View File

@ -0,0 +1,140 @@
#include <pch.h>
#include "Settings.h"
#include <cheat-base/render/gui-util.h>
#include <cheat-base/render/renderer.h>
#include <cheat-base/cheat/CheatManagerBase.h>
namespace cheat::feature
{
Settings::Settings() : Feature(),
NF(f_MenuKey, "Show Cheat Menu Key", "General", Hotkey(VK_F1)),
NF(f_HotkeysEnabled, "Hotkeys Enabled", "General", true),
NF(f_FontSize, "Font size", "General", 16.0f),
NF(f_StatusMove, "Move Status Window", "General::StatusWindow", true),
NF(f_StatusShow, "Show Status Window", "General::StatusWindow", true),
NF(f_InfoMove, "Move Info Window", "General::InfoWindow", true),
NF(f_InfoShow, "Show Info Window", "General::InfoWindow", true),
NF(f_FpsMove, "Move FPS Indicator", "General::FPS", false),
NF(f_FpsShow, "Show FPS Indicator", "General::FPS", true),
NF(f_NotificationsShow, "Show Notifications", "General::Notify", true),
NF(f_NotificationsDelay, "Notifications Delay", "General::Notify", 500),
NF(f_FileLogging, "File Logging", "General::Logging", false),
NF(f_ConsoleLogging, "Console Logging", "General::Logging", true),
NF(f_FastExitEnable, "Fast Exit", "General::FastExit", false),
NF(f_HotkeyExit, "Hotkeys", "General::FastExit", Hotkey(VK_F12))
{
renderer::SetGlobalFontSize(f_FontSize);
f_HotkeyExit.value().PressedEvent += MY_METHOD_HANDLER(Settings::OnExitKeyPressed);
}
const FeatureGUIInfo& Settings::GetGUIInfo() const
{
static const FeatureGUIInfo info{ "", "Settings", false };
return info;
}
void Settings::DrawMain()
{
BeginGroupPanel("General", ImVec2(-1, 0));
{
ConfigWidget(f_MenuKey, false,
"Key to toggle main menu visibility. Cannot be empty.\n"\
"If you forget this key, you can see or set it in your config file.");
ConfigWidget(f_HotkeysEnabled, "Enable hotkeys.");
if (ConfigWidget(f_FontSize, 1, 8, 64, "Font size for cheat interface."))
{
f_FontSize = std::clamp(f_FontSize.value(), 8, 64);
renderer::SetGlobalFontSize(f_FontSize);
}
}
EndGroupPanel();
BeginGroupPanel("Logging", ImVec2(-1, 0));
{
bool consoleChanged = ConfigWidget(f_ConsoleLogging,
"Enable console for logging information (changes will take effect after relaunch)");
if (consoleChanged && !f_ConsoleLogging)
{
Logger::SetLevel(Logger::Level::None, Logger::LoggerType::ConsoleLogger);
}
bool fileLogging = ConfigWidget(f_FileLogging,
"Enable file logging (changes will take effect after relaunch).\n" \
"A folder in the app directory will be created for logs.");
if (fileLogging && !f_FileLogging)
{
Logger::SetLevel(Logger::Level::None, Logger::LoggerType::FileLogger);
}
}
EndGroupPanel();
BeginGroupPanel("Status Window", ImVec2(-1, 0));
{
ConfigWidget(f_StatusShow);
ConfigWidget(f_StatusMove, "Allow moving of 'Status' window.");
}
EndGroupPanel();
BeginGroupPanel("Info Window", ImVec2(-1, 0));
{
ConfigWidget(f_InfoShow);
ConfigWidget(f_InfoMove, "Allow moving of 'Info' window.");
}
EndGroupPanel();
BeginGroupPanel("FPS indicator", ImVec2(-1, 0));
{
ConfigWidget(f_FpsShow);
ConfigWidget(f_FpsMove, "Allow moving of 'FPS Indicator' window.");
}
EndGroupPanel();
BeginGroupPanel("Show Notifications", ImVec2(-1, 0));
{
ConfigWidget(f_NotificationsShow, "Notifications on the bottom-right corner of the window will be displayed.");
ConfigWidget(f_NotificationsDelay, 1,1,10000, "Delay in milliseconds between notifications.");
}
EndGroupPanel();
BeginGroupPanel("Fast Exit", ImVec2(-1, 0));
{
ConfigWidget("Enabled",
f_FastExitEnable,
"Enable Fast Exit.\n"
);
if (!f_FastExitEnable)
ImGui::BeginDisabled();
ConfigWidget("Key", f_HotkeyExit, true,
"Key to exit the game.");
if (!f_FastExitEnable)
ImGui::EndDisabled();
}
EndGroupPanel();
}
Settings& Settings::GetInstance()
{
static Settings instance;
return instance;
}
void Settings::OnExitKeyPressed()
{
if (!f_FastExitEnable || CheatManagerBase::IsMenuShowed())
return;
ExitProcess(0);
}
}

View File

@ -0,0 +1,44 @@
#pragma once
#include <cheat-base/cheat/Feature.h>
#include <cheat-base/config/config.h>
namespace cheat::feature
{
class Settings : public Feature
{
public:
config::Field<Hotkey> f_MenuKey;
config::Field<bool> f_HotkeysEnabled;
config::Field<int> f_FontSize;
config::Field<bool> f_StatusMove;
config::Field<bool> f_StatusShow;
config::Field<bool> f_InfoMove;
config::Field<bool> f_InfoShow;
config::Field<bool> f_FpsShow;
config::Field<bool> f_FpsMove;
config::Field<bool> f_NotificationsShow;
config::Field<int> f_NotificationsDelay;
config::Field<bool> f_ConsoleLogging;
config::Field<bool> f_FileLogging;
config::Field<bool> f_FastExitEnable;
config::Field<Hotkey> f_HotkeyExit;
static Settings& GetInstance();
const FeatureGUIInfo& GetGUIInfo() const override;
void DrawMain() override;
private:
void OnExitKeyPressed();
Settings();
};
}

View File

@ -0,0 +1,383 @@
#include <pch.h>
#include "config.h"
#include <atomic>
#include <fstream>
#include <SimpleIni.h>
#include <cheat-base/util.h>
namespace config
{
TEvent<> ProfileChanged;
static std::filesystem::path s_Filepath;
static nlohmann::json s_ConfigRoot;
static nlohmann::json s_EmptyJObject = nlohmann::json::object();
// Little speed-up
static nlohmann::json* s_ProfileRoot = nullptr;
static nlohmann::json* s_Profiles = nullptr;
static nlohmann::json* s_SharedRoot = nullptr;
static std::mutex s_ProfileMutex;
static std::string s_ProfileName;
static std::vector<std::string> s_ProfilesNames;
static const int c_SaveDelay = 2000;
static TEvent<>* s_UpdateEvent = nullptr;
static std::atomic<int64_t> s_NextSaveTimestamp = 0;
static std::vector<std::shared_ptr<internal::FieldEntry>> s_Entries;
void LoadFile()
{
std::ifstream fileInput(s_Filepath, std::ios::in);
if (!fileInput.is_open())
{
LOG_DEBUG("Failed to open config file, maybe it's first launch.");
return;
}
try
{
s_ConfigRoot = nlohmann::json::parse(fileInput);
}
catch (nlohmann::json::parse_error& ex)
{
LOG_ERROR("Parse error at byte %llu", ex.byte);
return;
}
}
void UpdateProfilesNames()
{
std::lock_guard _lock(s_ProfileMutex);
s_ProfilesNames.clear();
for (auto& [name, _] : s_Profiles->items())
{
s_ProfilesNames.push_back(name);
}
}
void Initialize(const std::string& filePath)
{
s_ConfigRoot = {};
s_Filepath = filePath;
LoadFile();
if (!s_ConfigRoot.contains("current_profile"))
{
s_ConfigRoot = {
{ "shared", {} },
{ "profiles", {} },
{ "current_profile", ""}
};
}
s_Profiles = &s_ConfigRoot["profiles"];
s_SharedRoot = &s_ConfigRoot["shared"];
if (s_ConfigRoot["current_profile"] == "")
CreateProfile("default");
else
ChangeProfile(s_ConfigRoot["current_profile"]);
UpdateProfilesNames();
}
void OnUpdate();
void SetupUpdate(TEvent<>* updateEvent)
{
s_UpdateEvent = updateEvent;
(*s_UpdateEvent) += FUNCTION_HANDLER(OnUpdate);
}
void UpdateSaveTimestamp()
{
if (!s_UpdateEvent)
return;
if (s_NextSaveTimestamp != 0)
return;
s_NextSaveTimestamp = util::GetCurrentTimeMillisec() + c_SaveDelay;
}
void ResetNotShared()
{
for (auto& entry : s_Entries)
{
if (!entry->IsShared())
entry->Reset();
}
}
nlohmann::json& GetFieldJsonContainer(internal::FieldEntry* field, bool create = false)
{
if (field->GetContainer() != nullptr)
return *field->GetContainer();
nlohmann::json* rootContainer = s_ProfileRoot;
if (field->IsShared())
rootContainer = s_SharedRoot;
auto sectionParts = util::StringSplit("::", field->GetSection());
for (auto& part : sectionParts)
{
if (!rootContainer->contains(part))
{
if (!create)
return s_EmptyJObject;
(*rootContainer)[part] = {};
}
rootContainer = &(*rootContainer)[part];
}
auto& sectionContainer = *rootContainer;
if (!sectionContainer.contains(field->GetName()))
{
if (!create)
return s_EmptyJObject;
sectionContainer[field->GetName()] = {};
}
auto& fieldContainer = sectionContainer[field->GetName()];
field->SetContainer(&fieldContainer);
return fieldContainer;
}
void RemoveFieldContainer(internal::FieldEntry* field, const std::string& section, const std::string& name, bool shared)
{
field->SetContainer(nullptr);
nlohmann::json* rootContainer = s_ProfileRoot;
if (shared)
rootContainer = s_SharedRoot;
auto sectionParts = util::StringSplit("::", section);
std::list<std::pair<std::string, nlohmann::json*>> nodePath;
for (auto& part : sectionParts)
{
if (!(*rootContainer).contains(part))
return;
nodePath.push_front({ part, rootContainer });
rootContainer = &(*rootContainer)[part];
}
if (!rootContainer->contains(name))
return;
rootContainer->erase(name);
for (auto& [key, node] : nodePath)
{
if (!(*node)[key].empty())
break;
node->erase(key);
}
}
void UpdateField(internal::FieldEntry* field)
{
auto& fieldContainer = GetFieldJsonContainer(field);
field->FromJson(fieldContainer);
}
void UpdateNotShared()
{
ResetNotShared();
for (auto& entry : s_Entries)
{
if (!entry->IsShared())
UpdateField(entry.get());
}
}
void LoadField(internal::FieldEntry* field)
{
auto& fieldContainer = GetFieldJsonContainer(field, true);
auto jObject = field->ToJson();
if (jObject.empty())
RemoveFieldContainer(field, field->GetSection(), field->GetName(), field->IsShared());
else
fieldContainer = jObject;
}
void LoadAll()
{
for (auto& entry : s_Entries)
{
LoadField(entry.get());
}
}
void OnFieldChanged(internal::FieldEntry* field)
{
LoadField(field);
Save();
}
void OnFieldMoved(internal::FieldEntry* field, const std::string& oldSection, bool oldShared)
{
RemoveFieldContainer(field, oldSection, field->GetName(), oldShared);
OnFieldChanged(field);
}
void OnFieldReposition(internal::FieldEntry* field, const std::string& oldSection, bool oldShared)
{
field->SetContainer(nullptr);
UpdateField(field);
}
void internal::AddField(std::shared_ptr<FieldEntry> field)
{
s_Entries.push_back(field);
UpdateField(field.get());
field->ChangedEvent += FUNCTION_HANDLER(OnFieldChanged);
field->MovedEvent += FUNCTION_HANDLER(OnFieldMoved);
field->RepositionEvent += FUNCTION_HANDLER(OnFieldReposition);
}
void Refresh()
{
LoadAll();
Save();
}
void SaveInternal()
{
std::ofstream fileOutput(s_Filepath, std::ios::out);
if (!fileOutput.is_open())
{
LOG_DEBUG("Failed to open config file for writing.");
UpdateSaveTimestamp();
return;
}
fileOutput << s_ConfigRoot.dump(4);
fileOutput.close();
}
void Save()
{
if (s_UpdateEvent)
{
UpdateSaveTimestamp();
return;
}
SaveInternal();
}
void OnUpdate()
{
if (s_NextSaveTimestamp > 0 && util::GetCurrentTimeMillisec() > s_NextSaveTimestamp)
{
s_NextSaveTimestamp = 0;
SaveInternal();
}
}
void CreateProfile(const std::string& profileName, bool moveAfterCreate)
{
if (s_Profiles->contains(profileName))
{
if (moveAfterCreate)
ChangeProfile(profileName);
return;
}
(*s_Profiles)[profileName] = {};
UpdateProfilesNames();
if (moveAfterCreate)
ChangeProfile(profileName);
Save();
}
void RemoveProfile(const std::string& profileName)
{
if (!s_Profiles->contains(profileName))
return;
if (s_Profiles->size() == 1)
return;
if (s_ProfileName == profileName)
{
for (auto& [name, value] : s_Profiles->items())
{
if (name != profileName)
{
ChangeProfile(name);
break;
}
}
}
s_Profiles->erase(profileName);
UpdateProfilesNames();
Save();
}
void RenameProfile(const std::string& oldProfileName, const std::string& newProfileName)
{
if (!s_Profiles->contains(oldProfileName) || s_Profiles->contains(newProfileName))
return;
if (s_ProfileName == oldProfileName)
s_ProfileRoot = nullptr;
(*s_Profiles)[newProfileName] = (*s_Profiles)[oldProfileName];
s_Profiles->erase(oldProfileName);
if (s_ProfileRoot == nullptr)
{
for (auto& entry : s_Entries)
{
if (!entry->IsShared())
entry->SetContainer(nullptr);
}
ChangeProfile(newProfileName);
}
UpdateProfilesNames();
Save();
}
void ChangeProfile(const std::string& profileName)
{
if (s_ProfileName == profileName)
return;
if (!s_Profiles->contains(profileName))
return;
std::lock_guard _lock(s_ProfileMutex);
s_ProfileRoot = &(*s_Profiles)[profileName];
s_ProfileName = profileName;
s_ConfigRoot["current_profile"] = profileName;
UpdateNotShared();
Save();
ProfileChanged();
}
std::vector<std::string> const& GetProfiles()
{
return s_ProfilesNames;
}
std::string const& CurrentProfileName()
{
return s_ProfileName;
}
}

View File

@ -0,0 +1,66 @@
#pragma once
#include "Field.h"
#include <vector>
#include <string>
#include "fields/Toggle.h"
#include "fields/Enum.h"
#define NFEX(field, friendName, name, section, defaultValue, shared) field##(config::CreateField<decltype(##field##)::_ValueType>(friendName, name, section, shared, defaultValue))
#define NFEXUP(field, friendName, name, section, shared, ...) field##(config::CreateField<decltype(##field##)::_ValueType>(friendName, name, section, shared, __VA_ARGS__))
#define NFB(field, name, section, defaultValue, shared) NFEX(field, name, config::internal::FixFieldName(#field), section, defaultValue, shared)
#define NFS(field, name, section, defaultValue) NFB(field, name, section, defaultValue, true)
#define NF(field, name, section, defaultValue) NFB(field, name, section, defaultValue, false)
#define NFPB(field, name, section, shared, ...) NFEXUP(field, name, config::internal::FixFieldName(#field), section, shared, __VA_ARGS__)
#define NFPS(field, name, section, ...) NFPB(field, name, section, true, __VA_ARGS__)
#define NFP(field, name, section, ...) NFPB(field, name, section, false, __VA_ARGS__)
namespace config
{
namespace internal
{
template<typename T>
std::vector<T> s_Fields;
void AddField(std::shared_ptr<FieldEntry> field);
inline std::string FixFieldName(const std::string& fieldName)
{
if (fieldName.substr(1, 1) == "_")
return fieldName.substr(2);
return fieldName;
}
}
template<typename T, typename... Args>
Field<T> CreateField(const std::string& friendName, const std::string& name, const std::string& section, bool multiProfile, Args... args)
{
auto newField = Field<T>(friendName, name, section, T(args...), multiProfile);
internal::s_Fields<Field<T>>.push_back(newField);
internal::AddField(newField.entry());
return newField;
}
template<typename T>
std::vector<Field<T>>& GetFields()
{
return internal::s_Fields<Field<T>>;
}
void Initialize(const std::string& filePath);
void SetupUpdate(TEvent<>*);
void Refresh();
void Save();
void CreateProfile(const std::string& profileName, bool moveAfterCreate = true);
void RemoveProfile(const std::string& profileName);
void RenameProfile(const std::string& oldProfileName, const std::string& newProfileName);
void ChangeProfile(const std::string& profileName);
std::vector<std::string> const& GetProfiles();
std::string const& CurrentProfileName();
extern TEvent<> ProfileChanged;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "internal/FieldSerialize.h"
#include "internal/FieldBase.h"
namespace config
{
template<class T>
class Field : public internal::FieldBase<T>
{
public:
using base = internal::FieldBase<T>;
using base::operator=;
using base::base;
};
}

View File

@ -0,0 +1,68 @@
#pragma once
#include <nlohmann/json.hpp>
#include <cheat-base/Hotkey.h>
#include <imgui.h>
namespace config::converters
{
template<typename T>
inline nlohmann::json ToJson(const T& value)
{
return nlohmann::json(value);
}
template<typename T>
inline void FromJson(T& value, const nlohmann::json& jObject)
{
value = jObject.get<T>();
}
// Here is storing all simple converters json<->class
// ImColor
template<>
inline nlohmann::json ToJson(const ImColor& value)
{
return nlohmann::json((ImU32)value);
}
template<>
inline void FromJson(ImColor& value, const nlohmann::json& jObject)
{
value = { (ImU32)jObject };
}
// Hotkey
template<>
inline nlohmann::json ToJson(const Hotkey& value)
{
auto keys = value.GetKeys();
if (keys.empty())
return {};
if (keys.size() == 1)
return keys[0];
return nlohmann::json(value.GetKeys());
}
template<>
inline void FromJson(Hotkey& value, const nlohmann::json& jObject)
{
if (jObject.is_null() || jObject.empty())
return;
if (jObject.is_number())
{
value = { jObject.get<short>() };
return;
}
value = { jObject.get<std::vector<short>>() };
}
// Enum
}

View File

@ -0,0 +1,100 @@
#pragma once
#include <magic_enum.hpp>
namespace config
{
template<typename T>
class Enum
{
public:
Enum()
{
static_assert(std::is_enum<T>::value, "Must be an enum type");
m_Value = T();
}
Enum(T enumValue)
{
static_assert(std::is_enum<T>::value, "Must be an enum type");
m_Value = enumValue;
}
inline T value() const
{
return m_Value;
}
inline T* pointer() const
{
return const_cast<T*>(&m_Value);
}
inline operator T()
{
return value();
}
inline T* operator&()
{
return pointer();
}
inline uint32_t raw() const
{
return static_cast<uint32_t>(m_Value);
}
inline Enum& operator=(const T& other)
{
static_assert(std::is_enum<T>::value, "Must be an enum type");
m_Value = other;
return *this;
}
inline Enum& operator=(const uint32_t& other)
{
m_Value = static_cast<T>(other);
return *this;
}
private:
T m_Value;
};
//// Okay, close your eyes and don't look at this mess. (Please)
//template <typename K>
//class Field<Enum<K>> : public internal::FieldBase<Enum<K>>
//{
//public:
// using base = internal::FieldBase<Enum<K>>;
// using base::operator=;
// using base::base;
// operator T() const
// {
// return base::value();
// }
//};
}
namespace nlohmann
{
template <typename T>
struct adl_serializer<config::Enum<T>> {
static void to_json(json& j, const config::Enum<T>& enumValue)
{
j = {
{ "name", magic_enum::enum_name(enumValue.value()) },
{ "value", enumValue.raw() }
};
}
static void from_json(const json& j, config::Enum<T>& value)
{
value = j["value"].get<uint32_t>();
}
};
}

View File

@ -0,0 +1,83 @@
#pragma once
#include <cheat-base/Hotkey.h>
#include <cheat-base/config/internal/FieldBase.h>
namespace config
{
template<typename T>
class Toggle
{
public:
bool enabled;
T value;
Toggle(const T& value) : enabled(false), value(value) { }
Toggle(bool enabled) : enabled(enabled), value() { }
Toggle() : enabled(false), value() { }
inline operator bool&()
{
return enabled;
}
inline operator T&()
{
return value;
}
inline bool operator==(const Toggle<T>& rhs)
{
return rhs.enabled == enabled && rhs.value == value;
}
};
// Okay, close your eyes and don't look at this mess. (Please)
template<typename T>
class Field<Toggle<T>> : public internal::FieldBase<Toggle<T>>
{
public:
using base = internal::FieldBase<Toggle<T>>;
using base::operator=;
using base::base;
operator bool() const
{
return base::value();
}
operator T&() const
{
return base::value().value;
}
};
}
namespace nlohmann
{
template <typename T>
struct adl_serializer<config::Toggle<T>> {
static void to_json(json& j, const config::Toggle<T>& toggle)
{
j = {
{ "toggled", toggle.enabled },
{ "value", config::converters::ToJson(toggle.value) }
};
}
static void from_json(const json& j, config::Toggle<T>& toggle)
{
if (j.is_boolean())
{
toggle.enabled = j;
toggle.value = {};
return;
}
toggle.enabled = j["toggled"].get<uint32_t>();
config::converters::FromJson(toggle.value, j.contains("value") ? j["value"] : j["hotkey"]); // Support previously version
}
};
}

View File

@ -0,0 +1,105 @@
#pragma once
#include "FieldEntry.h"
#include "FieldSerialize.h"
namespace config::internal
{
template<typename T>
class FieldBase
{
public:
using _ValueType = T;
explicit FieldBase() : p_Container(nullptr) {}
explicit FieldBase(FieldSerialize<T>* serializeFieldPtr) : p_Container(serializeFieldPtr) { }
explicit FieldBase(const std::shared_ptr<FieldSerialize<T>>& serializeField) : p_Container(serializeField) { }
explicit FieldBase(const std::string friendlyName, const std::string name, const std::string section, T defaultValue, bool multiProfile = false)
: p_Container(std::make_shared<FieldSerialize<T>>(friendlyName, name, section, defaultValue, multiProfile)) { }
std::string name() const
{
return p_Container->GetName();
}
std::string friendName() const
{
return p_Container->GetFriendName();
}
std::string section() const
{
return p_Container->GetSection();
}
bool shared() const
{
return p_Container->IsShared();
}
T& value() const
{
return p_Container->m_Value;
}
T* pointer() const
{
return &p_Container->m_Value;
}
std::shared_ptr<internal::FieldEntry> entry() const
{
return std::static_pointer_cast<FieldEntry>(p_Container);
}
operator T& () const
{
return value();
}
operator T* () const
{
return pointer();
}
void FireChanged() const
{
p_Container->FireChanged();
}
void repos(const std::string& newSection, bool shared = false)
{
p_Container->Reposition(newSection, shared);
}
void move(const std::string& newSection, bool shared = false)
{
p_Container->Move(newSection, shared);
}
FieldBase<T>& operator=(const T& other)
{
p_Container->m_Value = other;
p_Container->FireChanged();
return *this;
}
FieldBase<T>& operator=(std::shared_ptr<FieldSerialize<T>>& other)
{
p_Container = other;
return *this;
}
FieldBase<T>& operator=(FieldSerialize<T>* other)
{
p_Container = std::make_shared<FieldSerialize<T>>(other);
return *this;
}
protected:
std::shared_ptr<FieldSerialize<T>> p_Container;
};
}

View File

@ -0,0 +1,87 @@
#pragma once
#include <string>
#include <cheat-base/events/event.hpp>
#include <nlohmann/json.hpp>
namespace config::internal
{
class FieldEntry
{
public:
FieldEntry(const std::string& friendlyName, const std::string& name, const std::string& sectionName, bool multiProfile = false)
: m_FriendName(friendlyName), m_Name(name), m_Section(sectionName), m_MultiProfile(multiProfile), m_Container(nullptr) {}
TEvent<FieldEntry*> ChangedEvent;
TEvent<FieldEntry*, const std::string&, bool> MovedEvent;
TEvent<FieldEntry*, const std::string&, bool> RepositionEvent;
inline virtual void FireChanged()
{
ChangedEvent(this);
}
virtual nlohmann::json ToJson() = 0;
virtual void FromJson(const nlohmann::json& value) = 0;
virtual void Reset() = 0;
inline bool IsShared() const
{
return m_MultiProfile;
}
inline std::string GetName() const
{
return m_Name;
}
inline std::string GetFriendName() const
{
return m_FriendName;
}
inline std::string GetSection() const
{
return m_Section;
}
inline nlohmann::json* GetContainer() const
{
return m_Container;
}
inline void Reposition(const std::string& newSection, bool shared = false)
{
std::string oldSection = m_Section;
bool oldMultiProfile = m_MultiProfile;
m_Section = newSection;
m_MultiProfile = shared;
RepositionEvent(this, newSection, shared);
}
inline void Move(const std::string& newSection, bool shared = false)
{
std::string oldSection = m_Section;
bool oldMultiProfile = m_MultiProfile;
m_Section = newSection;
m_MultiProfile = shared;
MovedEvent(this, oldSection, oldMultiProfile);
}
inline void SetContainer(nlohmann::json* newContainer)
{
m_Container = nullptr;
}
protected:
std::string m_Name;
std::string m_FriendName;
std::string m_Section;
bool m_MultiProfile;
nlohmann::json* m_Container;
};
}

View File

@ -0,0 +1,42 @@
#pragma once
#include "FieldEntry.h"
#include <cheat-base/config/converters.h>
namespace config::internal
{
template<typename T>
class FieldSerialize : public FieldEntry
{
public:
FieldSerialize(const std::string& friendlyName, const std::string& name, const std::string& sectionName, const T& defaultValue, bool multiProfile = false) :
FieldEntry(friendlyName, name, sectionName, multiProfile), m_Value(defaultValue), m_DefaultValue(defaultValue) { }
nlohmann::json ToJson() override
{
if (m_Value == m_DefaultValue)
return {};
return converters::ToJson(m_Value);
}
void FromJson(const nlohmann::json& jObject) override
{
if (jObject.empty())
{
m_Value = m_DefaultValue;
return;
}
converters::FromJson(m_Value, jObject);
}
void Reset() override
{
m_Value = m_DefaultValue;
}
T m_Value;
T m_DefaultValue;
};
}

View File

@ -0,0 +1,211 @@
// Taken from https://github.com/ZolotovPavel/EventHandling
#pragma once
#include <type_traits>
#include <list>
#include <memory>
#include <shared_mutex>
#include <algorithm>
#include <assert.h>
#include "handlers/abstracteventhandler.hpp"
#include "handlers/eventhandlerptr.h"
#include "handlers/handlercast.hpp"
#include "joins/eventjoinwrapper.hpp"
template<class ...TParams>
struct TypeHelper
{
using TEventHandlerPtr = ::events::handlers::TEventHandlerPtr<TParams...>;
using TEventHandlerIt = typename std::list<TEventHandlerPtr>::const_iterator;
};
namespace joins
{
template<class ...TParams> class HandlerEventJoin;
}
template<class ...TParams>
class IEvent
{
public:
template<class TSome>
::events::EventJoin operator+=( TSome&& some )
{
::events::EventJoin result( *this, std::forward<TSome>( some ) );
result.join();
return result;
}
template<class TSome>
bool operator-=( TSome&& some )
{
return removeHandler(::events::handlers::HandlerCast<TSome>::template cast<TParams...>( some ) );
}
protected:
using TMyEventHandlerPtr = typename TypeHelper<TParams...>::TEventHandlerPtr;
IEvent() {}
virtual bool isHandlerAdded( const TMyEventHandlerPtr& eventHandler ) const = 0;
virtual bool addHandler( TMyEventHandlerPtr eventHandler ) = 0;
virtual bool removeHandler( TMyEventHandlerPtr eventHandler ) = 0;
friend class ::events::joins::HandlerEventJoin<TParams...>;
};
template<class ...TParams>
struct EventCore
{
using TMyHandlerPtr = typename TypeHelper<TParams...>::TEventHandlerPtr;
std::list<TMyHandlerPtr> handlers;
mutable std::shared_mutex coreMutex;
};
template<class ...TParams>
class HandlerRunner
{
using TMyEventCore = EventCore<TParams...>;
using TMyHandlerIt = typename TypeHelper<TParams...>::TEventHandlerIt;
public:
HandlerRunner( TMyEventCore& eventCore ) :
m_eventCore( eventCore ),
currentIt(),
wasRemoving( false )
{
}
void run( TParams... params )
{
m_eventCore.coreMutex.lock_shared();
currentIt = m_eventCore.handlers.begin();
wasRemoving = false;
while( currentIt != m_eventCore.handlers.end() )
{
m_eventCore.coreMutex.unlock_shared();
( *currentIt )->call( params... );
m_eventCore.coreMutex.lock_shared();
if( wasRemoving )
wasRemoving = false;
else
++currentIt;
}
m_eventCore.coreMutex.unlock_shared();
}
TMyHandlerIt currentIt;
mutable bool wasRemoving;
private:
TMyEventCore& m_eventCore;
};
template<class ...TParams>
class TEvent : public IEvent<TParams...>
{
using TMyEventHandlerPtr = typename TypeHelper<TParams...>::TEventHandlerPtr;
using TMyEventHandlerIt = typename TypeHelper<TParams...>::TEventHandlerIt;
using TMyHandlerRunner = HandlerRunner<TParams...>;
public:
TEvent() :
m_core()
{
}
virtual void operator()( TParams... params )
{
TMyHandlerRunner newHandlerRunner( m_core );
m_core.coreMutex.lock_shared();
auto it = m_handlerRunners.insert( m_handlerRunners.end(), &newHandlerRunner );
m_core.coreMutex.unlock_shared();
newHandlerRunner.run( params... );
m_core.coreMutex.lock_shared();
m_handlerRunners.erase( it );
m_core.coreMutex.unlock_shared();
}
protected:
virtual bool isHandlerAdded( const TMyEventHandlerPtr& eventHandler ) const override
{
std::shared_lock<std::shared_mutex> _coreMutexLock( m_core.coreMutex );
return ( findEventHandler( eventHandler ) != m_core.handlers.end() );
}
virtual bool addHandler( TMyEventHandlerPtr eventHandler ) override
{
std::unique_lock<std::shared_mutex> _coreMutexLock( m_core.coreMutex );
if( findEventHandler( eventHandler ) == m_core.handlers.end() )
{
m_core.handlers.push_back( std::move( eventHandler ) );
return true;
}
return false;
}
virtual bool removeHandler( TMyEventHandlerPtr eventHandler ) override
{
std::unique_lock<std::shared_mutex> _coreMutexLock( m_core.coreMutex );
auto it = findEventHandler( eventHandler );
if( it != m_core.handlers.end() )
{
for( TMyHandlerRunner* oneHandlerRunner : m_handlerRunners )
{
if( it == oneHandlerRunner->currentIt )
{
++oneHandlerRunner->currentIt;
oneHandlerRunner->wasRemoving = true;
}
}
m_core.handlers.erase( it );
return true;
}
return false;
}
private:
inline TMyEventHandlerIt findEventHandler( const TMyEventHandlerPtr& eventHandler ) const noexcept
{
return std::find_if( m_core.handlers.cbegin(), m_core.handlers.cend(), [ &eventHandler ]( const TMyEventHandlerPtr& oneHandler )
{
return ( *oneHandler == *eventHandler );
} );
}
EventCore<TParams...> m_core;
std::list<TMyHandlerRunner*> m_handlerRunners;
};
template<class ...TParams>
class TCancelableEvent : public TEvent<TParams..., bool&>
{
using TEventBase = TEvent<TParams..., bool&>;
public:
bool operator()(TParams... params)
{
bool canceled = false;
TEventBase::operator ()(params..., canceled);
return !canceled;
}
};

View File

@ -0,0 +1,34 @@
#pragma once
#include "eventhandlerptr.h"
namespace events::handlers
{
template<class ...TParams>
class AbstractEventHandler
{
using MyType = AbstractEventHandler<TParams...>;
public:
virtual ~AbstractEventHandler() {}
virtual void call(TParams... params) = 0;
bool operator==(const MyType& other) const noexcept
{
return isEquals(other);
}
bool operator!=(const MyType& other) const noexcept
{
return !(*this == other);
}
protected:
AbstractEventHandler() {}
virtual bool isEquals(const MyType& other) const noexcept = 0;
};
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <memory>
namespace events::handlers
{
template<class ...TParams> class AbstractEventHandler;
template<class ...Types>
using TEventHandlerPtr = std::shared_ptr<AbstractEventHandler<Types...>>;
}

View File

@ -0,0 +1,151 @@
#pragma once
#include <memory>
#include <assert.h>
#include "abstracteventhandler.hpp"
#include "helpers/innerholder.hpp"
#include "../helpers/is_equatable.hpp"
namespace events::handlers
{
template<class TFunctor, class ...TParams>
struct IsFunctorParamsCompatible
{
private:
template<class TCheckedFunctor, class ...TCheckedParams>
static constexpr std::true_type exists( decltype( std::declval<TCheckedFunctor>()( std::declval<TCheckedParams>()... ) )* = nullptr ) noexcept;
template<class TCheckedFunctor, class ...TCheckedParams>
static constexpr std::false_type exists( ... ) noexcept;
public:
static constexpr bool value = decltype( exists<TFunctor, TParams...>( nullptr ) )::value;
};
template<class TFunctor> class FunctorHolder;
template<class TFunctor, class ...TParams>
class FunctorEventHandler : public AbstractEventHandler<TParams...>
{
using MyType = FunctorEventHandler<TFunctor, TParams...>;
using TFunctorHolderPtr = std::shared_ptr<FunctorHolder<TFunctor>>;
public:
FunctorEventHandler( TFunctorHolderPtr functorHolder ) :
AbstractEventHandler<TParams...>(),
m_functorHolder( functorHolder )
{
assert( m_functorHolder != nullptr );
}
virtual void call( TParams... params ) override
{
static_assert( IsFunctorParamsCompatible<TFunctor, TParams...>::value, "Event and functor arguments are not compatible" );
m_functorHolder->m_innerHolder.get()( params... );
}
protected:
virtual bool isEquals( const AbstractEventHandler<TParams...>& other ) const noexcept override
{
const MyType* _other = dynamic_cast<const MyType*>( &other );
return ( _other != nullptr && *m_functorHolder == *_other->m_functorHolder );
}
private:
TFunctorHolderPtr m_functorHolder;
};
template<class TEqu, class TEnabled = void>
struct EqualityChecker;
template<class TEquatable>
struct EqualityChecker<TEquatable, typename std::enable_if<is_equatable<TEquatable>::value>::type>
{
static constexpr bool isEquals( const TEquatable& operand1, const TEquatable& operand2 ) noexcept
{
return ( operand1 == operand2 );
}
};
template<class TNonEquatable>
struct EqualityChecker<TNonEquatable, typename std::enable_if<!is_equatable<TNonEquatable>::value>::type>
{
static constexpr bool isEquals( const TNonEquatable& operand1, const TNonEquatable& operand2 ) noexcept
{
return ( &operand1 == &operand2 );
}
};
template<class TFunctor>
class FunctorHolder
{
using MyType = FunctorHolder<TFunctor>;
public:
~FunctorHolder()
{
delete &m_innerHolder;
}
template<class ...TCallParams>
operator TEventHandlerPtr<TCallParams...>()
{
return TEventHandlerPtr<TCallParams...>( new FunctorEventHandler<TFunctor, TCallParams...>( m_me.lock() ) );
}
bool operator==( const MyType& other ) const noexcept
{
return EqualityChecker<TFunctor>::isEquals( m_innerHolder.get(), other.m_innerHolder.get() );
}
bool operator!=( const MyType& other ) const noexcept
{
return !( *this == other );
}
// TFunctor typename is reserved by the enclosing template so need something different
template<class TArgFunctor>
static std::shared_ptr<MyType> create( TArgFunctor&& functor )
{
std::shared_ptr<MyType> result( new MyType( std::forward<TArgFunctor>( functor ) ) );
result->m_me = result;
return result;
}
private:
template<class TArgFunctor>
FunctorHolder( TArgFunctor&& functor ) :
m_innerHolder( createInnerHolder<TFunctor>( std::forward<TArgFunctor>( functor ) ) ),
m_me()
{
}
AbstractInnerHolder<TFunctor>& m_innerHolder;
std::weak_ptr<MyType> m_me;
template<class TArgFunctor, class ...> friend class FunctorEventHandler;
};
template<class TFunctor>
std::shared_ptr<FunctorHolder<typename std::decay<TFunctor>::type>> createFunctorEventHandler( TFunctor&& functor )
{
return FunctorHolder<typename std::decay<TFunctor>::type>::create( std::forward<TFunctor>( functor ) );
}
}
#define FUNCTOR_HANDLER( Functor ) ::events::handlers::createFunctorEventHandler( Functor )
#define LAMBDA_HANDLER( Lambda ) FUNCTOR_HANDLER( Lambda )
#define STD_FUNCTION_HANDLER( StdFunction ) FUNCTOR_HANDLER( StdFunction )
#define FUNCTION_HANDLER( Function ) FUNCTOR_HANDLER( &Function )

View File

@ -0,0 +1,28 @@
#pragma once
#include <memory>
#include "eventhandlerptr.h"
namespace events::handlers
{
template<class TSome>
struct HandlerCast
{
template<class ...Types>
static constexpr TEventHandlerPtr<Types...> cast(TSome& some)
{
return static_cast<TEventHandlerPtr<Types...>>(some);
}
};
template<class TPtr>
struct HandlerCast<std::shared_ptr<TPtr>>
{
template<class ...Types>
static constexpr TEventHandlerPtr<Types...> cast(std::shared_ptr<TPtr> some)
{
return HandlerCast<TPtr>::template cast<Types ...>(*some);
}
};
}

View File

@ -0,0 +1,46 @@
#pragma once
#include "objectsaver.hpp"
namespace events::handlers
{
template<class TBase>
struct AbstractInnerHolder
{
virtual ~AbstractInnerHolder() {}
virtual inline TBase& get() = 0;
inline const TBase& get() const
{
return const_cast<AbstractInnerHolder<TBase>&>(*this).get();
}
};
template<class TBase, class TInner>
struct TInnerHolder : public AbstractInnerHolder<TBase>
{
using TInnerObject = typename ObjectSaver<TInner>::TObject;
TInnerHolder(TInner _inner) :
AbstractInnerHolder<TBase>(),
inner(std::forward<TInner>(_inner))
{ }
virtual inline TBase& get() override
{
return static_cast<TBase&>(inner);
}
TInnerObject inner;
};
template<class TAssignBase, class TArgInner>
AbstractInnerHolder<TAssignBase>& createInnerHolder(TArgInner&& inner)
{
using TAssignInner = decltype(inner);
return *new TInnerHolder<TAssignBase, TAssignInner>(std::forward<TArgInner>(inner));
}
}

View File

@ -0,0 +1,20 @@
#pragma once
namespace events::handlers
{
template<class TSome>
struct ObjectSaver;
template<class LValue>
struct ObjectSaver<LValue&>
{
using TObject = LValue&;
};
template<class RValue>
struct ObjectSaver<RValue&&>
{
using TObject = RValue;
};
}

View File

@ -0,0 +1,130 @@
#pragma once
#include <memory>
#include <assert.h>
#include "abstracteventhandler.hpp"
#include "helpers/innerholder.hpp"
namespace events::handlers
{
template<class TMethodHolder, class ...TParams>
struct IsMethodParamsCompatible
{
private:
template<class TCheckedMethodHolder, class ...TCheckedParams>
static constexpr std::true_type exists( decltype( ( std::declval<TCheckedMethodHolder>().m_innerHolder.get().*std::declval<TCheckedMethodHolder>().m_method )( std::declval<TCheckedParams>()... ) )* = nullptr ) noexcept;
template<class TCheckedMethodHolder, class ...TCheckedParams>
static constexpr std::false_type exists( ... ) noexcept;
public:
static constexpr bool value = decltype( exists<TMethodHolder, TParams...>( nullptr ) )::value;
};
template<class TMethodHolder, class ...TParams>
class MethodEventHandler : public AbstractEventHandler<TParams...>
{
using MyType = MethodEventHandler<TMethodHolder, TParams...>;
using TMethodHolderPtr = std::shared_ptr<TMethodHolder>;
public:
MethodEventHandler( TMethodHolderPtr methodHolder ) :
AbstractEventHandler<TParams...>(),
m_methodHolder( methodHolder )
{
assert( m_methodHolder != nullptr );
}
virtual void call( TParams... params ) override
{
static_assert( IsMethodParamsCompatible<TMethodHolder, TParams...>::value, "Event and method arguments are not compatible" );
( m_methodHolder->m_innerHolder.get().*m_methodHolder->m_method )( params... );
}
protected:
virtual bool isEquals( const AbstractEventHandler<TParams...>& other ) const noexcept override
{
const MyType* _other = dynamic_cast<const MyType*>( &other );
return ( _other != nullptr && *m_methodHolder == *_other->m_methodHolder );
}
private:
TMethodHolderPtr m_methodHolder;
};
template<class TObject, class TResult, class ...TParams>
class MethodHolder
{
using MyType = MethodHolder<TObject, TResult, TParams...>;
using TMethod = TResult( TObject::* )( TParams... );
public:
~MethodHolder()
{
delete &m_innerHolder;
}
template<class ...TCallParams>
operator TEventHandlerPtr<TCallParams...>()
{
return TEventHandlerPtr<TCallParams...>( new MethodEventHandler<MyType, TCallParams...>( m_me.lock() ) );
}
bool operator==( const MyType& other ) const noexcept
{
return ( &m_innerHolder.get() == &other.m_innerHolder.get() && m_method == other.m_method );
}
bool operator!=( const MyType& other ) const noexcept
{
return !( *this == other );
}
// TObject typename is reserved by the enclosing template so need something different
template<class TArgObject>
static std::shared_ptr<MyType> create( TArgObject&& object, TMethod method )
{
std::shared_ptr<MyType> result( new MyType( std::forward<TArgObject>( object ), method ) );
result->m_me = result;
return result;
}
private:
template<class TArgObject>
MethodHolder( TArgObject&& object, TMethod method ) :
m_innerHolder( createInnerHolder<TObject>( std::forward<TArgObject>( object ) ) ),
m_method( method )
{
assert( m_method != nullptr );
}
AbstractInnerHolder<TObject>& m_innerHolder;
TMethod m_method;
std::weak_ptr<MyType> m_me;
template<class TMethodHolder, class ...> friend class MethodEventHandler;
template<class TMethodHolder, class ...> friend struct IsMethodParamsCompatible;
};
template<class TObject, class TResult, class ...TParams>
std::shared_ptr<MethodHolder<std::decay_t<TObject>, TResult, TParams...>> createMethodEventHandler( TObject&& object, TResult( std::decay<TObject>::type::*method )( TParams... ) )
{
return MethodHolder<std::decay_t<TObject>, TResult, TParams...>::create( std::forward<TObject>( object ), method );
}
}
#define METHOD_HANDLER( Object, Method ) ::events::handlers::createMethodEventHandler( Object, &Method )
#define MY_METHOD_HANDLER( Method ) METHOD_HANDLER( *this, Method )

View File

@ -0,0 +1,20 @@
#pragma once
#include <type_traits>
template<class T>
class is_equatable
{
private:
template<class U>
static constexpr std::true_type exists( decltype( std::declval<U>() == std::declval<U>() )* = nullptr ) noexcept;
template<class U>
static constexpr std::false_type exists( ... ) noexcept;
public:
static constexpr bool value = decltype( exists<T>( nullptr ) )::value;
};

View File

@ -0,0 +1,9 @@
#include "abstracteventjoin.h"
namespace events::joins
{
AbstractEventJoin::AbstractEventJoin() {}
AbstractEventJoin::~AbstractEventJoin() {}
}

View File

@ -0,0 +1,20 @@
#pragma once
namespace events::joins
{
class AbstractEventJoin
{
public:
virtual ~AbstractEventJoin();
virtual bool isJoined() const = 0;
virtual bool join() = 0;
virtual bool unjoin() = 0;
protected:
AbstractEventJoin();
};
}

View File

@ -0,0 +1,62 @@
#include "eventjoinwrapper.h"
#include <type_traits>
#include "abstracteventjoin.h"
namespace events::joins
{
constexpr EventJoinWrapper::EventJoinWrapper() noexcept :
m_eventJoin( nullptr )
{ }
EventJoinWrapper::EventJoinWrapper( EventJoinWrapper&& other ) noexcept :
m_eventJoin( std::move( other.m_eventJoin ) )
{ }
EventJoinWrapper::EventJoinWrapper( EventJoinWrapper& other ) noexcept :
m_eventJoin( other.m_eventJoin )
{ }
EventJoinWrapper& EventJoinWrapper::operator=( EventJoinWrapper&& other ) noexcept
{
m_eventJoin = std::move( other.m_eventJoin );
return *this;
}
EventJoinWrapper& EventJoinWrapper::operator=( const EventJoinWrapper& other ) noexcept
{
m_eventJoin = other.m_eventJoin;
return *this;
}
EventJoinWrapper::operator bool() const
{
return isJoined();
}
bool EventJoinWrapper::isAssigned() const
{
return ( m_eventJoin != nullptr );
}
bool EventJoinWrapper::isJoined() const
{
return ( m_eventJoin != nullptr && m_eventJoin->isJoined() );
}
bool EventJoinWrapper::join()
{
return ( m_eventJoin != nullptr ? m_eventJoin->join() : false );
}
bool EventJoinWrapper::unjoin()
{
return ( m_eventJoin != nullptr ? m_eventJoin->unjoin() : false );
}
} // events

View File

@ -0,0 +1,44 @@
#pragma once
#include <memory>
#include "../handlers/eventhandlerptr.h"
template<class ...TParams> class IEvent;
namespace events::joins
{
class AbstractEventJoin;
class EventJoinWrapper
{
public:
template<class TSome, class ...TParams>
inline EventJoinWrapper(IEvent<TParams...>& _event, TSome&& handler);
constexpr EventJoinWrapper() noexcept;
EventJoinWrapper(EventJoinWrapper&& other) noexcept;
EventJoinWrapper(EventJoinWrapper& other) noexcept;
EventJoinWrapper& operator=(EventJoinWrapper&& other) noexcept;
EventJoinWrapper& operator=(const EventJoinWrapper& other) noexcept;
operator bool() const;
bool isAssigned() const;
bool isJoined() const;
bool join();
bool unjoin();
private:
std::shared_ptr<AbstractEventJoin> m_eventJoin;
};
}
namespace events
{
using EventJoin = joins::EventJoinWrapper;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "eventjoinwrapper.h"
#include "handlereventjoin.h"
#include "../handlers/handlercast.hpp"
namespace events::joins
{
template<class TSome, class ...TParams>
EventJoinWrapper::EventJoinWrapper( IEvent<TParams...>& _event, TSome&& handler ) :
m_eventJoin( std::make_shared<HandlerEventJoin<TParams...>>( _event, ::events::handlers::HandlerCast<TSome>::template cast<TParams...>( handler ) ) )
{ }
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "abstracteventjoin.h"
#include "../handlers/eventhandlerptr.h"
template<class ...TParams> class IEvent;
namespace events::joins
{
template<class ...TParams>
class HandlerEventJoin : public AbstractEventJoin
{
public:
HandlerEventJoin(IEvent<TParams...>& _event, ::events::handlers::TEventHandlerPtr<TParams...> handler) :
AbstractEventJoin(),
m_event(_event),
m_handler(handler)
{ }
virtual inline bool isJoined() const override;
virtual inline bool join() override;
virtual inline bool unjoin() override;
private:
IEvent<TParams...>& m_event;
::events::handlers::TEventHandlerPtr<TParams...> m_handler;
};
}

View File

@ -0,0 +1,26 @@
#pragma once
#include "handlereventjoin.h"
#include "../event.hpp"
namespace events::joins
{
template<class ...TParams>
bool HandlerEventJoin<TParams...>::isJoined() const
{
return m_event.isHandlerAdded(m_handler);
}
template<class ...TParams>
bool HandlerEventJoin<TParams...>::join()
{
return m_event.addHandler(m_handler);
}
template<class ...TParams>
bool HandlerEventJoin<TParams...>::unjoin()
{
return m_event.removeHandler(m_handler);
}
}

View File

@ -0,0 +1,10 @@
#include <pch.h>
#include "globals.h"
namespace events
{
TCancelableEvent<short> KeyUpEvent{};
TCancelableEvent<HWND, UINT, WPARAM, LPARAM> WndProcEvent {};
TEvent<> RenderEvent {};
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <Windows.h>
#include <cheat-base/events/event.hpp>
namespace events
{
extern TCancelableEvent<short> KeyUpEvent;
extern TCancelableEvent<HWND, UINT, WPARAM, LPARAM> WndProcEvent;
extern TEvent<> RenderEvent;
}

View File

@ -0,0 +1,54 @@
#include <pch.h>
#include "ImageLoader.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <cheat-base/util.h>
#include <cheat-base/render/backend/dx11-hook.h>
#include <cheat-base/ResourceLoader.h>
std::optional<ImageLoader::ImageData> ImageLoader::GetImage(const std::string& imageName, const char* type)
{
if (s_Textures.count(imageName) > 0)
return s_Textures[imageName];
LPBYTE pDestination;
DWORD size;
bool loadResult = ResourceLoader::LoadEx(imageName.c_str(), type, pDestination, size);
if (!loadResult)
{
// LOG_WARNING("Failed to load image: %s from resources", imageName);
return {};
}
// Load from disk into a raw RGBA buffer
int image_width = 0;
int image_height = 0;
unsigned char* image_data = stbi_load_from_memory(pDestination, size, &image_width, &image_height, NULL, 4);
if (image_data == NULL)
{
// LOG_WARNING("Failed to convert image '%s' to RGBA by 'stb_image.h'", imageName.c_str());
return {};
}
ImageLoader::ImageData imageData = {};
ID3D11ShaderResourceView* new_texture = NULL;
int width, height;
bool textureResult = backend::LoadTextureFromMemory(image_data, image_width, image_height,
reinterpret_cast<ID3D11ShaderResourceView**>(&imageData.textureID), &width, &height);
stbi_image_free(image_data);
if (!textureResult)
{
// LOG_WARNING("Failed to load texture by DX11 for image: %s", imageName.c_str());
return {};
}
imageData.size.x = width;
imageData.size.y = height;
s_Textures[imageName] = imageData;
return imageData;
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <string>
#include <map>
#include <optional>
#include <Windows.h>
#include <imgui.h>
class ImageLoader
{
public:
struct ImageData
{
ImTextureID textureID;
ImVec2 size;
};
static std::optional<ImageData> GetImage(const std::string& imageName, const char* imageType = "PNG");
private:
inline static std::map<std::string, ImageData> s_Textures {};
};

View File

@ -0,0 +1,141 @@
#include <pch.h>
#include "dx11-hook.h"
#include <cstdio>
#include <cheat-base/HookManager.h>
#pragma comment(lib, "D3dcompiler.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "winmm.lib")
// D3X HOOK DEFINITIONS
typedef HRESULT(__stdcall* IDXGISwapChainPresent)(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);
// Definition of WndProc Hook. Its here to avoid dragging dependencies on <windows.h> types.
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static IDXGISwapChainPresent fnIDXGISwapChainPresent;
static ID3D11Device* pDevice = nullptr;
static HRESULT __stdcall Present(IDXGISwapChain* pChain, const UINT SyncInterval, const UINT Flags)
{
static BOOL g_bInitialised = false;
// Main D3D11 Objects
static ID3D11DeviceContext* pContext = nullptr;
if (!g_bInitialised) {
pChain->GetDevice(__uuidof(pDevice), reinterpret_cast<void**>(&pDevice));
pDevice->GetImmediateContext(&pContext);
DXGI_SWAP_CHAIN_DESC sd;
pChain->GetDesc(&sd);
backend::DX11Events::InitializeEvent(sd.OutputWindow, pDevice, pContext, pChain);
g_bInitialised = true;
}
// render function
backend::DX11Events::RenderEvent(pContext);
return CALL_ORIGIN(Present, pChain, SyncInterval, Flags);
}
static IDXGISwapChainPresent findDirect11Present()
{
const HWND hWnd = GetForegroundWindow();
IDXGISwapChain* pSwapChain;
constexpr D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hWnd;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = TRUE; //((GetWindowLong(hWnd, GWL_STYLE) & WS_POPUP) != 0) ? FALSE : TRUE;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
// Main D3D11 Objects
ID3D11DeviceContext* pContext = nullptr;
ID3D11Device* pDevice = nullptr;
if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL, NULL, &featureLevel, 1,
D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pDevice, NULL, &pContext)) &&
FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, &featureLevel, 1,
D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pDevice, NULL, &pContext)))
{
return nullptr;
}
const DWORD_PTR* pSwapChainVtable = reinterpret_cast<DWORD_PTR*>(pSwapChain);
pSwapChainVtable = reinterpret_cast<DWORD_PTR*>(pSwapChainVtable[0]);
auto swapChainPresent = reinterpret_cast<IDXGISwapChainPresent>(pSwapChainVtable[8]);
pDevice->Release();
pContext->Release();
pSwapChain->Release();
return swapChainPresent;
}
void backend::InitializeDX11Hooks()
{
LOG_DEBUG("Initializing D3D11 hook: started.");
fnIDXGISwapChainPresent = findDirect11Present();
if (fnIDXGISwapChainPresent == nullptr)
{
LOG_ERROR("Failed to find 'Present' function for D3D11.");
return;
}
LOG_DEBUG("SwapChain Present: %p", fnIDXGISwapChainPresent);
HookManager::install(fnIDXGISwapChainPresent, Present);
LOG_DEBUG("Initializing D3D11 hook: done.");
}
bool backend::LoadTextureFromMemory(LPBYTE image_data, int image_width, int image_height, ID3D11ShaderResourceView** out_srv, int* out_width, int* out_height)
{
if (pDevice == nullptr)
return false;
// Create texture
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = image_width;
desc.Height = image_height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D11Texture2D* pTexture = NULL;
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = image_data;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
pDevice->CreateShaderResourceView(pTexture, &srvDesc, out_srv);
pTexture->Release();
*out_width = image_width;
*out_height = image_height;
return true;
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <Windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <cheat-base/events/event.hpp>
namespace backend
{
void InitializeDX11Hooks();
// Thanks to https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples#example-for-directx11-users
bool LoadTextureFromMemory(LPBYTE image_data, int image_width, int image_height, ID3D11ShaderResourceView** out_srv, int* out_width, int* out_height);
class DX11Events
{
public:
inline static TEvent<ID3D11DeviceContext*> RenderEvent{};
inline static TEvent<HWND, ID3D11Device*, ID3D11DeviceContext*, IDXGISwapChain*> InitializeEvent{};
};
}

View File

@ -0,0 +1,740 @@
#include <pch.h>
#include "gui-util.h"
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui_internal.h"
#include <imgui.h>
#include <misc/cpp/imgui_stdlib.h>
#include <cheat-base/util.h>
#include <shellapi.h>
void ShowHelpText(const char* text)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(text);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
void HelpMarker(const char* desc)
{
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered())
ShowHelpText(desc);
}
bool InputHotkey(const char* label, Hotkey* hotkey, bool clearable)
{
char hotkeyBuffer[50];
auto hotkeyString = std::string(*hotkey);
memcpy(hotkeyBuffer, hotkeyString.c_str(), hotkeyString.size() + 1);
bool changed = false;
if (clearable) {
char labelBuffer[128];
std::snprintf(labelBuffer, 128, "Clear ## %s_1", label);
if (ImGui::Button(labelBuffer, ImVec2(75, 0)))
{
*hotkey = Hotkey();
changed = true;
}
ImGui::SameLine();
}
changed = ImGui::HotkeyWidget(label, *hotkey, ImVec2(200, 0)) || changed;
return changed;
}
float CalcWidth(const std::string_view& view)
{
ImGuiContext& g = *GImGui;
return ImGui::CalcTextSize(view.data()).x + g.Style.FramePadding.x * 2.0f + 25.0f;
}
#define END_TYPE_WIDGET() \
if (desc != nullptr) { ImGui::SameLine(); HelpMarker(desc); } \
return result;
#define END_CONFIG_WIDGET() if (result) field.FireChanged(); return result;
bool TypeWidget(const char* label, bool& value, const char* desc)
{
bool result = ImGui::Checkbox(label, &value);
END_TYPE_WIDGET();
}
bool TypeWidget(const char* label, int& value, int step, int start, int end, const char* desc)
{
bool result = false;
if (start == end)
result = ImGui::InputInt(label, &value, step);
else
result = ImGui::DragInt(label, &value, (float)step, start, end);
END_TYPE_WIDGET();
}
bool TypeWidget(const char* label, float& value, float step, float start, float end, const char* desc)
{
bool result = false;
if (start == end)
result = ImGui::InputFloat(label, &value, step);
else
result = ImGui::DragFloat(label, &value, step, start, end);
END_TYPE_WIDGET();
}
bool TypeWidget(const char* label, Hotkey& value, bool clearable, const char* desc)
{
bool result = InputHotkey(label, &value, clearable);
END_TYPE_WIDGET();
}
bool TypeWidget(const char* label, std::string& value, const char* desc)
{
bool result = ImGui::InputText(label, &value);
END_TYPE_WIDGET();
}
bool TypeWidget(const char* label, ImColor& value, const char* desc)
{
bool result = ImGui::ColorEdit4(label, reinterpret_cast<float*>(&value));
END_TYPE_WIDGET();
}
bool TypeWidget(const char* label, config::Toggle<Hotkey>& value, const char* desc, bool hotkey)
{
bool result = hotkey ? InputHotkey(label, &value.value, true) : ImGui::Checkbox(label, &value.enabled);
END_TYPE_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<bool>& field, const char* desc)
{
bool result = TypeWidget(label, field.value(), desc);
END_CONFIG_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<int>& field, int step, int start, int end, const char* desc)
{
bool result = TypeWidget(label, field.value(), step, start, end, desc);
END_CONFIG_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<float>& field, float step, float start, float end, const char* desc)
{
bool result = TypeWidget(label, field.value(), step, start, end, desc);
END_CONFIG_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<Hotkey>& field, bool clearable, const char* desc)
{
bool result = TypeWidget(label, field.value(), clearable, desc);
END_CONFIG_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<std::string>& field, const char* desc)
{
bool result = TypeWidget(label, field.value(), desc);
END_CONFIG_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<ImColor>& field, const char* desc /*= nullptr*/)
{
bool result = TypeWidget(label, field.value(), desc);
END_CONFIG_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<config::Toggle<float>>& field, float step, float start, float end,
const char* desc, bool hotkey)
{
ImGui::PushID(&label);
bool result = TypeWidget("", field.value().enabled);
ImGui::SameLine();
result |= TypeWidget(label, field.value().value, step, start, end, desc);
ImGui::PopID();
END_CONFIG_WIDGET();
}
bool ConfigWidget(const char* label, config::Field<config::Toggle<Hotkey>>& field, const char* desc /*= nullptr*/, bool hotkey /*= false*/)
{
bool result = TypeWidget(label, field.value(), desc, hotkey);
END_CONFIG_WIDGET();
}
bool ConfigWidget(config::Field<bool>& field, const char* desc)
{
return ConfigWidget(field.friendName().c_str(), field, desc);
}
bool ConfigWidget(config::Field<int>& field, int step, int start, int end, const char* desc)
{
return ConfigWidget(field.friendName().c_str(), field, step, start, end, desc);
}
bool ConfigWidget(config::Field<float>& field, float step, float start, float end, const char* desc)
{
return ConfigWidget(field.friendName().c_str(), field, step, start, end, desc);
}
bool ConfigWidget(config::Field<Hotkey>& field, bool clearable, const char* desc)
{
return ConfigWidget(field.friendName().c_str(), field, clearable, desc);
}
bool ConfigWidget(config::Field<std::string>& field, const char* desc)
{
return ConfigWidget(field.friendName().c_str(), field, desc);
}
bool ConfigWidget(config::Field<ImColor>& field, const char* desc /*= nullptr*/)
{
return ConfigWidget(field.friendName().c_str(), field, desc);
}
bool ConfigWidget(config::Field<config::Toggle<float>>& field, float step, float start, float end, const char* desc)
{
return ConfigWidget(field.friendName().c_str(), field, step, start, end, desc);
}
bool ConfigWidget(config::Field<config::Toggle<Hotkey>>& field, const char* desc /*= nullptr*/, bool hotkey /*= false*/)
{
return ConfigWidget(field.friendName().c_str(), field, desc, hotkey);
}
#undef ShowDesc
// https://github.com/ocornut/imgui/issues/1496#issuecomment-655048353
struct GroupPanelInfo
{
ImRect labelRect;
ImRect selectRect;
};
static ImVector<GroupPanelInfo> s_GroupPanelLabelStack;
bool GroupPanelIsOpen(ImGuiID id)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStorage* storage = window->DC.StateStorage;
return storage->GetInt(id, 1) != 0;
}
void GroupPanelSetOpen(ImGuiID id, bool open)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStorage* storage = window->DC.StateStorage;
storage->SetInt(id, open ? 1 : 0);
}
bool BeginGroupPanel(const char* name, const ImVec2& size, bool node, SelectData* selectData)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGui::PushID(name);
ImGui::BeginGroup();
auto cursorPos = ImGui::GetCursorScreenPos();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
ImGui::BeginGroup();
ImVec2 effectiveSize = size;
if (size.x < 0.0f)
effectiveSize.x = ImGui::GetContentRegionAvail().x;
else
effectiveSize.x = size.x;
ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f));
ImVec2 startPos = window->DC.CursorPos;
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::SameLine(0.0f, 0.0f);
ImGui::BeginGroup();
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::SameLine(0.0f, 0.0f);
ImGui::TextUnformatted(name);
auto labelMin = ImGui::GetItemRectMin();
auto labelMax = ImGui::GetItemRectMax();
ImGui::SameLine(0.0f, 0.0f);
ImVec2 selectMin = {};
ImVec2 selectMax = {};
if (selectData != nullptr)
{
bool useText = true;
const char* selectAll = "Select all";
auto textSize = ImGui::CalcTextSize(selectAll);
auto spaceSize = ImVec2(effectiveSize.x - textSize.x - 35.0f - labelMax.x + startPos.x, 0.0f);
if (spaceSize.x <= 0)
{
spaceSize = ImVec2(effectiveSize.x - 35.0f - labelMax.x + startPos.x, 0.0f);
useText = false;
}
ImGui::Dummy(spaceSize);
ImGui::SameLine(0.0f, 0.0f);
selectData->changed = ImGui::Checkbox(useText ? selectAll : "", &selectData->toggle);
selectMin = ImGui::GetItemRectMin();
selectMax = ImGui::GetItemRectMax();
}
ImGui::SameLine(0.0f, 0.0f);
ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y));
if (node)
{
labelMin.x = startPos.x;
const ImVec2 text_size = ImGui::CalcTextSize(name);
const ImGuiID id = window->GetID(name);
bool isOpen = GroupPanelIsOpen(id);
bool hovered;
bool toggled = ImGui::ButtonBehavior({ labelMin, labelMax }, id, &hovered, nullptr, ImGuiButtonFlags_PressedOnClick);
if (toggled)
{
isOpen = !isOpen;
GroupPanelSetOpen(id, isOpen);
}
const ImU32 text_col = ImGui::GetColorU32(ImGuiCol_Text);
ImGui::RenderArrow(window->DrawList, { cursorPos.x, cursorPos.y + text_size.y * 0.15f }, text_col,
isOpen ? ImGuiDir_Down : ImGuiDir_Right, 0.7f);
if (!isOpen)
{
ImGui::PopStyleVar(2);
ImGui::EndGroup();
ImGui::EndGroup();
ImGui::EndGroup();
ImGui::PopID();
return false;
}
}
ImGui::BeginGroup();
//ImGui::GetWindowDrawList()->AddRect(labelMin, labelMax, IM_COL32(255, 0, 255, 255));
ImGui::PopStyleVar(2);
#if IMGUI_VERSION_NUM >= 17301
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f;
ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f;
ImGui::GetCurrentWindow()->InnerRect.Max.x -= frameHeight * 0.5f;
#else
ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x -= frameHeight * 0.5f;
#endif
ImGui::GetCurrentWindow()->Size.x -= frameHeight;
auto itemWidth = ImGui::CalcItemWidth();
ImGui::PushItemWidth(ImMax(0.0f, itemWidth - frameHeight));
s_GroupPanelLabelStack.push_back({ ImRect(labelMin, labelMax) , ImRect(selectMin, selectMax)});
return true;
}
void EndGroupPanel()
{
ImGui::PopItemWidth();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
ImGui::EndGroup();
//ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(0, 255, 0, 64), 4.0f);
ImGui::EndGroup();
ImGui::SameLine(0.0f, 0.0f);
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::Dummy(ImVec2(0.0, frameHeight - frameHeight * 0.5f - itemSpacing.y));
ImGui::EndGroup();
auto itemMin = ImGui::GetItemRectMin();
auto itemMax = ImGui::GetItemRectMax();
//ImGui::GetWindowDrawList()->AddRectFilled(itemMin, itemMax, IM_COL32(255, 0, 0, 64), 4.0f);
auto& info = s_GroupPanelLabelStack.back();
s_GroupPanelLabelStack.pop_back();
ImVec2 halfFrame = ImVec2(frameHeight * 0.25f, frameHeight) * 0.5f;
ImRect frameRect = ImRect(itemMin + halfFrame, itemMax - ImVec2(halfFrame.x, 0.0f));
auto& labelRect = info.labelRect;
labelRect.Min.x -= itemSpacing.x;
labelRect.Max.x += itemSpacing.x;
bool hasSelect = info.selectRect.Min.x != 0;
if (!hasSelect)
{
for (int i = 0; i < 3; ++i)
{
switch (i)
{
// left half-plane
case 0: ImGui::PushClipRect(ImVec2(-FLT_MAX, -FLT_MAX), ImVec2(labelRect.Min.x, FLT_MAX), true); break;
// right half-plane
case 1: ImGui::PushClipRect(ImVec2(labelRect.Max.x, -FLT_MAX), ImVec2(FLT_MAX, FLT_MAX), true); break;
// bottom
case 2: ImGui::PushClipRect(ImVec2(labelRect.Min.x, labelRect.Max.y), ImVec2(labelRect.Max.x, FLT_MAX), true); break;
}
ImGui::GetWindowDrawList()->AddRect(
frameRect.Min, frameRect.Max,
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Border)),
halfFrame.x);
ImGui::PopClipRect();
}
}
else
{
auto& selectRect = info.selectRect;
selectRect.Min.x -= itemSpacing.x;
selectRect.Max.x += itemSpacing.x;
for (int i = 0; i < 5; ++i)
{
switch (i)
{
// left half-plane
case 0: ImGui::PushClipRect(ImVec2(-FLT_MAX, -FLT_MAX), ImVec2(labelRect.Min.x, FLT_MAX), true); break;
// label - select
case 1: ImGui::PushClipRect(ImVec2(labelRect.Max.x, -FLT_MAX), ImVec2(selectRect.Min.x, FLT_MAX), true); break;
// bottom label
case 2: ImGui::PushClipRect(ImVec2(labelRect.Min.x, labelRect.Max.y), ImVec2(labelRect.Max.x, FLT_MAX), true); break;
// bottom select
case 3: ImGui::PushClipRect(ImVec2(selectRect.Min.x, selectRect.Max.y), ImVec2(selectRect.Max.x, FLT_MAX), true); break;
// right hand-plane
case 4: ImGui::PushClipRect(ImVec2(selectRect.Max.x, -FLT_MAX), ImVec2(FLT_MAX, FLT_MAX), true); break;
}
ImGui::GetWindowDrawList()->AddRect(
frameRect.Min, frameRect.Max,
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Border)),
halfFrame.x);
ImGui::PopClipRect();
}
}
ImGui::PopStyleVar(2);
#if IMGUI_VERSION_NUM >= 17301
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f;
ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f;
ImGui::GetCurrentWindow()->InnerRect.Max.x += frameHeight * 0.5f;
#else
ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x += frameHeight * 0.5f;
#endif
ImGui::GetCurrentWindow()->Size.x += frameHeight;
ImGui::Dummy(ImVec2(0.0f, 0.0f));
ImGui::EndGroup();
ImGui::PopID();
}
void AddUnderLine(ImColor col_)
{
ImVec2 min = ImGui::GetItemRectMin();
ImVec2 max = ImGui::GetItemRectMax();
min.y = max.y;
ImGui::GetWindowDrawList()->AddLine(min, max, col_, 1.0f);
}
void TextURL(const char* name_, const char* URL_, bool SameLineBefore_, bool SameLineAfter_)
{
if (SameLineBefore_) { ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); }
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered]);
ImGui::Text(name_);
ImGui::PopStyleColor();
if (ImGui::IsItemHovered())
{
if (ImGui::IsMouseClicked(0))
{
ShellExecute(0, 0, URL_, 0, 0, SW_SHOW);
}
AddUnderLine(ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered]);
ImGui::SetTooltip("Open in browser\n%s", URL_);
}
else
{
AddUnderLine(ImGui::GetStyle().Colors[ImGuiCol_Button]);
}
if (SameLineAfter_) { ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); }
}
bool operator&(OutlineSide lhs, OutlineSide rhs) {
return
static_cast<std::underlying_type<OutlineSide>::type>(lhs) &
static_cast<std::underlying_type<OutlineSide>::type>(rhs);
}
void DrawTextWithOutline(ImDrawList* drawList, ImFont* font, float fontSize, const ImVec2& screenPos,
const char* text, const ImColor& textColor, float outlineThickness, OutlineSide sides, const ImColor& outlineColor)
{
if (outlineThickness == 0.0f)
{
drawList->AddText(font, fontSize, screenPos, outlineColor, text);
}
else
{
if (sides & OutlineSide::Left)
drawList->AddText(font, fontSize,
{ screenPos.x - outlineThickness, screenPos.y }, outlineColor, text);
if (sides & OutlineSide::Right)
drawList->AddText(font, fontSize,
{ screenPos.x + outlineThickness, screenPos.y }, outlineColor, text);
if (sides & OutlineSide::Bottom)
drawList->AddText(font, fontSize,
{ screenPos.x, screenPos.y - outlineThickness }, outlineColor, text);
if (sides & OutlineSide::Top)
drawList->AddText(font, fontSize,
{ screenPos.x, screenPos.y + outlineThickness }, outlineColor, text);
}
drawList->AddText(font, fontSize, screenPos, textColor, text);
}
void DrawTextWithOutline(ImDrawList* drawList, const ImVec2& screenPos, const char* text, const ImColor& textColor,
float outlineThickness, OutlineSide sides, const ImColor& outlineColor)
{
DrawTextWithOutline(drawList, nullptr, 0.0f, screenPos, text, textColor, outlineThickness, sides, outlineColor);
}
// Modified version of: https://github.com/spirthack/CSGOSimple/blob/master/CSGOSimple/UI.cpp#L287
bool ImGui::HotkeyWidget(const char* label, Hotkey& hotkey, const ImVec2& size)
{
// Init ImGui
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
const ImVec2 item_size = ImGui::CalcItemSize(size, ImGui::CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + item_size);
const ImRect total_bb(window->DC.CursorPos, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
ImGui::ItemSize(total_bb, style.FramePadding.y);
if (!ImGui::ItemAdd(total_bb, id))
return false;
const bool focus_requested = (ImGui::GetItemStatusFlags() & ImGuiItemStatusFlags_FocusedByTabbing) != 0 || g.NavActivateInputId == id;
const bool hovered = ImGui::ItemHoverable(frame_bb, id);
if (hovered)
{
ImGui::SetHoveredID(id);
g.MouseCursor = ImGuiMouseCursor_TextInput;
}
static Hotkey _initHotkey;
static Hotkey _currHotkey;
static Hotkey _prevHotkey;
const bool user_clicked = hovered && io.MouseClicked[0];
if (focus_requested || user_clicked)
{
if (g.ActiveId != id)
{
memset(io.MouseDown, 0, sizeof(io.MouseDown));
memset(io.KeysDown, 0, sizeof(io.KeysDown));
_initHotkey = hotkey;
_currHotkey = Hotkey();
_prevHotkey = Hotkey();
}
ImGui::SetActiveID(id, window);
ImGui::FocusWindow(window);
}
else if (io.MouseClicked[0] && g.ActiveId == id)
{
ImGui::ClearActiveID();
}
bool valueChanged = false;
if (g.ActiveId == id)
{
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
{
ImGui::ClearActiveID();
if (hotkey != _initHotkey)
{
hotkey = _initHotkey;
valueChanged = true;
}
}
else
{
ImGui::NavMoveRequestCancel();
auto newHotkey = Hotkey::GetPressedHotkey();
if (newHotkey.IsEmpty() && !_currHotkey.IsEmpty())
{
ImGui::ClearActiveID();
valueChanged = false;
}
else if (newHotkey - _prevHotkey)
{
_currHotkey = newHotkey;
hotkey = newHotkey;
valueChanged = true;
}
_prevHotkey = newHotkey;
}
}
// Render
// Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is Set 'buf' might still be the old value. We Set buf to NULL to prevent accidental usage from now on.
char buf_display[128] = "Empty";
const ImU32 frame_col = ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
ImGui::RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
if ((g.ActiveId == id && !_currHotkey.IsEmpty()) || g.ActiveId != id)
strcpy_s(buf_display, static_cast<std::string>(hotkey).c_str());
else if (g.ActiveId == id)
strcpy_s(buf_display, "<Press a key>");
const ImRect clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + item_size.x, frame_bb.Min.y + item_size.y); // Not using frame_bb.Max because we have adjusted size
ImVec2 render_pos = frame_bb.Min + style.FramePadding;
ImGui::RenderTextClipped(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding, buf_display, NULL, NULL, style.ButtonTextAlign, &clip_rect);
//RenderTextClipped(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding, buf_display, NULL, NULL, GetColorU32(ImGuiCol_Text), style.ButtonTextAlign, &clip_rect);
//draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, NULL, 0.0f, &clip_rect);
if (label_size.x > 0)
ImGui::RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
return valueChanged;
}
// https://github.com/ocornut/imgui/issues/3798
float ImGui::CalcContrastRatio(const ImU32& backgroundColor, const ImU32& foreGroundColor)
{
// real code https://www.w3.org/TR/WCAG20/#relativeluminancedef
/*const auto colBG = ImGui::ColorConvertU32ToFloat4(backgroundColor);
const auto colFG = ImGui::ColorConvertU32ToFloat4(foreGroundColor);
float lumBG = 0.2126 * colBG.x + 0.7152 * colBG.y + 0.0722 * colBG.z;
float lumFG = 0.2126 * colFG.x + 0.7152 * colFG.y + 0.0722 * colFG.z;
return (ImMax(lumBG, lumFG) + 0.05) / (ImMin(lumBG, lumFG) + 0.05);*/
float sa0 = ((backgroundColor >> IM_COL32_A_SHIFT) & 0xFF);
float sa1 = ((foreGroundColor >> IM_COL32_A_SHIFT) & 0xFF);
static float sr = 0.2126f / 255.0f;
static float sg = 0.7152f / 255.0f;
static float sb = 0.0722f / 255.0f;
const float contrastRatio =
(sr * sa0 * ((backgroundColor >> IM_COL32_R_SHIFT) & 0xFF) +
sg * sa0 * ((backgroundColor >> IM_COL32_G_SHIFT) & 0xFF) +
sb * sa0 * ((backgroundColor >> IM_COL32_B_SHIFT) & 0xFF) + 0.05f) /
(sr * sa1 * ((foreGroundColor >> IM_COL32_R_SHIFT) & 0xFF) +
sg * sa1 * ((foreGroundColor >> IM_COL32_G_SHIFT) & 0xFF) +
sb * sa1 * ((foreGroundColor >> IM_COL32_B_SHIFT) & 0xFF) + 0.05f);
if (contrastRatio < 1.0f)
return 1.0f / contrastRatio;
return contrastRatio;
}
ImColor ImGui::CalcContrastColor(const ImColor& foreground, float maxContrastRatio, const ImColor& background, const ImColor& inverted)
{
return ImGui::CalcContrastRatio(background, foreground) < maxContrastRatio ? inverted : background;
}
bool ImGui::PushStyleColorWithContrast(ImU32 backGroundColor, ImGuiCol foreGroundColor, ImU32 invertedColor, float maxContrastRatio)
{
const float contrastRatio = CalcContrastRatio(backGroundColor, GetColorU32(foreGroundColor));
if (contrastRatio < maxContrastRatio)
{
ImGui::PushStyleColor(foreGroundColor, invertedColor);
return true;
}
return false;
}
static std::string nameBuffer;
void ImGui::OpenRenamePopup(const std::string& initName)
{
ImGui::OpenPopup("RenamePopup");
if (IsRenamePopupOpened())
nameBuffer = initName;
}
bool ImGui::IsRenamePopupOpened()
{
return ImGui::IsPopupOpen("RenamePopup");
}
bool ImGui::DrawRenamePopup(std::string& out)
{
if (ImGui::BeginPopup("RenamePopup", ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("To save press `Enter`.\nTo close without saving press `Esc`.");
if (!ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0))
ImGui::SetKeyboardFocusHere(0);
ImGui::InputText("Name", &nameBuffer);
bool changed = false;
if (ImGui::IsKeyPressed(ImGuiKey_Enter, false))
{
changed = true;
out = nameBuffer;
ImGui::CloseCurrentPopup();
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape, false))
{
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
return changed;
}
return false;
}

View File

@ -0,0 +1,163 @@
#pragma once
#include <imgui.h>
#include <filesystem>
#include <cheat-base/config/config.h>
#include <cheat-base/Hotkey.h>
#include <cheat-base/config/fields/Toggle.h>
#include <cheat-base/config/fields/Enum.h>
#define BLOCK_FOCUS()
bool TypeWidget(const char* label, bool& value, const char* desc = nullptr);
bool TypeWidget(const char* label, int& value, int step = 1, int start = 0, int end = 0, const char* desc = nullptr);
bool TypeWidget(const char* label, float& value, float step = 1.0F, float start = 0, float end = 0, const char* desc = nullptr);
bool TypeWidget(const char* label, Hotkey& value, bool clearable = true, const char* desc = nullptr);
bool TypeWidget(const char* label, std::string& value, const char* desc = nullptr);
bool TypeWidget(const char* label, ImColor& value, const char* desc = nullptr);
bool TypeWidget(const char* label, config::Toggle<Hotkey>& value, const char* desc = nullptr, bool hotkey = false);
bool ConfigWidget(const char* label, config::Field<bool>& field, const char* desc = nullptr);
bool ConfigWidget(const char* label, config::Field<int>& field, int step = 1, int start = 0, int end = 0, const char* desc = nullptr);
bool ConfigWidget(const char* label, config::Field<float>& field, float step = 1.0F, float start = 0, float end = 0, const char* desc = nullptr);
bool ConfigWidget(const char* label, config::Field<Hotkey>& field, bool clearable = true, const char* desc = nullptr);
bool ConfigWidget(const char* label, config::Field<std::string>& field, const char* desc = nullptr);
bool ConfigWidget(const char* label, config::Field<ImColor>& field, const char* desc = nullptr);
template<typename T>
bool ConfigWidget(const char* label, config::Field<config::Toggle<T>>& field, const char* desc = nullptr)
{
ImGui::PushID(&field);
bool result = TypeWidget("", field.value().enabled);
ImGui::SameLine();
result |= TypeWidget(label, field.value().value, desc);
ImGui::PopID();
if (result)
field.FireChanged();
return result;
}
bool ConfigWidget(const char* label, config::Field<config::Toggle<float>>& field, float step = 1.0F, float start = 0, float end = 0, const char* desc = nullptr, bool hotkey = false);
bool ConfigWidget(const char* label, config::Field<config::Toggle<Hotkey>>& field, const char* desc = nullptr, bool hotkey = false);
bool ConfigWidget(config::Field<bool>& field, const char* desc = nullptr);
bool ConfigWidget(config::Field<int>& field, int step = 1, int start = 0, int end = 0, const char* desc = nullptr);
bool ConfigWidget(config::Field<float>& field, float step = 1.0F, float start = 0, float end = 0, const char* desc = nullptr);
bool ConfigWidget(config::Field<Hotkey>& field, bool clearable = true, const char* desc = nullptr);
bool ConfigWidget(config::Field<std::string>& field, const char* desc = nullptr);
bool ConfigWidget(config::Field<ImColor>& field, const char* desc = nullptr);
template<typename T>
bool ConfigWidget(config::Field<config::Toggle<T>>& field, const char* desc = nullptr)
{
return ConfigWidget(field.friendName().c_str(), field, desc);
}
bool ConfigWidget(config::Field<config::Toggle<float>>& field, float step = 1.0F, float start = 0, float end = 0, const char* desc = nullptr);
bool ConfigWidget(config::Field<config::Toggle<Hotkey>>& field, const char* desc = nullptr, bool hotkey = false);
void ShowHelpText(const char* text);
void HelpMarker(const char* desc);
bool InputHotkey(const char* label, Hotkey* hotkey, bool clearable);
// Thanks to https://gist.github.com/dougbinks/ef0962ef6ebe2cadae76c4e9f0586c69
void AddUnderLine(ImColor col_);
void TextURL(const char* name_, const char* URL_, bool SameLineBefore_, bool SameLineAfter_);
enum class OutlineSide : uint32_t
{
Left = 1,
Right = 2,
Top = 4,
Bottom = 8,
All = Left | Right | Top | Bottom
};
bool operator&(OutlineSide lhs, OutlineSide rhs);
void DrawTextWithOutline(ImDrawList* drawList, ImFont* font, float fontSize, const ImVec2& screenPos, const char* text, const ImColor& textColor,
float outlineThickness = 0.0f, OutlineSide sides = OutlineSide::All, const ImColor& outlineColor = ImColor(0.0f, 0.0f, 0.0f));
void DrawTextWithOutline(ImDrawList* drawList, const ImVec2& screenPos, const char* text, const ImColor& textColor,
float outlineThickness = 0.0f, OutlineSide sides = OutlineSide::All, const ImColor& outlineColor = ImColor(0.0f, 0.0f, 0.0f));
struct SelectData
{
bool toggle;
bool changed;
};
bool BeginGroupPanel(const char* name, const ImVec2& size = ImVec2(-1, 0), bool node = false, SelectData* selectData = nullptr);
void EndGroupPanel();
namespace ImGui
{
bool HotkeyWidget(const char* label, Hotkey& hotkey, const ImVec2& size = ImVec2(0, 0));
float CalcContrastRatio(const ImU32& backgroundColor, const ImU32& foreGroundColor);
ImColor CalcContrastColor(const ImColor& foreground, float maxContrastRatio = 2.0f, const ImColor& background = ImColor(1.0f, 1.0f, 1.0f), const ImColor& inverted = ImColor(0.0f, 0.0f, 0.0f));
bool PushStyleColorWithContrast(ImU32 backGroundColor, ImGuiCol foreGroundColor, ImU32 invertedColor, float maxContrastRatio);
void OpenRenamePopup(const std::string& initName);
bool IsRenamePopupOpened();
bool DrawRenamePopup(std::string& out);
}
float CalcWidth(const std::string_view& view);
template <typename T>
float GetMaxEnumWidth()
{
constexpr auto names = magic_enum::enum_names<T>();
auto maxComboName = std::max_element(names.begin(), names.end(),
[](const auto& a, const auto& b) { return CalcWidth(a) < CalcWidth(b); });
return CalcWidth(*maxComboName);
}
template <typename T>
bool ComboEnum(const char* label, T* currentValue)
{
auto name = magic_enum::enum_name(*currentValue);
auto& current = *currentValue;
bool result = false;
static auto width = GetMaxEnumWidth<T>();
ImGui::SetNextItemWidth(width);
if (ImGui::BeginCombo(label, name.data()))
{
for (auto& entry : magic_enum::enum_entries<T>())
{
bool is_selected = (name == entry.second);
if (ImGui::Selectable(entry.second.data(), is_selected))
{
current = entry.first;
result = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
return result;
}
template <typename T>
bool ConfigWidget(const char* label, config::Field<config::Enum<T>>& field, const char* desc = nullptr)
{
bool result = false;
if (ComboEnum(label, &field.value()))
{
field.FireChanged();
result = true;
}
if (desc != nullptr) { ImGui::SameLine(); HelpMarker(desc); };
return result;
}
template <typename T>
bool ConfigWidget(config::Field<config::Enum<T>>& field, const char* desc = nullptr)
{
return ConfigWidget(field.friendName().c_str(), field, desc);
}

View File

@ -0,0 +1,291 @@
#include <pch.h>
#include "renderer.h"
#include <backends/imgui_impl_dx11.h>
#include <backends/imgui_impl_win32.h>
#include <cheat-base/util.h>
#include <cheat-base/render/backend/dx11-hook.h>
#include <cheat-base/ResourceLoader.h>
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
namespace renderer
{
struct Data
{
LPBYTE data;
DWORD size;
};
static std::unordered_set<void*> _inputLockers;
static float _globalFontSize = 16.0f;
static bool _isCustomFontLoaded = false;
static constexpr int _fontSizeStep = 1;
static constexpr int _fontSizeMax = 64;
static constexpr int _fontsCount = _fontSizeMax / _fontSizeStep;
static std::array<ImFont*, _fontsCount> _fonts;
static Data _customFontData {};
static WNDPROC OriginalWndProcHandler;
static ID3D11RenderTargetView* mainRenderTargetView;
static void OnRender(ID3D11DeviceContext* pContext);
static void OnDX11Initialize(HWND window, ID3D11Device* pDevice, ID3D11DeviceContext* pContext, IDXGISwapChain* pChain);
void Init(LPBYTE fontData, DWORD fontDataSize)
{
_customFontData = { fontData, fontDataSize };
LOG_DEBUG("Initialize IMGui...");
backend::DX11Events::RenderEvent += FUNCTION_HANDLER(OnRender);
backend::DX11Events::InitializeEvent += FUNCTION_HANDLER(OnDX11Initialize);
backend::InitializeDX11Hooks();
}
void SetInputLock(void* id, bool value)
{
if (value)
AddInputLocker(id);
else
RemoveInputLocker(id);
}
void AddInputLocker(void* id)
{
if (_inputLockers.count(id) == 0)
_inputLockers.insert(id);
}
void RemoveInputLocker(void* id)
{
if (_inputLockers.count(id) > 0)
_inputLockers.erase(id);
}
bool IsInputLocked()
{
return _inputLockers.size() > 0;
}
ImFont* GetFontBySize(float fontSize)
{
if (!_isCustomFontLoaded)
{
ImGuiIO& io = ImGui::GetIO();
return io.FontDefault;
}
int fontSizeInt = static_cast<int>(fontSize);
int fontIndex = fontSizeInt / _fontSizeStep +
(fontSizeInt % _fontSizeStep > (_fontSizeStep / 2) ? 1 : 0) - 1;
fontIndex = std::clamp(fontIndex, 0, _fontsCount - 1);
return _fonts[fontIndex];
}
float GetScaleByFontSize(float fontSize)
{
if (!_isCustomFontLoaded)
{
ImGuiIO& io = ImGui::GetIO();
return fontSize / io.FontDefault->FontSize;
}
int fontSizeInt = static_cast<int>(fontSize);
int fontIndex = fontSizeInt / _fontSizeStep;
int fontAligned = fontIndex * _fontSizeStep +
((fontSizeInt % _fontSizeStep) > _fontSizeStep / 2 ? _fontSizeStep : 0);
fontAligned = std::clamp(fontAligned, _fontSizeStep, _fontSizeMax);
return fontSize / static_cast<float>(fontAligned);
}
void SetGlobalFontSize(float globalFontSize)
{
_globalFontSize = globalFontSize;
}
float GetGlobalFontSize()
{
return _globalFontSize;
}
static void LoadCustomFont()
{
if (_customFontData.data == nullptr)
return;
for (int i = 0; i < _fontsCount; i++)
{
ImGuiIO& io = ImGui::GetIO();
auto newFont = io.Fonts->AddFontFromMemoryTTF(_customFontData.data, _customFontData.size, (i + 1) * _fontSizeStep);
if (newFont == nullptr)
return;
_fonts[i] = newFont;
}
_isCustomFontLoaded = true;
}
static void SetupImGuiStyle();
static LRESULT CALLBACK hWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void OnDX11Initialize(HWND window, ID3D11Device* pDevice, ID3D11DeviceContext* pContext, IDXGISwapChain* pChain)
{
LOG_DEBUG("ImGUI: DirectX11 backend initialized successfully.");
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
LoadCustomFont();
SetupImGuiStyle();
//Set OriginalWndProcHandler to the Address of the Original WndProc function
OriginalWndProcHandler = reinterpret_cast<WNDPROC>(SetWindowLongPtr(window, GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(hWndProc)));
ImGui_ImplWin32_Init(window);
ImGui_ImplDX11_Init(pDevice, pContext);
ID3D11Texture2D* pBackBuffer;
pChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<LPVOID*>(&pBackBuffer));
pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView);
pBackBuffer->Release();
io.SetPlatformImeDataFn = nullptr; // F**king bug take 4 hours of my life
}
static void OnRender(ID3D11DeviceContext* pContext)
{
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.FontDefault = GetFontBySize(_globalFontSize);
ImGui::NewFrame();
events::RenderEvent();
ImGui::EndFrame();
ImGui::Render();
pContext->OMSetRenderTargets(1, &mainRenderTargetView, nullptr);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
}
static LRESULT CALLBACK hWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ImGuiIO& io = ImGui::GetIO();
POINT mPos;
GetCursorPos(&mPos);
ScreenToClient(hWnd, &mPos);
ImGui::GetIO().MousePos.x = mPos.x;
ImGui::GetIO().MousePos.y = mPos.y;
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
if (!events::WndProcEvent(hWnd, uMsg, wParam, lParam))
return true;
short key;
bool keyUpEvent = true;
switch (uMsg)
{
case WM_LBUTTONUP:
key = VK_LBUTTON;
break;
case WM_RBUTTONUP:
key = VK_RBUTTON;
break;
case WM_MBUTTONUP:
key = VK_MBUTTON;
break;
case WM_XBUTTONUP:
key = GET_XBUTTON_WPARAM(wParam);
break;
case WM_KEYUP:
key = wParam;
break;
default:
keyUpEvent = false;
break;
}
bool canceled = false;
if (keyUpEvent)
canceled = !events::KeyUpEvent(key);
if (IsInputLocked() || canceled)
return true;
return CallWindowProc(OriginalWndProcHandler, hWnd, uMsg, wParam, lParam);
}
static void SetupImGuiStyle()
{
ImGui::GetStyle().FrameRounding = 4.0f;
ImGui::GetStyle().GrabRounding = 4.0f;
ImVec4* colors = ImGui::GetStyle().Colors;
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.17f, 0.21f, 0.24f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.12f, 0.15f, 0.14f, 1.00f);
colors[ImGuiCol_ChildBg] = ImVec4(0.12f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.09f, 0.11f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.15f, 0.22f, 0.25f, 1.00f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.20f, 0.20f, 0.20f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.18f, 0.25f, 0.27f, 1.00f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.15f, 0.19f, 0.24f, 1.00f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.19f, 0.22f, 0.24f, 1.00f);
colors[ImGuiCol_TitleBg] = ImVec4(0.14f, 0.18f, 0.22f, 0.65f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.13f, 0.16f, 0.19f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.15f, 0.15f, 0.15f, 0.51f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.12f, 0.14f, 0.18f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.11f, 0.11f, 0.11f, 0.39f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.53f, 0.37f, 0.37f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.23f, 0.23f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.56f, 0.10f, 0.10f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.65f, 0.74f, 0.86f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.35f, 0.47f, 0.68f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.68f, 0.80f, 1.00f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.14f, 0.19f, 0.24f, 1.00f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.27f, 0.30f, 0.44f, 1.00f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.28f, 0.29f, 0.41f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.24f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.12f, 0.16f, 0.20f, 0.80f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.00f, 0.44f, 0.92f, 1.00f);
colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.31f, 0.45f, 0.60f, 0.78f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.42f, 0.57f, 0.75f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.64f, 0.79f, 0.98f, 0.25f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.65f, 0.75f, 0.87f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.43f, 0.55f, 0.70f, 0.95f);
colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabHovered] = ImVec4(0.59f, 0.59f, 0.59f, 0.80f);
colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
}
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <Windows.h>
#include <cheat-base/events/event.hpp>
#include <imgui.h>
namespace renderer
{
void Init(LPBYTE pFontData, DWORD dFontDataSize);
// Font sizing
ImFont* GetFontBySize(float fontSize);
float GetScaleByFontSize(float fontSize);
void SetGlobalFontSize(float globalFontSize);
float GetGlobalFontSize();
// Input lock
void SetInputLock(void* id, bool value);
void AddInputLocker(void* id);
void RemoveInputLocker(void* id);
bool IsInputLocked();
}

View File

@ -0,0 +1,87 @@
#pragma once
#include <mutex>
#include <queue>
#include <optional>
template<typename T>
class SafeQueue
{
public:
SafeQueue() = default;
SafeQueue(const SafeQueue<T>&) = delete;
SafeQueue& operator=(const SafeQueue<T>&) = delete;
SafeQueue(SafeQueue<T>&& other) {
std::lock_guard<std::mutex> lock(mutex_);
queue_ = std::move(other.queue_);
}
virtual ~SafeQueue() { }
unsigned long size() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.size();
}
std::optional<T> pop()
{
std::lock_guard<std::mutex> lock(mutex_);
if (queue_.empty()) {
return {};
}
T tmp = queue_.front();
queue_.pop();
return tmp;
}
void push(const T& item) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(item);
}
private:
std::queue<T> queue_;
mutable std::mutex mutex_;
bool empty() const {
return queue_.empty();
}
};
template <class T>
class SafeValue
{
public:
SafeValue(T initValue) : value(initValue) {}
SafeValue(const SafeValue<T>&) = delete;
SafeValue& operator=(const SafeValue<T>&) = delete;
T GetValue() const
{
std::lock_guard<std::mutex> lock(mutex_);
return value;
}
void SetValue(const T& newValue)
{
std::lock_guard<std::mutex> lock(mutex_);
value = newValue;
}
SafeValue& operator=(const T& newValue)
{
SetValue(newValue);
return *this;
}
operator T() const
{
return GetValue();
}
private:
T value;
mutable std::mutex mutex_;
};

View File

@ -0,0 +1,264 @@
#include <pch.h>
#include <framework.h>
#include "util.h"
#include <Windows.h>
#include <commdlg.h>
#include <shtypes.h>
#include <shobjidl_core.h>
#include <shlobj_core.h>
#include <sstream>
#include <string>
#include <iomanip>
#include <codecvt>
#include <filesystem>
namespace util
{
std::string GetLastErrorAsString(DWORD errorId /*= 0*/)
{
//Get the error message ID, if any.
DWORD errorMessageID = errorId == 0 ? ::GetLastError() : errorId;
if (errorMessageID == 0)
{
return std::string(); //No error message has been recorded
}
LPSTR messageBuffer = nullptr;
//Ask Win32 to give us the string version of that message ID.
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
//Copy the error message into a std::string.
std::string message(messageBuffer, size);
//Free the Win32's string's buffer.
LocalFree(messageBuffer);
return message;
}
std::string to_hex_string(uint8_t* barray, int length)
{
if (barray == nullptr || length == 0)
return std::string();
std::stringstream stream;
for (size_t i = 0; i < length; i++)
stream << std::setfill('0') << std::setw(2) << std::hex << (int)barray[i];
return stream.str();
}
bool IsLittleEndian()
{
unsigned int i = 1;
char* c = (char*)&i;
return (*c);
}
std::optional<std::string> SelectDirectory(const char* title)
{
auto currPath = std::filesystem::current_path();
if (!SUCCEEDED(CoInitialize(nullptr)))
return {};
IFileDialog* pfd;
if (!SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
return {};
const size_t titleSize = strlen(title) + 1;
wchar_t* wcTitle = new wchar_t[titleSize];
mbstowcs(wcTitle, title, titleSize);
DWORD dwOptions;
IShellItem* psi;
if (!SUCCEEDED(pfd->GetOptions(&dwOptions)) ||
!SUCCEEDED(pfd->SetOptions(dwOptions | FOS_PICKFOLDERS)) ||
!SUCCEEDED(pfd->SetTitle(wcTitle)) ||
!SUCCEEDED(pfd->Show(NULL)) ||
!SUCCEEDED(pfd->GetResult(&psi)))
{
pfd->Release();
return {};
}
WCHAR* folderName;
if (!SUCCEEDED(psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &folderName)))
{
pfd->Release();
psi->Release();
return {};
}
pfd->Release();
psi->Release();
std::filesystem::current_path(currPath);
std::u16string u16(reinterpret_cast<const char16_t*>(folderName));
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
}
std::optional<std::string> SelectFile(const char* filter, const char* title)
{
auto currPath = std::filesystem::current_path();
// common dialog box structure, setting all fields to 0 is important
OPENFILENAME ofn = { 0 };
TCHAR szFile[260] = { 0 };
// Initialize remaining fields of OPENFILENAME structure
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = filter;
ofn.lpstrTitle = title;
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
std::optional<std::string> result = {};
if (GetOpenFileName(&ofn) == TRUE)
result = std::string(szFile);
std::filesystem::current_path(currPath);
return result;
}
std::optional<std::string> GetOrSelectPath(CSimpleIni& ini, const char* section, const char* name, const char* friendName, const char* filter)
{
auto savedPath = ini.GetValue(section, name);
if (savedPath != nullptr)
return std::string(savedPath);
LOG_DEBUG("%s path not found. Please point to it manually.", friendName);
auto titleStr = string_format("Select %s", friendName);
auto selectedPath = filter == nullptr ? SelectDirectory(titleStr.c_str()) : SelectFile(filter, titleStr.c_str());
if (!selectedPath)
return {};
ini.SetValue(section, name, selectedPath->c_str());
return selectedPath;
}
int64_t GetCurrentTimeMillisec()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
std::vector<std::string> StringSplit(const std::string& delimiter, const std::string& content)
{
std::vector<std::string> tokens;
size_t pos = 0;
size_t prevPos = 0;
std::string token;
while ((pos = content.find(delimiter, prevPos)) != std::string::npos) {
token = content.substr(prevPos, pos - prevPos);
tokens.push_back(token);
prevPos = pos + delimiter.length();
}
tokens.push_back(content.substr(prevPos));
return tokens;
}
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(BYTE c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
std::string ret;
int i = 0;
int j = 0;
BYTE char_array_3[3];
BYTE char_array_4[4];
while (bufLen--) {
char_array_3[i++] = *(buf++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
std::vector<BYTE> base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
BYTE char_array_4[4], char_array_3[3];
std::vector<BYTE> ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret.push_back(char_array_3[i]);
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++)
char_array_4[j] = 0;
for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]);
}
return ret;
}
}

View File

@ -0,0 +1,79 @@
#pragma once
#include <string>
#include <stdexcept>
#include <memory>
#include <optional>
#include <vector>
#include <cheat-base/Logger.h>
#include <SimpleIni.h>
#define LOG_LAST_ERROR(fmt, ...) util::LogLastError(__FILE__, __LINE__, fmt, __VA_ARGS__)
#define UPDATE_DELAY(delay) \
static ULONGLONG s_LastUpdate = 0; \
ULONGLONG currentTime = GetTickCount64();\
if (s_LastUpdate + (delay) > currentTime) \
return; \
s_LastUpdate = currentTime;
#define UPDATE_DELAY_VAR(type, name, delay) \
static type name = {}; \
static ULONGLONG s_LastUpdate = 0; \
ULONGLONG currentTime = GetTickCount64();\
if (s_LastUpdate + (delay) > currentTime) \
return name; \
s_LastUpdate = currentTime;
namespace util
{
std::optional<std::string> SelectFile(const char* filter, const char* title);
std::optional<std::string> SelectDirectory(const char* title);
std::optional<std::string> GetOrSelectPath(CSimpleIni& ini, const char* section, const char* name, const char* friendName, const char* filter);
std::string GetLastErrorAsString(DWORD errorId = 0);
int64_t GetCurrentTimeMillisec();
std::vector<std::string> StringSplit(const std::string& delimiter, const std::string& content);
std::string to_hex_string(uint8_t* barray, int length);
bool IsLittleEndian();
std::string base64_encode(BYTE const* buf, unsigned int bufLen);
std::vector<BYTE> base64_decode(std::string const&);
template<typename ... Args>
std::string string_format(const std::string& format, Args ... args)
{
int size_s = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra space for '\0'
if (size_s <= 0) { throw std::runtime_error("Error during formatting."); }
auto size = static_cast<size_t>(size_s);
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, format.c_str(), args ...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
template<typename ... Args>
void LogLastError(const char* filepath, int line, const char* fmt, Args ... args)
{
auto errorId = ::GetLastError();
auto newFmt = string_format("%s. Error: %d %s", fmt, errorId, GetLastErrorAsString(errorId).c_str());
Logger::Log(Logger::Level::Error, filepath, line, newFmt.c_str(), args ...);
}
template<class T>
static T ReadMapped(void* data, int offset, bool littleEndian = false)
{
char* cData = (char*)data;
T result = {};
if (IsLittleEndian() != littleEndian)
{
for (int i = 0; i < sizeof(T); i++)
((char*)&result)[i] = cData[offset + sizeof(T) - i - 1];
return result;
}
memcpy_s(&result, sizeof(result), cData + offset, sizeof(result));
return result;
}
}

Binary file not shown.

1227
cheat-base/vendor/detours/detours.h vendored Normal file

File diff suppressed because it is too large Load Diff

27
cheat-base/vendor/detours/detver.h vendored Normal file
View File

@ -0,0 +1,27 @@
//////////////////////////////////////////////////////////////////////////////
//
// Common version parameters.
//
// Microsoft Research Detours Package, Version 4.0.1
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#define _USING_V110_SDK71_ 1
#include "winver.h"
#if 0
#include <windows.h>
#include <detours.h>
#else
#ifndef DETOURS_STRINGIFY
#define DETOURS_STRINGIFY_(x) #x
#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x)
#endif
#define VER_FILEFLAGSMASK 0x3fL
#define VER_FILEFLAGS 0x0L
#define VER_FILEOS 0x00040004L
#define VER_FILETYPE 0x00000002L
#define VER_FILESUBTYPE 0x00000000L
#endif
#define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS)

1
cheat-base/vendor/fmt vendored Submodule

@ -0,0 +1 @@
Subproject commit 86e27ccb41c2708e17ba264359223ef664d9bb78

1
cheat-base/vendor/imgui vendored Submodule

@ -0,0 +1 @@
Subproject commit af916cdf1aa41243b493c217c8d4256c04aa8921

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,357 @@
// imgui-notify by patrickcjk
// https://github.com/patrickcjk/imgui-notify
#ifndef IMGUI_NOTIFY
#define IMGUI_NOTIFY
#pragma once
#include <vector>
#include <string>
#include "font_awesome_5.h"
#include "fa_solid_900.h"
#define NOTIFY_MAX_MSG_LENGTH 4096 // Max message content length
#define NOTIFY_PADDING_X 20.f // Bottom-left X padding
#define NOTIFY_PADDING_Y 20.f // Bottom-left Y padding
#define NOTIFY_PADDING_MESSAGE_Y 10.f // Padding Y between each message
#define NOTIFY_FADE_IN_OUT_TIME 150 // Fade in and out duration
#define NOTIFY_DEFAULT_DISMISS 3000 // Auto dismiss after X ms (default, applied only of no data provided in constructors)
#define NOTIFY_OPACITY 1.0f // 0-1 Toast opacity
#define NOTIFY_TOAST_FLAGS ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing
// Comment out if you don't want any separator between title and content
#define NOTIFY_USE_SEPARATOR
#define NOTIFY_INLINE inline
#define NOTIFY_NULL_OR_EMPTY(str) (!str ||! strlen(str))
#define NOTIFY_FORMAT(fn, format, ...) if (format) { va_list args; va_start(args, format); fn(format, args, __VA_ARGS__); va_end(args); }
typedef int ImGuiToastType;
typedef int ImGuiToastPhase;
typedef int ImGuiToastPos;
enum ImGuiToastType_
{
ImGuiToastType_None,
ImGuiToastType_Success,
ImGuiToastType_Warning,
ImGuiToastType_Error,
ImGuiToastType_Info,
ImGuiToastType_COUNT
};
enum ImGuiToastPhase_
{
ImGuiToastPhase_FadeIn,
ImGuiToastPhase_Wait,
ImGuiToastPhase_FadeOut,
ImGuiToastPhase_Expired,
ImGuiToastPhase_COUNT
};
enum ImGuiToastPos_
{
ImGuiToastPos_TopLeft,
ImGuiToastPos_TopCenter,
ImGuiToastPos_TopRight,
ImGuiToastPos_BottomLeft,
ImGuiToastPos_BottomCenter,
ImGuiToastPos_BottomRight,
ImGuiToastPos_Center,
ImGuiToastPos_COUNT
};
class ImGuiToast
{
private:
ImGuiToastType type = ImGuiToastType_None;
char title[NOTIFY_MAX_MSG_LENGTH];
char content[NOTIFY_MAX_MSG_LENGTH];
int dismiss_time = NOTIFY_DEFAULT_DISMISS;
uint64_t creation_time = 0;
private:
// Setters
NOTIFY_INLINE void set_title(const char* format, va_list args) { vsnprintf(this->title, sizeof(this->title), format, args); }
NOTIFY_INLINE void set_content(const char* format, va_list args) { vsnprintf(this->content, sizeof(this->content), format, args); }
public:
NOTIFY_INLINE void set_title(const char* format, ...) { NOTIFY_FORMAT(this->set_title, format); }
NOTIFY_INLINE void set_content(const char* format, ...) { NOTIFY_FORMAT(this->set_content, format); }
NOTIFY_INLINE void set_type(const ImGuiToastType& type) { IM_ASSERT(type < ImGuiToastType_COUNT); this->type = type; };
public:
// Getters
NOTIFY_INLINE char* get_title() { return this->title; };
NOTIFY_INLINE const char* get_default_title()
{
if (!strlen(this->title))
{
switch (this->type)
{
case ImGuiToastType_Success:
return "Success";
case ImGuiToastType_Warning:
return "Warning";
case ImGuiToastType_Error:
return "Error";
case ImGuiToastType_Info:
return "Info";
case ImGuiToastType_None:
default:
return NULL;
}
}
return this->title;
};
NOTIFY_INLINE const ImGuiToastType get_type() { return this->type; };
NOTIFY_INLINE const ImVec4 get_color()
{
switch (this->type)
{
case ImGuiToastType_Success:
return { 0, 255, 0, 255 }; // Green
case ImGuiToastType_Warning:
return { 255, 255, 0, 255 }; // Yellow
case ImGuiToastType_Error:
return { 255, 0, 0, 255 }; // Error
case ImGuiToastType_Info:
return { 0, 157, 255, 255 }; // Blue
case ImGuiToastType_None:
default:
return { 255, 255, 255, 255 }; // White
}
}
NOTIFY_INLINE const char* get_icon()
{
switch (this->type)
{
case ImGuiToastType_Success:
return ICON_FA_CHECK_CIRCLE;
case ImGuiToastType_Warning:
return ICON_FA_EXCLAMATION_TRIANGLE;
case ImGuiToastType_Error:
return ICON_FA_TIMES_CIRCLE;
case ImGuiToastType_Info:
return ICON_FA_INFO_CIRCLE;
case ImGuiToastType_None:
default:
return NULL;
}
}
NOTIFY_INLINE char* get_content() { return this->content; };
NOTIFY_INLINE uint64_t get_elapsed_time() { return GetTickCount64() - this->creation_time; }
NOTIFY_INLINE const ImGuiToastPhase get_phase()
{
const auto elapsed = get_elapsed_time();
if (elapsed > NOTIFY_FADE_IN_OUT_TIME + this->dismiss_time + NOTIFY_FADE_IN_OUT_TIME)
{
return ImGuiToastPhase_Expired;
}
else if (elapsed > NOTIFY_FADE_IN_OUT_TIME + this->dismiss_time)
{
return ImGuiToastPhase_FadeOut;
}
else if (elapsed > NOTIFY_FADE_IN_OUT_TIME)
{
return ImGuiToastPhase_Wait;
}
else
{
return ImGuiToastPhase_FadeIn;
}
}
NOTIFY_INLINE const float get_fade_percent()
{
const auto phase = get_phase();
const auto elapsed = get_elapsed_time();
if (phase == ImGuiToastPhase_FadeIn)
{
return ((float)elapsed / (float)NOTIFY_FADE_IN_OUT_TIME) * NOTIFY_OPACITY;
}
else if (phase == ImGuiToastPhase_FadeOut)
{
return (1.f - (((float)elapsed - (float)NOTIFY_FADE_IN_OUT_TIME - (float)this->dismiss_time) / (float)NOTIFY_FADE_IN_OUT_TIME)) * NOTIFY_OPACITY;
}
return 1.f * NOTIFY_OPACITY;
}
public:
// Constructors
ImGuiToast(ImGuiToastType type, int dismiss_time = NOTIFY_DEFAULT_DISMISS)
{
IM_ASSERT(type < ImGuiToastType_COUNT);
this->type = type;
this->dismiss_time = dismiss_time;
this->creation_time = GetTickCount64();
memset(this->title, 0, sizeof(this->title));
memset(this->content, 0, sizeof(this->content));
}
ImGuiToast(ImGuiToastType type, const char* format, ...) : ImGuiToast(type) { NOTIFY_FORMAT(this->set_content, format); }
ImGuiToast(ImGuiToastType type, int dismiss_time, const char* format, ...) : ImGuiToast(type, dismiss_time) { NOTIFY_FORMAT(this->set_content, format); }
};
namespace ImGui
{
NOTIFY_INLINE std::vector<ImGuiToast> notifications;
/// <summary>
/// Insert a new toast in the list
/// </summary>
NOTIFY_INLINE VOID InsertNotification(const ImGuiToast& toast)
{
notifications.push_back(toast);
}
/// <summary>
/// Remove a toast from the list by its index
/// </summary>
/// <param name="index">index of the toast to remove</param>
NOTIFY_INLINE VOID RemoveNotification(int index)
{
notifications.erase(notifications.begin() + index);
}
/// <summary>
/// Render toasts, call at the end of your rendering!
/// </summary>
NOTIFY_INLINE VOID RenderNotifications()
{
const auto vp_size = GetMainViewport()->Size;
float height = 0.f;
for (auto i = 0; i < notifications.size(); i++)
{
auto* current_toast = &notifications[i];
// Remove toast if expired
if (current_toast->get_phase() == ImGuiToastPhase_Expired)
{
RemoveNotification(i);
continue;
}
// Get icon, title and other data
const auto icon = current_toast->get_icon();
const auto title = current_toast->get_title();
const auto content = current_toast->get_content();
const auto default_title = current_toast->get_default_title();
const auto opacity = current_toast->get_fade_percent(); // Get opacity based of the current phase
// Window rendering
auto text_color = current_toast->get_color();
text_color.w = opacity;
// Generate new unique name for this toast
char window_name[50];
sprintf_s(window_name, "##TOAST%d", i);
//PushStyleColor(ImGuiCol_Text, text_color);
SetNextWindowBgAlpha(opacity);
SetNextWindowPos(ImVec2(vp_size.x - NOTIFY_PADDING_X, vp_size.y - NOTIFY_PADDING_Y - height), ImGuiCond_Always, ImVec2(1.0f, 1.0f));
Begin(window_name, NULL, NOTIFY_TOAST_FLAGS);
// Here we render the toast content
{
PushTextWrapPos(vp_size.x / 3.f); // We want to support multi-line text, this will wrap the text after 1/3 of the screen width
bool was_title_rendered = false;
// If an icon is set
if (!NOTIFY_NULL_OR_EMPTY(icon))
{
//Text(icon); // Render icon text
TextColored(text_color, icon);
was_title_rendered = true;
}
// If a title is set
if (!NOTIFY_NULL_OR_EMPTY(title))
{
// If a title and an icon is set, we want to render on same line
if (!NOTIFY_NULL_OR_EMPTY(icon))
SameLine();
Text(title); // Render title text
was_title_rendered = true;
}
else if (!NOTIFY_NULL_OR_EMPTY(default_title))
{
if (!NOTIFY_NULL_OR_EMPTY(icon))
SameLine();
Text(default_title); // Render default title text (ImGuiToastType_Success -> "Success", etc...)
was_title_rendered = true;
}
// In case ANYTHING was rendered in the top, we want to add a small padding so the text (or icon) looks centered vertically
if (was_title_rendered && !NOTIFY_NULL_OR_EMPTY(content))
{
SetCursorPosY(GetCursorPosY() + 5.f); // Must be a better way to do this!!!!
}
// If a content is set
if (!NOTIFY_NULL_OR_EMPTY(content))
{
if (was_title_rendered)
{
#ifdef NOTIFY_USE_SEPARATOR
Separator();
#endif
}
Text(content); // Render content text
}
PopTextWrapPos();
}
// Save height for next toasts
height += GetWindowHeight() + NOTIFY_PADDING_MESSAGE_Y;
// End
End();
}
}
/// <summary>
/// Adds font-awesome font, must be called ONCE on initialization
/// <param name="FontDataOwnedByAtlas">Fonts are loaded from read-only memory, should be set to false!</param>
/// </summary>
NOTIFY_INLINE VOID MergeIconsWithLatestFont(float font_size, bool FontDataOwnedByAtlas = false)
{
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 = FontDataOwnedByAtlas;
GetIO().Fonts->AddFontFromMemoryTTF((void*)fa_solid_900, sizeof(fa_solid_900), font_size, &icons_config, icons_ranges);
}
}
#endif

1
cheat-base/vendor/json vendored Submodule

@ -0,0 +1 @@
Subproject commit a94430615d8360272151f602b8c9eeb58509ecde

1
cheat-base/vendor/magic_enum vendored Submodule

@ -0,0 +1 @@
Subproject commit d1ccd22c853ac3afaf7a0f1c86019ea641e777c5

1
cheat-base/vendor/simpleIni vendored Submodule

@ -0,0 +1 @@
Subproject commit 9b3ed7ec815997bc8c5b9edf140d6bde653e1458

1
cheat-base/vendor/stb vendored Submodule

@ -0,0 +1 @@
Subproject commit af1a5bc352164740c1cc1354942b1c6b72eacb8a

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EasyHook" version="2.7.7097" targetFramework="native" />
</packages>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,13 @@
{
"game_version": "2.6",
"modules": {
"UnityPlayer.dll": {
"checksum": 1499808152269523874,
"timestamp": 132918960850629156
},
"UserAssembly.dll": {
"checksum": 6469164240778644427,
"timestamp": 132918960789354191
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Some files were not shown because too many files have changed in this diff Show More