- Notifications
You must be signed in to change notification settings - Fork24
Game cheat base and clean architecture for your next cheat
License
CorrM/CleanCheat
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Game cheat base and clean architecture for your next cheat, even it's a cheat it should be clean
Project maintenance
Let's say i have level objects loop that have like 10k object, and everytype of objects have different task to do,if i havePlayerObject
andWeaponObject
, and i want to make ESP for players and zero recoil for weapons,then that is a different tasks but related to same task(object iterate).
Problem example code will be very UGLY and very hard to maintain fast:
for (int i =0; i < OBJECT_COUNT; ++i){if (OBJECT[i] is PlayerObject)// Condition {if (!OBJECT[i]->IsDead() && OBJECT[i]->Distance <100.f)// Condition {// Collect/Prepare data ...// Draw ... } }if (OBJECT[i] is WeaponObject)// Condition {if (!OBJECT[i]->IsEmpty())// Condition {// Collect/Prepare data ...// Handle OBJECT[i]->Recoil =0.f; } }}
Reusability
With some tweaks you can write Runners, DataProviders and Features only once and share them in all your projects
- Clean architecture
- Force your code to be maintainable and easy to read
- Easy to use, initialize and unload(dll unload)
- Easy global/shared data access
- Logger (Basic one)
- Hooks:
- Un/Detour
- Un/VMT swap
- Memory:
- Pattern scan
- Value scan (
TODO
)
To useCleanCheat
you need to do 3 simple steps
At first your project need to know aboutCleanCheat
.
First option:
Copysrc/CleanCheat
andsrc/CleanCheat.h
OR downloadLatest Release to your project dir
Second option:
Copy CleanCheat repo or add as git submodule (git submodule add https://github.com/CorrM/CleanCheat.git CleanCheat
)
Edit.vcxproj
file:
Add this to ItemGroup that haveClCompile
tags (Exmaple)
<ClCompile Include=".\CleanCheat\src\CleanCheat\**\*.cpp"> <PrecompiledHeader>NotUsing</PrecompiledHeader></ClCompile>
Add this to ItemGroup that haveClInclude
tags (Example)
<ClInclude Include=".\CleanCheat\src\CleanCheat\**\*.h" />
Now include CleanCheat in your project
- Add
#include "CleanCheat.h"
into your cpp/h files (if you have precompiled headers it is a good place to add this include there) - Initialize shared data if you will use it
Note:
In cpp/h files you need to includeCleanCheat.h
NOTCleanCheat/CleanCheatManager.h
CleanCheatSettings
CreateCleanCheatSettings.h
file in your project folder and its content should be like that
#pragma once#include"CleanCheat/RunnersCollectionBase.h"#include"SHARED_DATA_FILENAME.h"#include"Runners/BasicRunner.h"#defineSHARED_DATA_TYPE SHARED_DATA_CLASS_NAMEclassRunnersCollectionfinal : public RunnersCollectionBase{public:// RUNNERS};
This file is the only file you need to edit to start using CleanCheat, so that are things you need to change:
Name | Description |
---|---|
SHARED_DATA_FILENAME | Shared data header file name |
SHARED_DATA_CLASS_NAME | Shared data class name |
RUNNERS | Runners you want to register |
ExampleCleanCheatSettings.h
RUNNERS must to bepointer to runner
, any other field type will lead to unexpected behavior
Initialize CleanCheat
First thing to do after createCleanCheatSettings.h
is initializeCleanCheat
withOptions you prefer, actually this should befirst code you be executed in your project, this is how to initializeCleanCheat
:
CleanCheatOptions options;options.UseLogger =true;options.ConsoleTitle =L"CleanCheat";if (!CleanCheat::Init(options))CleanCheat::Discard();
Initialize Runners
To initializeRunner you need first to initialize allDataProviders andFeatures it hold:
(Prefer to initializeDataProviders first)
// # BasicRunner// Get basic runnerBasicRunner* basicRunner = CleanCheat::Runners->Basic;BasicRunnerDataProviders* basicDataProviders = basicRunner->DataProviders;BasicRunnerFeatures* basicDataFeatures = basicRunner->Features;// # DataProviders// Get BasicDataProvider and initalizebasicDataProviders->Basic->Init();// # Features// Get BasicFeature and initalizebasicDataFeatures->Basic->Init(&initData);// Get TestFeature and initalizebasicDataFeatures->Test->Init();// Init runner after its tasksbasicRunner->Init();// Other runners// ...
Start
After initialize runners your need to startCleanCheat
:
CleanCheat::Start();
Execute
CleanCheat
do all it's operation byCleanCheat::Tick
so it needs to be called from any where that get called at least once per frame:You can hook any (DirectX, OpenGL, Vulkan, etc) that called every frameInternalUnrealExample usePostRender
hooked function to do it.
int sharedDataTickParam =0;CleanCheat::Tick(&sharedDataTickParam);
Discard
Discard, stop and clean every operation done by CleanCheat, should only called once before exit.
(that should give you ability to unload your internal dll without need to restart or kill current process)
CleanCheat::Discard();
Use Shared data
You can accessshared data related stuff usingCleanCheat::SharedData
// Access shared dataCleanCheat::SharedData->ANY_DATA;
Logger
You can log byLOG
macro that's only work ifUseLogger
option areture
intmain(int argc,char* argv[]){// Init CleanCheat ...// LogLOG("Hello '%s' users","CleanCheat");return0;}// Output// [Main.cpp:main:11] Hello 'CleanCheat' users
Hooks
You can accesshooking related stuff usingCleanCheat::Hook
// Swap VMT method addressvoid* outOrignalMethodAddress =nullptr;CleanCheat::Hook->SwapVmt(INSTANCE_ADDRESS, METHOD_INDEX, &HOOK_FUNC, &outOrignalMethodAddress);// Detour functionvoid* functionAddress =0x123456CD;CleanCheat::Hook->Detour(&functionAddress, &HOOK_FUNC);
Memory
You can accessmemory related stuff usingCleanCheat::Memory
// Pattern scan// Look for "48 89 5C 24" in main module, and maximum result 2 (0 for get all result)std::vector<void*> addrs = CleanCheat::Memory->PatternScan("48 89 5C 24",2);
Options presented byCleanCheatOptions
struct that are passed wheninitialize CleanCheat
Option | Type | Description |
---|---|---|
UseLogger | bool | Enable console logging by attaching or allocate console window |
ConsoleTitle | string | Console window title |
The place where you would store global status and shared data, you could also add functions too.As every code need it's own collection of shared data you will need to make your own class.
Shared data basic setup
- FollowCleanCheatSettings Initialization
- Make a class that inherits from
SharedDataBase
- Include its header in
CleanCheatSettings.h
- Edit
SHARED_DATA_TYPE
inCleanCheatSettings.h
with your shared data class name
Runner concept present task that can be split into tasks(Features) with providing input to that tasks to check and handle.
In our example runner will present the loopfor (int i = 0; i < OBJECT_COUNT; ++i)
and iteratorObject
as input for ourFeatures.
boolLevelObjectsRunner::Condition(){return CleanCheat::SharedData && CleanCheat::SharedData->World;}voidLevelObjectsRunner::OnExecute(){for (int32_t i =0; i < curLevel->Objects.Count(); i++) {auto* curObject = curLevel->Objects[i];if (!curObject)continue;// Here we execute all registered features with 'curObject' as inputExecuteFeatures(curObject); }}
Runner life cycle
Func | Description |
---|---|
OnExecute | Called by CleanCheat every tick |
Condition | Called before OnExecute by CleanCheat to determine run it or not |
Discard | Called by CleanCheat when CleanCheat itself get discarded |
Runner task is the concept of any task that run underRunner wings.
Type | Description |
---|---|
DataProvider | Task that exist to provide data to runner itself or one of its features |
Feature | Task runner will invoke to handle part of your project logic |
DataProvider concept presentRunner sub-task that can do calculate/grab data withone input after pass acondition.
boolBestTargetDataProvider::Condition(Actor* curActor){return CleanCheat::SharedData && CleanCheat::SharedData->CurrentCanvas && CleanCheat::SharedData->CurrentWorld && CleanCheat::SharedData->GCharacter && curActor->IsA(ACharacterBP_C);}voidBestTargetDataProvider::AfterExecute(){SetData(LastBestTargetPlayer.Player);}voidBestTargetDataProvider::OnExecute(AActor* curActor){// ...}
Feature concept presentRunner sub-task that can doone thing withone input after pass acondition.So you can't pass same feature to multi runner (unexpected behavior).Feature are there to spilt runner code and make it easy to maintain easy to read.
In our example feature can be presented as aPlayer ESP drawer orWeapon no recoilin separate isolated classes like that:
boolEspFeature::Condition(Object* curObject){return curObject is PlayerObject && !curObject->IsDead() && curObject->Distance <100.f;}voidEspFeature::OnExecute(Object* curObject){// Collect/Preper data ...// Draw ...}
boolWeaponZeroRecoilFeature::Condition(Object* curObject){return curObject is WeaponObject && !curObject->IsEmpty();}voidWeaponZeroRecoilFeature::OnExecute(Object* curObject){// Collect/Preper data ...// Handle curObject->Recoil =0.f;}
Feature life cycle
Func | Description |
---|---|
OnInit | Called only once by user before it get registers by runner |
Condition | Called beforeOnExecute by runner to determine whether it will call it or not |
OnExecute | Called by runner during runner executive once or more depend on the runner |
BeforeExecute | Called by runnerbefore callOnExecute always get called, doesn't care aboutCondition |
AfterExecute | Called by runnerafter callOnExecute always get called, doesn't care aboutCondition |
Discard | Called by runner when runner itself get discarded |
There are a number of examples that demonstrate various aspects of usingCleanCheat
. They can be found in the examples folder:
Example | Description |
---|---|
Simple | Simple example |
InternalUnrealEngine | Shows how to use withCheatGear |
About
Game cheat base and clean architecture for your next cheat