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