#include <iostream>
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <vector>
#include <TlHelp32.h>
DWORD GetProcessId(const wchar_t* procName);
void* GetModuleBaseAddress(DWORD procId, const wchar_t* modName);
void* FindThePointedAddress(HANDLE hProc, void* ptr, std::vector<DWORD> offsets);
int main()
{
    DWORD GEngine = 0x4E27F48;
    std::vector<DWORD> offsets = {
        0xD28, //GameInstance
        0x38,  //LocalPlayers
        0x00, //[0]
        0x30, //PlayerController
        0x250, //Pawn
        0x1348,  //GameManager
        0x879 //PlayerBoomSize
    };
    const wchar_t* procName = L"MonolithBay-Win64-Shipping.exe";
    printf("Looking for \"%ls\" ...\n", procName);
    DWORD procId = GetProcessId(procName);
    if (!procId)
    {
        printf("Waiting for the game!\n");
        while (!procId)
        {
            procId = GetProcessId(procName);
        }
    }
    printf("Found \"%ls\" ...\n", procName);
    void* modBase = GetModuleBaseAddress(procId, procName);
    if (!modBase)
    {
        printf("Error: ModuleBase was missing!  Exiting....\n");
        system("pause");
        return 0;
    }
    modBase = (void*)((uintptr_t)modBase + GEngine);
    HANDLE pHandle = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);
    if (!pHandle || pHandle == INVALID_HANDLE_VALUE)
    {
        printf("Error: Could not open the target process! Exiting....\n");
        system("pause");
        return 0;
    }
    void* PlayerBoomSizeAddress = FindThePointedAddress(pHandle, modBase, offsets);
    if (!PlayerBoomSizeAddress)
    {
        printf("Error: Failed to find the inteded address! Are you sure you are in the game?\n");
        system("pause");
        return 0;
    }
    int val = 1;
    WriteProcessMemory(pHandle, (void*)PlayerBoomSizeAddress, &val, 1, nullptr);
    CloseHandle(pHandle);
    printf("Successfully cheats enabled!\n");
    system("pause");
    return 0;
}
DWORD GetProcessId(const wchar_t* procName)
{
    DWORD procId = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32 procEntry;
        procEntry.dwSize = sizeof(procEntry);
        if (Process32First(hSnap, &procEntry))
        {
            do
            {
                if (!_wcsicmp(procEntry.szExeFile, procName))
                {
                    procId = procEntry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnap, &procEntry));
        }
    }
    CloseHandle(hSnap);
    return procId;
}
void* GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
    void* MBAr = nullptr;
    HANDLE hToolHelp = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hToolHelp != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 moduleEntry;
        moduleEntry.dwSize = sizeof(moduleEntry);
        if (Module32First(hToolHelp, &moduleEntry))
        {
            do
            {
                if (!_wcsicmp(moduleEntry.szModule, modName))
                {
                    MBAr = moduleEntry.modBaseAddr;
                    break;
                }
            } while (Module32Next(hToolHelp, &moduleEntry));
        }
    }
    CloseHandle(hToolHelp);
    return MBAr;
}
void* FindThePointedAddress(HANDLE ProcessHandle, void* OriginalPointer, std::vector<DWORD> offsets)
{
    void* address = OriginalPointer;
    for (DWORD i = 0; i < offsets.size(); ++i)
    {
        ReadProcessMemory(ProcessHandle, (BYTE*)address, &address, sizeof(address), 0);
        address = (void*)((uintptr_t)address + offsets[i]);
    }
    return address;
}