diff --git a/The Callisto Protocol/dllmain.cpp b/The Callisto Protocol/dllmain.cpp index 44d85e4..aaaeacc 100644 --- a/The Callisto Protocol/dllmain.cpp +++ b/The Callisto Protocol/dllmain.cpp @@ -18,6 +18,7 @@ const std::string PLUGIN_NAME = "TheCallistoProtocol"; const std::string PLUGIN_LOG = PLUGIN_NAME + ".log"; constexpr float INVENTORY_CAM_OFFSET = 59.16f; constexpr float FORGE_CAM_OFFSET = 46.f; +constexpr ULONGLONG DEFAULT_ACTORS_SCAN_BETWEEN_TICKS = 300; // Used for enemies time dilation // Logger std::shared_ptr logger; @@ -36,10 +37,11 @@ static bool g_fov_fix_enabled = false; static bool g_CA_fix_enabled = false; static bool g_Vignetting_fix_enabled = false; static bool g_Fog_fix_enabled = false; -static bool g_WorldTimeDilation_fix_enabled = false; +static bool g_TimeDilation_fix_enabled = false; static int g_AdditionalFOVValue = 0; static int g_CameraOffset = 0; static float g_WorldTimeDilationValue = 1.f; +static float g_AITimeDilationValue = 1.f; static float g_CameraSmoothnessValue = 3.5f; static float g_TransitionCameraOffset = 0.f; static float g_NativeCameraDistance = 80.f; @@ -53,6 +55,7 @@ static bool bIsInPrinterMode = false; static bool bIsAiming = false; static double LastCineCallTime = 0.0; static bool user_inputs_logged = false; +static ULONGLONG lastScanTick = 0; // Last time Actors were scanned for enemies time dilation // Shared values static float g_FOV_In = 75.f; @@ -93,7 +96,7 @@ static void DOFFixEnabled(); static void CAFixEnabled(); static void VignettingFixEnabled(); static void FogFixEnabled(); -static void WorldTimeDilation(); +static void TimeDilation(); static void EnableConsole(); // Unreal Engine camera struct @@ -253,7 +256,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) if (!init && CAaddress) CAFixEnabled(); if (!init && Vignettingaddress) VignettingFixEnabled(); if (!init && Fogaddress) FogFixEnabled(); - if (!init && WorldTimedilationaddress) WorldTimeDilation(); + if (!init && WorldTimedilationaddress) TimeDilation(); if (!init && GObjectsaddress && AppendStringaddress && ProcessEventaddress) EnableConsole(); if (ConstrainAspectaddress) UltraWideFixEnabled(); } @@ -267,7 +270,7 @@ extern "C" __declspec(dllexport) void SetFixesEnabled(GameFixes fix, bool enable if (fix == GameFixes::ChromaticAberrations) { g_CA_fix_enabled = enabled; CAFixEnabled(); } if (fix == GameFixes::Vignetting) { g_Vignetting_fix_enabled = enabled; VignettingFixEnabled(); } if (fix == GameFixes::Fog) { g_Fog_fix_enabled = enabled; FogFixEnabled(); } - if (fix == GameFixes::WorldTimeDilation) { g_WorldTimeDilation_fix_enabled = enabled; WorldTimeDilation(); } + if (fix == GameFixes::WorldTimeDilation) { g_TimeDilation_fix_enabled = enabled; TimeDilation(); } } extern "C" __declspec(dllexport) void SetFOV(int fov) @@ -289,10 +292,63 @@ extern "C" __declspec(dllexport) void SetWorldTimeDilation(float timeDilation) { g_WorldTimeDilationValue = timeDilation; } +extern "C" __declspec(dllexport) void SetAITimeDilation(float timeDilation) { + g_AITimeDilationValue = timeDilation; +} + extern "C" __declspec(dllexport) void SetCameraSmoothness(float smoothness) { g_CameraSmoothnessValue = smoothness; } +// Unreal Engine functions +/** + * @brief Converts a rotator (Pitch, Yaw) to a forward direction vector. + * + * Computes a normalized forward vector from the given FRotator, + * using Pitch and Yaw angles (in degrees). + * + * @param rotator Input rotation (degrees). + * @return Forward direction vector. + */ +static FVector RotatorToForwardVector(const FRotator& rotator) +{ + const float DEG_TO_RAD = 3.1415926535f / 180.0f; + + float cp = cosf(rotator.Pitch * DEG_TO_RAD); + float sp = sinf(rotator.Pitch * DEG_TO_RAD); + float cy = cosf(rotator.Yaw * DEG_TO_RAD); + float sy = sinf(rotator.Yaw * DEG_TO_RAD); + + return FVector(cp * cy, cp * sy, sp); +} + +/** + * @brief Gets the current player Pawn from the world. + * @param world Optional UWorld pointer. + * @return Player Pawn or nullptr. + */ +static APawn* GetPawnFromWorld(UWorld* world = nullptr) { + if (!world) UWorld* world = UWorld::GetWorld(); + if (!world) return nullptr; + + UGameInstance* gameInstance = world->OwningGameInstance; + if (!gameInstance || gameInstance->LocalPlayers.Num() == 0) return nullptr; + ULocalPlayer* localPlayer = gameInstance->LocalPlayers[0]; + if (!localPlayer) return nullptr; + APlayerController* pc = localPlayer->PlayerController; + if (!pc) return nullptr; + APawn* pawn = pc->AcknowledgedPawn; + + return pawn; +} + +// Miscellaneous functions +static inline double NowSeconds() +{ + using namespace std::chrono; + static steady_clock::time_point start = steady_clock::now(); + return duration(steady_clock::now() - start).count(); +} // Getters for Reshade addon call extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) { @@ -324,25 +380,6 @@ static void FOVFixEnabled() { } } -static FVector RotatorToForwardVector(const FRotator& rotator) -{ - const float DEG_TO_RAD = 3.1415926535f / 180.0f; - - float cp = cosf(rotator.Pitch * DEG_TO_RAD); - float sp = sinf(rotator.Pitch * DEG_TO_RAD); - float cy = cosf(rotator.Yaw * DEG_TO_RAD); - float sy = sinf(rotator.Yaw * DEG_TO_RAD); - - return FVector(cp * cy, cp * sy, sp); -} - -inline double NowSeconds() -{ - using namespace std::chrono; - static steady_clock::time_point start = steady_clock::now(); - return duration(steady_clock::now() - start).count(); -} - static void CameraFixEnabled() { if (g_fix_enabled && g_camera_fix_enabled && ProcessEventaddress) { if (!PEHook) { @@ -384,13 +421,7 @@ static void CameraFixEnabled() { // --- World to Pawn (player) --- UWorld* world = UWorld::GetWorld(); if (!world) return; - UGameInstance* gameInstance = world->OwningGameInstance; - if (!gameInstance || gameInstance->LocalPlayers.Num() == 0) return; - ULocalPlayer* localPlayer = gameInstance->LocalPlayers[0]; - if (!localPlayer) return; - APlayerController* pc = localPlayer->PlayerController; - if (!pc) return; - APawn* pawn = pc->AcknowledgedPawn; + APawn* pawn = GetPawnFromWorld(world); if (!pawn) return; // Retrieve Character class @@ -486,7 +517,6 @@ static void CameraFixEnabled() { cameraParams->NewViewRotation = cameraParams->ViewRotation; cameraParams->NewFOV = cameraParams->FOV; } - } }); } @@ -552,21 +582,44 @@ static void HUDFixEnabled() { } } -static void WorldTimeDilation() { - if (g_fix_enabled && g_WorldTimeDilation_fix_enabled) { +static void TimeDilation() { + if (g_fix_enabled && g_TimeDilation_fix_enabled && WorldTimedilationaddress) { if (!WorldTimeDilationHook) { WorldTimeDilationHook = safetyhook::create_mid(WorldTimedilationaddress + 0x20, [](SafetyHookContext& ctx) { - ctx.xmm0.f32[0] = g_WorldTimeDilationValue; + ctx.xmm0.f32[0] = g_TimeDilation_fix_enabled ? g_WorldTimeDilationValue : 1.f; + + ULONGLONG now = GetTickCount64(); + if (now - lastScanTick < DEFAULT_ACTORS_SCAN_BETWEEN_TICKS) return; + + lastScanTick = now; + UWorld* world = UWorld::GetWorld(); + if (!world) return; + APawn* pawn = GetPawnFromWorld(world); + if (!pawn) return; + + for (int i = 0; i < world->Levels.Num(); i++) // Loop through level to find actors + { + ULevel* Level = world->Levels[i]; + if (!Level) continue; + + for (int j = 0; j < Level->Actors.Num(); j++) // Loop through actors + { + AActor* actor = Level->Actors[j]; + if (!actor) continue; + if (actor == pawn) continue; // We don't want to affect Jacob + if (!actor->IsA(ACharacter::StaticClass()) && !actor->IsA(APawn::StaticClass())) + continue; // We want to affect only enemies + + actor->CustomTimeDilation = g_TimeDilation_fix_enabled ? g_AITimeDilationValue : 1.f; + } + } }); } - else WorldTimeDilationHook.enable(); - logger->info("World time dilation fix enabled"); - } - if (!(g_fix_enabled && g_WorldTimeDilation_fix_enabled)) { - if (WorldTimeDilationHook) WorldTimeDilationHook.disable(); - logger->info("World time dilation fix disabled"); + logger->info("Time dilation fix enabled"); } + if (!(g_fix_enabled && g_TimeDilation_fix_enabled) && WorldTimedilationaddress) + logger->info("Time dilation fix disabled"); } // Memory patch fixes