diff --git a/The Callisto Protocol/dllmain.cpp b/The Callisto Protocol/dllmain.cpp index 9c6d4a4..a63a464 100644 --- a/The Callisto Protocol/dllmain.cpp +++ b/The Callisto Protocol/dllmain.cpp @@ -37,11 +37,16 @@ static bool g_Fog_fix_enabled = false; static int g_AdditionalFOVValue = 0; static int g_CameraOffset = 0; static float g_TransitionCameraOffset = 0.f; +static float g_NativeCameraDistance = 80.f; +static float g_LastCameraDeltaTime = 1.f / 60.f; // fallback static float g_HUDLeft = 0.f; static float g_HUDRight = 1.f; static bool g_Console = false; static bool bIsInventoryOpen = false; static bool bIsInCinematicMode = false; +static bool bIsInPrinterMode = false; +static bool bIsAiming = false; +static double LastCineCallTime = 0.0; static bool user_inputs_logged = false; // Shared values @@ -51,11 +56,13 @@ static bool g_Console_Enabled = false; // AOB Unreal Engine offsets addresses static uint8_t* GObjectsaddress = nullptr; +static uint8_t* GWorldaddress = nullptr; static uint8_t* AppendStringaddress = nullptr; static uint8_t* ProcessEventaddress = nullptr; // AOB Scan pointers static uint8_t* FOVaddress = nullptr; +static uint8_t* ConstrainAspectaddress = nullptr; static uint8_t* Cameraaddress = nullptr; static uint8_t* CameraObjectaddress = nullptr; static uint8_t* HUDaddress = nullptr; @@ -72,6 +79,7 @@ static SafetyHookMid PEHook{}; // Prototypes static void FOVFixEnabled(); +static void UltraWideFixEnabled(); static void CameraFixEnabled(); static void HUDFixEnabled(); static void DOFFixEnabled(); @@ -105,8 +113,10 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) if (!FOVaddress) logger->warn("FOV signature not found. Maybe your game has been updated and is no more compatible with this plugin."); - else + else { logger->info("FOV signature found at address: 0x{:X}.", reinterpret_cast(FOVaddress)); + ConstrainAspectaddress = FOVaddress + 0x25; + } } if (!Cameraaddress) { @@ -116,7 +126,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) if (!Cameraaddress) logger->warn("Camera signature not found. Maybe your game has been updated and is no more compatible with this plugin."); else - logger->info("Camera grain signature found at address: 0x{:X}.", reinterpret_cast(Cameraaddress)); + logger->info("Camera signature found at address: 0x{:X}.", reinterpret_cast(Cameraaddress)); } if (!HUDaddress) { @@ -168,6 +178,8 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) logger->info("------------ UEngine offsets search ------------"); uint8_t* baseModule = reinterpret_cast(GetModuleHandleA(nullptr)); // Get game base address + constexpr auto GWorldStringObfuscated = make_obfuscated<0x4A>("48 8B ?? ?? ?? ?? ?? 48 ?? ?? 74 ?? 48 ?? ?? E8 ?? ?? ?? ?? 83 ?? ?? 74"); + GWorldaddress = Memory::AOBScan("", GWorldStringObfuscated.decrypt(), PAGE_EXECUTE_READ); constexpr auto GObjetcsStringObfuscated = make_obfuscated<0x4A>("48 8B ?? ?? ?? ?? ?? 48 8B ?? ?? 48 8D ?? ?? EB ?? 33"); GObjectsaddress = Memory::AOBScan("", GObjetcsStringObfuscated.decrypt(), PAGE_EXECUTE_READ); constexpr auto AppendStringStringObfuscated = make_obfuscated<0x4A>("48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 ?? ?? ?? 8B ?? 48 ?? ?? 8B ?? 44 ?? ?? ?? C1 ?? ?? 48 ?? ?? 80 3D ?? ?? ?? ?? ?? 89 ?? ?? ?? 44 89 ?? ?? ?? 74 ?? 4C 8D ?? ?? ?? ?? ?? EB ?? 48 8D ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 4C ?? ?? C6 05 ?? ?? ?? ?? ?? 48 8B ?? ?? ?? 48 ?? ?? 48 ?? ?? ?? 8D ?? ?? 49 03 ?? ?? ?? E8 ?? ?? ?? ?? 83"); @@ -175,6 +187,15 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) constexpr auto ProcessEventStringObfuscated = make_obfuscated<0x4A>("40 ?? 56 57 41 ?? 41 ?? 41 ?? 41 ?? 48 81 ?? ?? ?? ?? ?? 48 8D ?? ?? ?? 48 89 ?? ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 ?? ?? 48 89 ?? ?? ?? ?? ?? 8B"); ProcessEventaddress = Memory::AOBScan("", ProcessEventStringObfuscated.decrypt(), PAGE_EXECUTE_READ); + if (!GWorldaddress) + logger->warn("GWorld signature not found. Maybe your game has been updated and is no more compatible with this plugin."); + else { + uint32_t gWorldOffset = static_cast(Memory::GetOffsetFromOpcode(GWorldaddress + 0x3) - + baseModule); + logger->info("GWorld offset is: 0x{:X}.", gWorldOffset); + Offsets::GWorld = static_cast(gWorldOffset); // Update GWorld offset + } + if (!GObjectsaddress) logger->warn("GObjects signature not found. Maybe your game has been updated and is no more compatible with this plugin."); else { @@ -216,6 +237,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) if (!init && Vignettingaddress) VignettingFixEnabled(); if (!init && Fogaddress) FogFixEnabled(); if (!init && GObjectsaddress && AppendStringaddress && ProcessEventaddress) EnableConsole(); + if (ConstrainAspectaddress) UltraWideFixEnabled(); } // Setters for Reshade addon call @@ -235,7 +257,7 @@ extern "C" __declspec(dllexport) void SetFOV(int fov) } extern "C" __declspec(dllexport) void SetCameraOffset(int cameraOffset) { - g_CameraOffset = cameraOffset; + g_CameraOffset = cameraOffset + 80; g_TransitionCameraOffset = (float)g_CameraOffset; } @@ -250,6 +272,7 @@ extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) { infos->FOVIn = g_FOV_In; infos->FOVOut = g_FOV_Out; + infos->CompensatedFOV = g_NativeCameraDistance; infos->consoleEnabled = g_Console_Enabled; } @@ -285,6 +308,13 @@ static FVector RotatorToForwardVector(const FRotator& rotator) 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) { @@ -292,91 +322,142 @@ static void CameraFixEnabled() { [](SafetyHookContext& ctx) { UObject* object = (UObject*)ctx.rcx; UFunction* func = (UFunction*)ctx.rdx; + if (object && func) { std::string funcName = func->GetName(); std::string objectName = object->GetFullName(); - // Detect inventory + + static auto start = std::chrono::high_resolution_clock::now(); + + // Detect cinematics to disable temporarily camera fix + if (objectName.contains("CineCameraComponent") && funcName == "SetCurrentFocalLength") { + bIsInCinematicMode = true; + LastCineCallTime = NowSeconds(); + } + // Detect reforge station interactions to disable temporarily camera fix + if (objectName.contains("BP_PrinterTabs_C")) { + if (funcName == "Show") bIsInPrinterMode = true; + if (funcName == "Hide") bIsInPrinterMode = false; + } + // Detect inventory interactions to disable temporarily camera fix if (objectName.contains("BP_State_Inventory_C")) { if (funcName == "OnBegin") bIsInventoryOpen = true; if (funcName == "OnEnd") bIsInventoryOpen = false; } - // Detect cinematics to disable temporarily camera fix - if (objectName.contains("PhxCinematicsComponent")) { - if (funcName == "OnAnimMontageStartedForLevelSequenceActor0") - bIsInCinematicMode = true; - if (funcName == "OnLevelSequenceFinishedReversePlaybackForLevelSequenceActor0") - bIsInCinematicMode = false; - } // Detect camera collisions to avoid world to vanish ending in character death - if (objectName.contains("CameraModifier_PhxCameraRig") && funcName == "BlueprintModifyCamera") { - if (bIsInCinematicMode) return; + if (objectName.contains("CameraModifier_PhxCameraRig") && funcName == "BlueprintModifyCamera") + { + auto* cameraParams = reinterpret_cast(ctx.r8); + if (!cameraParams) return; - void* params = reinterpret_cast(ctx.r8); - if (!params) return; + if (cameraParams->DeltaTime > 0.f && cameraParams->DeltaTime < 0.1f) + g_LastCameraDeltaTime = cameraParams->DeltaTime; - BlueprintModifyCamera_Params* cameraParams = reinterpret_cast(params); - static float lastSafeDistance = -1.0f; - FVector start = cameraParams->ViewLocation; - // --- backward direction --- + // --- 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; + if (!pawn) return; + // Retrieve Character class + void* inventoryComp = *(void**)((uintptr_t)pawn + 0x6d8); // inventoryComp offset from SDK + void* moveComp = *(void**)((uintptr_t)pawn + 0x908); // moveComp offset FROM SDK + if (inventoryComp && moveComp) { + APhxCharacter* phxChar = static_cast(pawn); + if (phxChar) bIsAiming = phxChar->GetIsAiming(); // Is player aiming + } + + // --- Positions --- + FVector pawnPos = pawn->K2_GetActorLocation(); + FVector engineCamPos = cameraParams->ViewLocation; + // --- Camera direction --- FVector forward = RotatorToForwardVector(cameraParams->ViewRotation); - FVector backward = forward * -1.0f; - // Max distance desired - float maxDistance = g_TransitionCameraOffset; - FVector desired = start + (backward * maxDistance); + FVector backward = forward * -1.f; + // --- ENGINE OFFSET (full) --- + FVector engineOffset = engineCamPos - pawnPos; + // --- DECOMPOSE OFFSET --- + // Projection of engine offset onto backward axis (recul moteur) + float engineBackDist = engineOffset.Dot(backward); + g_NativeCameraDistance = engineBackDist; + FVector backComponent = backward * engineBackDist; - // --- Sphere trace --- - float radius = 8.0f; + if (bIsInCinematicMode || bIsInPrinterMode || bIsInventoryOpen || bIsAiming) return; + + // What we KEEP (height + lateral) + FVector preservedOffset = engineOffset - backComponent; + + // --- Desired corrected distance --- + float maxDistance = g_TransitionCameraOffset; + FVector traceStart = pawnPos /*+ preservedOffset*/; + FVector traceEnd = traceStart + backward * maxDistance; + + // --- Sphere Trace --- TArray ignoreActors; TArray hits; - // Collision detection + float radius = 12.f; + bool bHit = UKismetSystemLibrary::SphereTraceMulti( - object, // WorldContextObject - start, - desired, + object, + traceStart, + traceEnd, radius, - ETraceTypeQuery::TraceTypeQuery1, - true, // bTraceComplex + ETraceTypeQuery::TraceTypeQuery2, // camera channel + true, ignoreActors, EDrawDebugTrace::None, &hits, - true, // bIgnoreSelf + true, FLinearColor(1, 0, 0, 1), FLinearColor(0, 1, 0, 1), - 0.0f - ); + 0.f); + // --- Compute target distance --- float targetDist = maxDistance; - if (bHit && hits.Num() > 0) { + + if (bHit && hits.Num() > 0) + { float best = maxDistance; - float tracePadding = 10.0f; // Padding to avoid camera too close to obstacle - float minAllowedDist = 5.0f; // To not approach walls + float padding = 15.f; - for (int i = 0; i < hits.Num(); i++) { - const FHitResult& hit = hits[i]; + for (const FHitResult& hit : hits) + { if (hit.bStartPenetrating) continue; - if (hit.PenetrationDepth > 2.0f) continue; + if (hit.PenetrationDepth > 2.f) continue; + + float dist = (hit.Location - traceStart).Magnitude(); + dist -= padding; + dist = std::max(dist, 0.f); - FVector local = hit.Location - start; - float dist = local.Magnitude(); - dist -= tracePadding; - if (dist < minAllowedDist) dist = minAllowedDist; if (dist < best) best = dist; } targetDist = best; } - // --- Init lastSafeDistance --- - if (lastSafeDistance < 0.0f) lastSafeDistance = targetDist; - // --- Lerp based on DeltaTime for smoothing rotation --- - float lerpSpeed = (targetDist < lastSafeDistance) ? 12.f : 6.f; // Fast if obstacle, slow otherwise - float alpha = std::clamp(lerpSpeed * cameraParams->DeltaTime, 0.0f, 1.0f); + + // --- Smoothing --- + static float lastSafeDistance = -1.f; + if (lastSafeDistance < 0.f) lastSafeDistance = targetDist; + + float interpSpeed = (targetDist < lastSafeDistance) ? 14.f : 6.f; + float alpha = std::clamp(interpSpeed * cameraParams->DeltaTime, 0.f, 1.f); lastSafeDistance = UKismetMathLibrary::Lerp(lastSafeDistance, targetDist, alpha); - lastSafeDistance = std::clamp(lastSafeDistance, 0.0f, maxDistance); // Security clamp - FVector final = start + (backward * lastSafeDistance); // Final position - // --- Final camera --- - cameraParams->NewViewLocation = final; + lastSafeDistance = std::clamp(lastSafeDistance, 0.f, maxDistance); + + // --- FINAL CAMERA POSITION --- + FVector finalCamPos = pawnPos + preservedOffset + + backward * lastSafeDistance; + + if (!world->K2_GetWorldSettings()) return; + // --- APPLY --- + cameraParams->NewViewLocation = finalCamPos; cameraParams->NewViewRotation = cameraParams->ViewRotation; cameraParams->NewFOV = cameraParams->FOV; } + } }); } @@ -391,18 +472,24 @@ static void CameraFixEnabled() { CameraHook = safetyhook::create_mid(Cameraaddress, [](SafetyHookContext& ctx) { if (bIsInCinematicMode) { - g_TransitionCameraOffset = 0.f; // No smooth transition to avoid fall into the world - return; - } - // Fade in & out - if (bIsInventoryOpen) { - g_TransitionCameraOffset -= (float)g_CameraOffset / 40; - g_TransitionCameraOffset = std::max(g_TransitionCameraOffset, 0.f); - } - else { // Fade out for inventory and cutscenes - g_TransitionCameraOffset += (float)g_CameraOffset / 40; - g_TransitionCameraOffset = std::min(g_TransitionCameraOffset,(float)g_CameraOffset); + double now = NowSeconds(); + if ((now - LastCineCallTime) > 1.0) // 1 seconde sans appel + bIsInCinematicMode = false; } + + float dt = g_LastCameraDeltaTime; + float fadeInSpeed = 3.5f; // vitesse quand on RAPPROCHE la caméra + float fadeOutSpeed = 3.5f; // vitesse quand on RECULE la caméra + // sécurité + if (dt <= 0.f || dt > 0.1f) dt = 1.f / 60.f; + + float targetOffset = (bIsInventoryOpen || bIsInPrinterMode || bIsInCinematicMode || bIsAiming) ? + g_NativeCameraDistance : // Minimum offset + (float)g_CameraOffset; // User offset + float interpSpeed = (targetOffset < g_TransitionCameraOffset) ? fadeInSpeed : fadeOutSpeed; + + g_TransitionCameraOffset = UKismetMathLibrary::FInterpTo(g_TransitionCameraOffset, + targetOffset,dt,interpSpeed); }); } else CameraHook.enable(); @@ -434,6 +521,12 @@ static void HUDFixEnabled() { } } +// Memory patch fixes +static void UltraWideFixEnabled() { + if (ConstrainAspectaddress) + Memory::PatchBytes(ConstrainAspectaddress, "\x31\xC0\x90\x90\x90\x90\x90", 7); // bConstrainAspectRatio = 0 +} + static void CAFixEnabled() { if (g_fix_enabled && g_CA_fix_enabled && CAaddress) { Memory::PatchBytes(CAaddress, "\x90\x90", 2); // NOP jg "HellIsUs-Win64-Shipping.exe"+3D73BD5 r.SceneColorFringeQuality = 0 @@ -445,7 +538,6 @@ static void CAFixEnabled() { } } -// Memory patch fixes static void VignettingFixEnabled() { if (g_fix_enabled && g_Vignetting_fix_enabled && Vignettingaddress) { Memory::PatchBytes(Vignettingaddress, "\x31\xC9", 2); // xor ecx,ecx r.Tonemapper.Quality=0