Stealth mode cheat improvement. Add god mode cheat
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include "CommonHeaders.h"
|
||||
#include "UEngine.hpp";
|
||||
#include "UETools.hpp"
|
||||
#include "UEngine.hpp"
|
||||
#include "UEVars.hpp"
|
||||
#include "SDK/Basic.hpp"
|
||||
#include "SDK/Engine_classes.hpp"
|
||||
#include "SDK/WBP_Cutscene_classes.hpp"
|
||||
@@ -16,6 +18,7 @@ static AExponentialHeightFog* previousFogActor = nullptr;
|
||||
// Constants
|
||||
const std::string PLUGIN_NAME = "SilentHillf";
|
||||
const std::string PLUGIN_LOG = PLUGIN_NAME + ".log";
|
||||
constexpr ULONGLONG DEFAULT_ACTORS_SCAN_BETWEEN_TICKS = 300; // Used for enemies time dilation
|
||||
|
||||
// Logger
|
||||
std::shared_ptr<spdlog::logger> logger;
|
||||
@@ -37,6 +40,7 @@ static bool g_Cutscenes_FPS_fix_enabled = false;
|
||||
static bool g_SkipIntro_fix_enabled = false;
|
||||
static bool g_TimeDilation_fix_enabled = false;
|
||||
static bool g_StealthMode_fix_enabled = false;
|
||||
static bool g_GodMode_fix_enabled = false;
|
||||
static int g_AdditionalFOVValue = 0;
|
||||
static float g_CameraDistance = 1.f;
|
||||
static float g_FogDensity = 0.4f;
|
||||
@@ -55,11 +59,6 @@ static float g_DefaultFogDensity = -1.f;
|
||||
static float g_DefaultFogMaxOpacity = -1.f;
|
||||
static bool g_Console_Enabled = false;
|
||||
|
||||
// AOB Unreal Engine offsets addresses
|
||||
static uint8_t* GObjectsaddress = nullptr;
|
||||
static uint8_t* AppendStringaddress = nullptr;
|
||||
static uint8_t* ProcessEventaddress = nullptr;
|
||||
|
||||
// AOB Scan pointers
|
||||
static uint8_t* FOVaddress = nullptr;
|
||||
static uint8_t* DOFaddress = nullptr;
|
||||
@@ -138,7 +137,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) {
|
||||
Make(&FogOpacityEngineaddress, FogOpacityStringObfuscated, "Fog opacity"),
|
||||
Make(&VolumetricFogaddress, VolumetricFogStringObfuscated, "Volumetric fog"),
|
||||
Make(&CutscenesFPSaddress, CutscenesFPSStringObfuscated, "Cutscenes framerate"),
|
||||
Make(&WorldTimedilationaddress, WorldTimeDilationStringObfuscated, "World time dilation"),
|
||||
Make(&WorldTimedilationaddress, WorldTimeDilationStringObfuscated, "World time dilation")
|
||||
};
|
||||
// Scan all signature in a batch
|
||||
Memory::AOBScanBatch(signatures, logger);
|
||||
@@ -152,12 +151,14 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) {
|
||||
if (!GObjectsaddress || !AppendStringaddress || !ProcessEventaddress) {
|
||||
logger->info("------------ UEngine offsets search ------------");
|
||||
|
||||
constexpr auto GObjetcsStringObfuscated = make_obfuscated<0x4A>("48 8B ?? ?? ?? ?? ?? 48 8B ?? ?? 48 8D ?? ?? EB ?? 33");
|
||||
constexpr auto AppendStringStringObfuscated = make_obfuscated<0x4A>("48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 83 ?? ?? 80 3D ?? ?? ?? ?? ?? 48 8B F2 8B ?? 48");
|
||||
constexpr auto ProcessEventStringObfuscated = make_obfuscated<0x4A>("40 ?? 56 57 41 ?? 41 ?? 41 ?? 41 ?? 48 81 ?? ?? ?? ?? ?? 48 8D ?? ?? ?? 48 89 ?? ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? 48 89 ?? ?? ?? ?? ?? 4D ?? ?? 48");
|
||||
constexpr auto GObjetcsStringObfuscated = make_obfuscated<0x48>("48 8B ?? ?? ?? ?? ?? 48 8B ?? ?? 48 8D ?? ?? EB ?? 33");
|
||||
constexpr auto GWorldStringObfuscated = make_obfuscated<0x5B>("48 8B 05 ?? ?? ?? ?? 48 ?? ?? 75 ?? 48 ?? ?? ?? 5B C3");
|
||||
constexpr auto AppendStringStringObfuscated = make_obfuscated<0x89>("48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 83 ?? ?? 80 3D ?? ?? ?? ?? ?? 48 8B F2 8B ?? 48");
|
||||
constexpr auto ProcessEventStringObfuscated = make_obfuscated<0x81>("40 ?? 56 57 41 ?? 41 ?? 41 ?? 41 ?? 48 81 ?? ?? ?? ?? ?? 48 8D ?? ?? ?? 48 89 ?? ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? 48 89 ?? ?? ?? ?? ?? 4D ?? ?? 48");
|
||||
// Prepare all data for scanning
|
||||
std::vector<OffsetScanEntry> UEoffsetsScans = {
|
||||
Make(&GObjectsaddress, GObjetcsStringObfuscated, "GObjects", OffsetCalcType::GetOffsetFromOpcode, &Offsets::GObjects, 0x3),
|
||||
Make(&GWorldaddress, GWorldStringObfuscated, "GWorld", OffsetCalcType::GetOffsetFromOpcode, &Offsets::GWorld, 0x3),
|
||||
Make(&AppendStringaddress, AppendStringStringObfuscated, "AppendString", OffsetCalcType::UE_CalculateOffset, &Offsets::AppendString),
|
||||
Make(&ProcessEventaddress, ProcessEventStringObfuscated, "ProcessEvent", OffsetCalcType::UE_CalculateOffset, &Offsets::ProcessEvent)
|
||||
};
|
||||
@@ -177,6 +178,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) {
|
||||
if (!init && WorldTimedilationaddress) {
|
||||
EnableCheats(Cheat::TimeDilation);
|
||||
EnableCheats(Cheat::Stealth);
|
||||
EnableCheats(Cheat::GodMode);
|
||||
}
|
||||
if (!init && Fogaddress && FogDensityEngineaddress && FogOpacityEngineaddress) FogFixEnabled();
|
||||
if (!init && VolumetricFogaddress) VolumetricFogFixEnabled();
|
||||
@@ -200,6 +202,7 @@ extern "C" __declspec(dllexport) void SetFixesEnabled(GameFixes fix, bool enable
|
||||
if (fix == GameFixes::Fog) { g_Fog_fix_enabled = enabled; FogFixEnabled(); }
|
||||
if (fix == GameFixes::TimeDilation) { g_TimeDilation_fix_enabled = enabled; EnableCheats(Cheat::TimeDilation); }
|
||||
if (fix == GameFixes::Stealth) { g_StealthMode_fix_enabled = enabled; EnableCheats(Cheat::Stealth); }
|
||||
if (fix == GameFixes::GodMode) { g_GodMode_fix_enabled = enabled; EnableCheats(Cheat::GodMode); }
|
||||
}
|
||||
|
||||
// Setters for Reshade addon call
|
||||
@@ -356,7 +359,6 @@ static void VolumetricFogFixEnabled() {
|
||||
}
|
||||
}
|
||||
|
||||
static APawn* g_PlayerPawn = nullptr;
|
||||
static void ProcessEvent() {
|
||||
if (!PEHook && ProcessEventaddress) {
|
||||
PEHook = safetyhook::create_mid(ProcessEventaddress + 0xc,
|
||||
@@ -378,8 +380,9 @@ static void ProcessEvent() {
|
||||
}
|
||||
|
||||
bool bEnable = g_fix_enabled && g_Cutscenes_fix_enabled;
|
||||
if (object->GetName().contains("WBP_Cutscene_C") && (funcName == "Destruct" || funcName == "Construct")) bLastState = false;
|
||||
if (object->GetName().contains("WBP_Cutscene_C")) { // Black bars widgets removal
|
||||
bLastState = !(funcName == "Destruct" || funcName == "Construct");
|
||||
|
||||
auto cutscene = static_cast<UWBP_Cutscene_C*>(object);
|
||||
if (bEnable != bLastState) {
|
||||
float opacity = bEnable ? 0.f : 1.f;
|
||||
@@ -429,24 +432,57 @@ static void CutscenesFPSFixEnabled() {
|
||||
logger->info("Cutscenes FPS unlocker fix disabled");
|
||||
}
|
||||
|
||||
constexpr int ScanEveryNFrames = 120;
|
||||
static std::unordered_map<ANoceEnemyCharacter*, float> CachedAlertness;
|
||||
// Cheats
|
||||
static std::unordered_map<ANoceEnemyCharacter*, float> CachedAlertness;
|
||||
static float hinakoHealth = -1.f;
|
||||
static float hinakoSanity = -1.f;
|
||||
static float hinakoStamina = -1.f;
|
||||
static UWorld* LastWorld = nullptr;
|
||||
static ULONGLONG lastScanTick = 0; // Last time Actors were scanned for enemies time dilation
|
||||
|
||||
static void EnableCheats(Cheat cheat) {
|
||||
if (WorldTimedilationaddress && !WorldTimeDilationHook) {
|
||||
WorldTimeDilationHook = safetyhook::create_mid(WorldTimedilationaddress + 0x10,
|
||||
[](SafetyHookContext& ctx) {
|
||||
// From AWorldSettings retrieved from world->K2_GetWorldSettings()
|
||||
ctx.xmm0.f32[0] *= g_TimeDilation_fix_enabled ? g_WorldTimeDilationValue : 1.f;
|
||||
|
||||
UWorld* world = UWorld::GetWorld();
|
||||
if (world && world->OwningGameInstance->LocalPlayers[0]->PlayerController->AcknowledgedPawn)
|
||||
g_PlayerPawn = world->OwningGameInstance->LocalPlayers[0]->PlayerController->AcknowledgedPawn;
|
||||
if (!world || !world->OwningGameInstance) return;
|
||||
if (world != LastWorld) {
|
||||
CachedAlertness.clear();
|
||||
hinakoHealth = -1.f;
|
||||
hinakoSanity = -1.f;
|
||||
hinakoStamina = -1.f;
|
||||
LastWorld = world;
|
||||
}
|
||||
APawn* playerPawn = GetPawnFromWorld(world);
|
||||
if (playerPawn && playerPawn->IsA(ANocePlayerCharacter::StaticClass()) && playerPawn->IsPlayerControlled()) {
|
||||
auto* Hinako = static_cast<ANocePlayerCharacter*>(playerPawn);
|
||||
if (Hinako && Hinako->IsInBattling() && Hinako->InRealBattleStatus()) {
|
||||
if (g_GodMode_fix_enabled) {
|
||||
if (hinakoHealth < 0.f) hinakoHealth = Hinako->GetHealth();
|
||||
if (hinakoStamina < 0.f) hinakoStamina = Hinako->GetStamina();
|
||||
if (hinakoSanity < 0.f) hinakoSanity = Hinako->GetSanity();
|
||||
|
||||
// Scan levels and actors every 120 frames
|
||||
static uint64_t FrameCounter = 0;
|
||||
if (++FrameCounter < ScanEveryNFrames) return;
|
||||
FrameCounter = 0;
|
||||
Hinako->SetHealth(hinakoHealth);
|
||||
Hinako->SetSanity(hinakoSanity);
|
||||
Hinako->SetStamina(hinakoStamina);
|
||||
Hinako->ForceRunningNoCostStamina = true;
|
||||
}
|
||||
else {
|
||||
hinakoHealth = -1.f;
|
||||
hinakoSanity = -1.f;
|
||||
hinakoStamina = -1.f;
|
||||
Hinako->ForceRunningNoCostStamina = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ULONGLONG now = GetTickCount64();
|
||||
if (now - lastScanTick < DEFAULT_ACTORS_SCAN_BETWEEN_TICKS) return;
|
||||
lastScanTick = now;
|
||||
|
||||
if (world->Levels.Num() == 0) return;
|
||||
// Enemies time dilation & stealth
|
||||
for (int i = 0; i < world->Levels.Num(); i++) { // Loop through level to find actors
|
||||
ULevel* Level = world->Levels[i];
|
||||
@@ -454,25 +490,29 @@ static void EnableCheats(Cheat cheat) {
|
||||
|
||||
for (int j = 0; j < Level->Actors.Num(); j++) { // Loop through actors
|
||||
AActor* actor = Level->Actors[j];
|
||||
if (!actor || !g_PlayerPawn || actor == g_PlayerPawn) continue; // We don't want to affect Hinako
|
||||
if (actor->IsA(ANoceEnemyCharacter::StaticClass())) { // actor is enemy
|
||||
actor->CustomTimeDilation = g_TimeDilation_fix_enabled ? g_AITimeDilationValue : 1.f; // Enemy time dilation
|
||||
// Set enemy alert
|
||||
ANoceEnemyCharacter* enemy = static_cast<ANoceEnemyCharacter*>(actor);
|
||||
if (enemy && enemy->EnemyAIController) {
|
||||
if (g_StealthMode_fix_enabled) {
|
||||
if (CachedAlertness.find(enemy) == CachedAlertness.end())
|
||||
CachedAlertness[enemy] = enemy->EnemyAIController->GetAlertness();
|
||||
if (!actor || !playerPawn || actor == playerPawn) continue; // We don't want to affect Hinako
|
||||
if (!actor->IsA(ANoceEnemyCharacter::StaticClass())) continue; // actor is enemy
|
||||
// Set enemy alert
|
||||
ANoceEnemyCharacter* enemy = static_cast<ANoceEnemyCharacter*>(actor);
|
||||
if (!enemy || !enemy->EnemyAIController) continue;
|
||||
|
||||
enemy->EnemyAIController->SetAlertness(0.f, true); // Set enemy alert to 0
|
||||
}
|
||||
else {
|
||||
auto it = CachedAlertness.find(enemy);
|
||||
if (it != CachedAlertness.end()) {
|
||||
enemy->EnemyAIController->SetAlertness(it->second, true); // Restore original enemy alert
|
||||
CachedAlertness.erase(it);
|
||||
}
|
||||
}
|
||||
enemy->CustomTimeDilation = g_TimeDilation_fix_enabled ? g_AITimeDilationValue : 1.f; // Enemy time dilation
|
||||
UAIPerceptionComponent* AIPerception = enemy->EnemyAIController->GetAIPerceptionComponent();
|
||||
if (!AIPerception) continue;
|
||||
|
||||
if (g_StealthMode_fix_enabled) {
|
||||
AIPerception->SetSenseEnabled(UAISense_Sight::StaticClass(), false);
|
||||
if (enemy->EnemyAIController->GetAlertness() > 0.f && CachedAlertness.find(enemy) == CachedAlertness.end()) {
|
||||
CachedAlertness[enemy] = enemy->EnemyAIController->GetAlertness();
|
||||
}
|
||||
enemy->EnemyAIController->SetAlertness(0.f, true); // Set enemy alert to 0
|
||||
}
|
||||
else {
|
||||
AIPerception->SetSenseEnabled(UAISense_Sight::StaticClass(), true);
|
||||
auto it = CachedAlertness.find(enemy);
|
||||
if (it != CachedAlertness.end()) {
|
||||
enemy->EnemyAIController->SetAlertness(it->second, true); // Restore original enemy alert
|
||||
CachedAlertness.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,6 +521,7 @@ static void EnableCheats(Cheat cheat) {
|
||||
}
|
||||
if (cheat == Cheat::TimeDilation) logger->info("Time dilation cheat {}",g_TimeDilation_fix_enabled ? "enabled" : "disabled");
|
||||
if (cheat == Cheat::Stealth) logger->info("Stealth mode cheat {}", g_StealthMode_fix_enabled ? "enabled" : "disabled");
|
||||
if (cheat == Cheat::GodMode) logger->info("God mode cheat {}", g_GodMode_fix_enabled ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
// Memory patch fixes
|
||||
@@ -518,8 +559,7 @@ static void VignettingFixEnabled() {
|
||||
}
|
||||
|
||||
// UE Console creation
|
||||
static void EnableConsole()
|
||||
{
|
||||
static void EnableConsole() {
|
||||
if (g_Console_Enabled || !g_Console || !GObjectsaddress || !AppendStringaddress || !ProcessEventaddress) {
|
||||
if (!g_Console && !user_inputs_logged) {
|
||||
logger->info("------------------ User inputs ------------------");
|
||||
@@ -590,8 +630,7 @@ static void InitializeLogger() {
|
||||
}
|
||||
|
||||
// Standard dll entry
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID)
|
||||
{
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) {
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
InitializeLogger();
|
||||
logger->info("Plugin {} loaded.", PLUGIN_NAME);
|
||||
|
||||
Reference in New Issue
Block a user