diff --git a/Alphanium/Source/Features.cpp b/Alphanium/Source/Features.cpp index 425b6c8..a07f994 100644 --- a/Alphanium/Source/Features.cpp +++ b/Alphanium/Source/Features.cpp @@ -295,11 +295,43 @@ void Features::RefreshActorCache() { void Features::RenderSpawningTab() { ImGui::Text("Husk Spawning:"); - if (ImGui::Button("Spawn Husk (No AI / T-Pose)")) { - SpawnHusk(false); - } - if (ImGui::Button("Spawn Husk (With AI)")) { - SpawnHusk(true); + static const char* kHuskOptions[] = { + "WerewolfPawn_C", + "FlingerPawn_C", + "TakerPawn_C", + "TrollPawn_C", + "BlasterPawn_C", + "HuskPawn_Beehive_C", + "HuskPawn_Bombshell_Poison_C", + "HuskPawn_Bombshell_C", + "HuskPawn_Dwarf_Fire_C", + "HuskPawn_Dwarf_Ice_C", + "HuskPawn_Dwarf_Lightning_C", + "HuskPawn_Dwarf_C", + "HuskPawn_Fire_C", + "HuskPawn_Husky_Fire_C", + "HuskPawn_Husky_Ice_C", + "HuskPawn_Husky_Lightning_C", + "HuskPawn_Husky_C", + "HuskPawn_Ice_C", + "HuskPawn_Lightning_C", + "HuskPawn_Pitcher_C", + "HuskPawn_Sploder_C", + "HuskPawn_Trashman_C", + "HuskPawn_C", + "SmasherPawn_Boss_C", + "SmasherPawn_Fire_C", + "SmasherPawn_Ice_C", + "SmasherPawn_Lightning_C", + "SmasherPawn_C", + "SmasherPawn_BossRampage_C", + }; + static int selectedHusk = 0; + ImGui::Combo("Husk Type", &selectedHusk, kHuskOptions, static_cast(std::size(kHuskOptions))); + static bool withAI = true; + ImGui::Checkbox("With AI", &withAI); + if (ImGui::Button("Spawn Husk")) { + SpawnHusk(kHuskOptions[selectedHusk], withAI); } } @@ -462,14 +494,19 @@ void Features::ProcessPendingCommands() { lastCommandRun_ = now; } -void Features::SpawnHusk(bool withAI) { +void Features::SpawnHusk(const std::string& huskClassName, bool withAI) { auto controller = GetLocalPlayerController(); if (!controller) { return; } - SDK::UObject* huskClass = FindObjectByName(L"Class FortniteGame.FortAIPawn_Husk"); + if (huskClassName.empty()) { + return; + } + std::wstring className(huskClassName.begin(), huskClassName.end()); + std::wstring fullClassName = L"Class FortniteGame." + className; + SDK::UObject* huskClass = FindObjectByName(fullClassName); if (!huskClass) { - huskClass = FindObjectByName(L"Husk"); + huskClass = FindObjectByName(className); } if (!huskClass) { return; @@ -484,8 +521,12 @@ void Features::SpawnHusk(bool withAI) { } SDK::FVector spawnLoc{0.0f, 0.0f, 300.0f}; if (controller->AcknowledgedPawn) { - spawnLoc = controller->AcknowledgedPawn->K2_GetActorLocation(); - spawnLoc.X += 200.0f; + auto pawn = reinterpret_cast(controller->AcknowledgedPawn); + spawnLoc = pawn->K2_GetActorLocation(); + SDK::FVector forward = pawn->GetActorForwardVector(); + spawnLoc.X += forward.X * 10.0f; + spawnLoc.Y += forward.Y * 10.0f; + spawnLoc.Z += forward.Z * 10.0f; } struct SpawnParams { SDK::UClass* Class; diff --git a/Alphanium/Source/Features.h b/Alphanium/Source/Features.h index 312ac91..c0b7b82 100644 --- a/Alphanium/Source/Features.h +++ b/Alphanium/Source/Features.h @@ -39,7 +39,7 @@ private: void ReloadMap(); void ApplyMovementCheats(); - void SpawnHusk(bool withAI); + void SpawnHusk(const std::string& huskClassName, bool withAI); void SetupGameplay(); void StartContentScan(); void ProcessScanResults(); diff --git a/Alphanium/Source/ImGuiLayer.cpp b/Alphanium/Source/ImGuiLayer.cpp index afae22e..05b9ece 100644 --- a/Alphanium/Source/ImGuiLayer.cpp +++ b/Alphanium/Source/ImGuiLayer.cpp @@ -19,21 +19,21 @@ bool ImGuiLayer::Initialize(IDirect3DDevice9* device) { LogMessage("ImGuiLayer::Initialize: device null"); return false; } - device_ = device; + gameDevice_ = device; D3DDEVICE_CREATION_PARAMETERS params{}; - if (FAILED(device_->GetCreationParameters(¶ms))) { + if (FAILED(gameDevice_->GetCreationParameters(¶ms))) { return false; } - hwnd_ = params.hFocusWindow; + gameHwnd_ = params.hFocusWindow; if (!contextInitialized_) { ImGui::CreateContext(); contextInitialized_ = true; } if (!backendInitialized_) { - ImGui_ImplWin32_Init(hwnd_); - ImGui_ImplDX9_Init(device_); + ImGui_ImplWin32_Init(gameHwnd_); + ImGui_ImplDX9_Init(gameDevice_); backendInitialized_ = true; - LogMessage("ImGuiLayer::Initialize: backend initialized hwnd=%p device=%p", hwnd_, device_); + LogMessage("ImGuiLayer::Initialize: backend initialized hwnd=%p device=%p", gameHwnd_, gameDevice_); } threadedRender_ = false; return true; @@ -44,7 +44,7 @@ bool ImGuiLayer::InitializeStandalone(HWND hwnd) { LogMessage("ImGuiLayer::InitializeStandalone: hwnd null"); return false; } - hwnd_ = hwnd; + standaloneHwnd_ = hwnd; if (!contextInitialized_) { ImGui::CreateContext(); contextInitialized_ = true; @@ -57,17 +57,17 @@ bool ImGuiLayer::InitializeStandaloneDevice(HWND hwnd, IDirect3DDevice9* device) LogMessage("ImGuiLayer::InitializeStandaloneDevice: invalid hwnd/device hwnd=%p device=%p", hwnd, device); return false; } - hwnd_ = hwnd; - device_ = device; + standaloneHwnd_ = hwnd; + standaloneDevice_ = device; if (!contextInitialized_) { ImGui::CreateContext(); contextInitialized_ = true; } if (!backendInitialized_) { - ImGui_ImplWin32_Init(hwnd_); - ImGui_ImplDX9_Init(device_); + ImGui_ImplWin32_Init(standaloneHwnd_); + ImGui_ImplDX9_Init(standaloneDevice_); backendInitialized_ = true; - LogMessage("ImGuiLayer::InitializeStandaloneDevice: backend initialized hwnd=%p device=%p", hwnd_, device_); + LogMessage("ImGuiLayer::InitializeStandaloneDevice: backend initialized hwnd=%p device=%p", standaloneHwnd_, standaloneDevice_); } threadedRender_ = false; return true; @@ -87,8 +87,10 @@ void ImGuiLayer::Shutdown() { contextInitialized_ = false; LogMessage("ImGuiLayer::Shutdown: context destroyed"); } - device_ = nullptr; - hwnd_ = nullptr; + gameDevice_ = nullptr; + gameHwnd_ = nullptr; + standaloneDevice_ = nullptr; + standaloneHwnd_ = nullptr; } void ImGuiLayer::RenderForPresent() { @@ -100,7 +102,7 @@ void ImGuiLayer::RenderForEndScene() { } void ImGuiLayer::RenderStandalone() { - RenderInternal(false); + RenderInternal(standaloneDevice_, standaloneHwnd_, false); } void ImGuiLayer::StartRenderThread() { @@ -123,7 +125,7 @@ void ImGuiLayer::StartRenderThread() { frameRequested_ = false; beginScene = nextBeginScene_; } - RenderInternal(beginScene); + RenderInternal(gameDevice_, gameHwnd_, beginScene); } LogMessage("ImGuiLayer::RenderThread: exiting"); }); @@ -144,7 +146,7 @@ void ImGuiLayer::StopRenderThread() { void ImGuiLayer::RequestFrame(bool beginScene) { if (!threadedRender_) { - RenderInternal(beginScene); + RenderInternal(gameDevice_, gameHwnd_, beginScene); return; } if (!renderThreadRunning_.load()) { @@ -158,14 +160,14 @@ void ImGuiLayer::RequestFrame(bool beginScene) { frameCv_.notify_one(); } -void ImGuiLayer::RenderInternal(bool beginScene) { - if (!device_ || !hwnd_) { - LogMessage("ImGuiLayer::RenderInternal: device/hwnd missing device=%p hwnd=%p", device_, hwnd_); +void ImGuiLayer::RenderInternal(IDirect3DDevice9* device, HWND hwnd, bool beginScene) { + if (!device || !hwnd) { + LogMessage("ImGuiLayer::RenderInternal: device/hwnd missing device=%p hwnd=%p", device, hwnd); return; } const auto start = std::chrono::steady_clock::now(); std::lock_guard lock(renderMutex_); - if (beginScene && FAILED(device_->BeginScene())) { + if (beginScene && FAILED(device->BeginScene())) { LogMessage("ImGuiLayer::RenderInternal: BeginScene failed"); return; } @@ -176,7 +178,7 @@ void ImGuiLayer::RenderInternal(bool beginScene) { ImGui::Render(); ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); if (beginScene) { - device_->EndScene(); + device->EndScene(); } const auto end = std::chrono::steady_clock::now(); if (lastRenderLog_ == std::chrono::steady_clock::time_point{} diff --git a/Alphanium/Source/ImGuiLayer.h b/Alphanium/Source/ImGuiLayer.h index 76367c2..3bd2692 100644 --- a/Alphanium/Source/ImGuiLayer.h +++ b/Alphanium/Source/ImGuiLayer.h @@ -22,10 +22,12 @@ private: void StartRenderThread(); void StopRenderThread(); void RequestFrame(bool beginScene); - void RenderInternal(bool beginScene); + void RenderInternal(IDirect3DDevice9* device, HWND hwnd, bool beginScene); - IDirect3DDevice9* device_ = nullptr; - HWND hwnd_ = nullptr; + IDirect3DDevice9* gameDevice_ = nullptr; + HWND gameHwnd_ = nullptr; + IDirect3DDevice9* standaloneDevice_ = nullptr; + HWND standaloneHwnd_ = nullptr; bool contextInitialized_ = false; bool backendInitialized_ = false; bool threadedRender_ = false;