From 1c0e9dd1df935dd20e340050155d35bb70fe62b5 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 1 Apr 2026 20:59:17 +0300 Subject: [PATCH] `chore(application): extract appearance controller and unify UI flow` - Refactor UI application architecture: extracted appearance controller into ui_services.hpp + implementation updates - Update UI components and managers to use new service layer: - `action_bar_panel`, `auth_screen`, `character_screen`, `chat_panel`, `combat_ui`, `dialog_manager`, `game_screen`, `settings_panel`, `social_panel`, `toast_manager`, `ui_manager`, `window_manager` - Adjust core application entrypoints: - application.cpp - Update component implementations for new controller flow: - action_bar_panel.cpp, `chat_panel.cpp`, `combat_ui.cpp`, `dialog_manager.cpp`, `game_screen.cpp`, `settings_panel.cpp`, `social_panel.cpp`, `toast_manager.cpp`, `window_manager.cpp` These staged changes implement a major architectural refactor for UI/appearance controller separation --- include/ui/action_bar_panel.hpp | 5 ++ include/ui/auth_screen.hpp | 6 ++ include/ui/character_screen.hpp | 6 ++ include/ui/chat_panel.hpp | 7 +++ include/ui/combat_ui.hpp | 7 +++ include/ui/dialog_manager.hpp | 6 ++ include/ui/game_screen.hpp | 8 ++- include/ui/settings_panel.hpp | 6 ++ include/ui/social_panel.hpp | 7 +++ include/ui/toast_manager.hpp | 7 +++ include/ui/ui_manager.hpp | 11 ++++ include/ui/ui_services.hpp | 55 +++++++++++++++++ include/ui/window_manager.hpp | 5 ++ src/core/application.cpp | 31 ++++++++++ src/ui/action_bar_panel.cpp | 10 +-- src/ui/chat_panel.cpp | 24 ++++---- src/ui/combat_ui.cpp | 20 +++--- src/ui/dialog_manager.cpp | 34 +++++----- src/ui/game_screen.cpp | 106 ++++++++++++++++++-------------- src/ui/settings_panel.cpp | 10 +-- src/ui/social_panel.cpp | 18 +++--- src/ui/toast_manager.cpp | 22 +++---- src/ui/window_manager.cpp | 38 ++++++------ 23 files changed, 315 insertions(+), 134 deletions(-) create mode 100644 include/ui/ui_services.hpp diff --git a/include/ui/action_bar_panel.hpp b/include/ui/action_bar_panel.hpp index ae650485..4a62e642 100644 --- a/include/ui/action_bar_panel.hpp +++ b/include/ui/action_bar_panel.hpp @@ -4,6 +4,7 @@ // XP bar, reputation bar, macro resolution. // ============================================================ #pragma once +#include "ui/ui_services.hpp" #include #include #include @@ -70,7 +71,11 @@ public: std::unordered_map macroPrimarySpellCache_; size_t macroCacheSpellCount_ = 0; + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { services_ = services; } + private: + UIServices services_; uint32_t resolveMacroPrimarySpellId(uint32_t macroId, game::GameHandler& gameHandler); }; diff --git a/include/ui/auth_screen.hpp b/include/ui/auth_screen.hpp index e1dbdde7..ff99d963 100644 --- a/include/ui/auth_screen.hpp +++ b/include/ui/auth_screen.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ui/ui_services.hpp" #include "auth/auth_handler.hpp" #include #include @@ -30,6 +31,9 @@ public: */ void setOnSuccess(std::function callback) { onSuccess = callback; } + /// Set services (dependency injection) + void setServices(const UIServices& services) { services_ = services; } + /** * Check if authentication is in progress @@ -44,6 +48,8 @@ public: const std::string& getStatusMessage() const { return statusMessage; } private: + UIServices services_; // Injected service references + struct ServerProfile { std::string hostname; int port = 3724; diff --git a/include/ui/character_screen.hpp b/include/ui/character_screen.hpp index aae4d6a0..c4312bc8 100644 --- a/include/ui/character_screen.hpp +++ b/include/ui/character_screen.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ui/ui_services.hpp" #include "game/game_handler.hpp" #include #include @@ -48,6 +49,9 @@ public: void setOnBack(std::function cb) { onBack = std::move(cb); } void setOnDeleteCharacter(std::function cb) { onDeleteCharacter = std::move(cb); } + /// Set services (dependency injection) + void setServices(const UIServices& services) { services_ = services; } + /** * Reset selection state (e.g., when switching servers) */ @@ -89,6 +93,8 @@ public: void selectCharacterByName(const std::string& name); private: + UIServices services_; // Injected service references + // UI state int selectedCharacterIndex = -1; bool characterSelected = false; diff --git a/include/ui/chat_panel.hpp b/include/ui/chat_panel.hpp index 50dac84b..b6528545 100644 --- a/include/ui/chat_panel.hpp +++ b/include/ui/chat_panel.hpp @@ -1,6 +1,7 @@ #pragma once #include "game/game_handler.hpp" +#include "ui/ui_services.hpp" #include #include #include @@ -109,10 +110,16 @@ public: /** Reset all chat settings to defaults. */ void restoreDefaults(); + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { services_ = services; } + /** Replace $g/$G and $n/$N gender/name placeholders in quest/chat text. */ std::string replaceGenderPlaceholders(const std::string& text, game::GameHandler& gameHandler); private: + // Section 3.5: Injected UI services (Phase B singleton breaking) + UIServices services_; + // ---- Chat input state ---- char chatInputBuffer_[512] = ""; char whisperTargetBuffer_[256] = ""; diff --git a/include/ui/combat_ui.hpp b/include/ui/combat_ui.hpp index 7d7a8058..b09d2fc4 100644 --- a/include/ui/combat_ui.hpp +++ b/include/ui/combat_ui.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ui/ui_services.hpp" #include #include #include @@ -70,6 +71,12 @@ public: SpellbookScreen& spellbookScreen); void renderThreatWindow(game::GameHandler& gameHandler); void renderBgScoreboard(game::GameHandler& gameHandler); + + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { services_ = services; } + +private: + UIServices services_; }; } // namespace ui diff --git a/include/ui/dialog_manager.hpp b/include/ui/dialog_manager.hpp index 2fd0fb19..9bd075ee 100644 --- a/include/ui/dialog_manager.hpp +++ b/include/ui/dialog_manager.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ui/ui_services.hpp" #include #include #include @@ -34,7 +35,12 @@ public: /// called in render() after reclaim corpse button void renderLateDialogs(game::GameHandler& gameHandler); + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { services_ = services; } + private: + // Section 3.5: Injected UI services + UIServices services_; // Common ImGui window flags for popup dialogs static constexpr ImGuiWindowFlags kDialogFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize; diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index 530d9778..f35bd679 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -17,6 +17,7 @@ #include "ui/social_panel.hpp" #include "ui/action_bar_panel.hpp" #include "ui/window_manager.hpp" +#include "ui/ui_services.hpp" #include #include #include @@ -54,8 +55,13 @@ public: // Dependency injection for extracted classes (Phase A singleton breaking) void setAppearanceComposer(core::AppearanceComposer* ac) { appearanceComposer_ = ac; } + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services); + private: - // Injected dependencies (replaces getInstance() calls) + // Injected UI services (Section 3.5 Phase B - replaces getInstance() calls) + UIServices services_; + // Legacy pointer for Phase A compatibility (will be removed when all callsites migrate) core::AppearanceComposer* appearanceComposer_ = nullptr; // Chat panel (extracted from GameScreen — owns all chat state and rendering) ChatPanel chatPanel_; diff --git a/include/ui/settings_panel.hpp b/include/ui/settings_panel.hpp index 36d92f85..5dd58136 100644 --- a/include/ui/settings_panel.hpp +++ b/include/ui/settings_panel.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ui/ui_services.hpp" #include #include #include @@ -149,7 +150,12 @@ public: /// Return the platform-specific settings file path static std::string getSettingsPath(); + /// Set services (dependency injection) + void setServices(const UIServices& services) { services_ = services; } + private: + UIServices services_; // Injected service references + // Keybinding customization (private — only used in Controls tab) int pendingRebindAction_ = -1; // -1 = not rebinding, otherwise action index bool awaitingKeyPress_ = false; diff --git a/include/ui/social_panel.hpp b/include/ui/social_panel.hpp index 30bce495..1eed9a93 100644 --- a/include/ui/social_panel.hpp +++ b/include/ui/social_panel.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ui/ui_services.hpp" #include #include #include @@ -71,6 +72,12 @@ public: ChatPanel& chatPanel); void renderInspectWindow(game::GameHandler& gameHandler, InventoryScreen& inventoryScreen); + + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { services_ = services; } + +private: + UIServices services_; }; } // namespace ui diff --git a/include/ui/toast_manager.hpp b/include/ui/toast_manager.hpp index 29c27983..34cafa4d 100644 --- a/include/ui/toast_manager.hpp +++ b/include/ui/toast_manager.hpp @@ -1,5 +1,6 @@ #pragma once +#include "ui/ui_services.hpp" #include #include #include @@ -40,11 +41,17 @@ public: /// Fire achievement earned toast + sound void triggerAchievementToast(uint32_t achievementId, std::string name = {}); + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { services_ = services; } + // --- public state consumed by GameScreen for the golden burst overlay --- float levelUpFlashAlpha = 0.0f; uint32_t levelUpDisplayLevel = 0; private: + // Section 3.5: Injected UI services + UIServices services_; + // ---- Ding effect (own level-up) ---- static constexpr float DING_DURATION = 4.0f; float dingTimer_ = 0.0f; diff --git a/include/ui/ui_manager.hpp b/include/ui/ui_manager.hpp index f34228d7..bdc217d9 100644 --- a/include/ui/ui_manager.hpp +++ b/include/ui/ui_manager.hpp @@ -5,6 +5,7 @@ #include "ui/character_create_screen.hpp" #include "ui/character_screen.hpp" #include "ui/game_screen.hpp" +#include "ui/ui_services.hpp" #include // Forward declare SDL_Event @@ -74,8 +75,18 @@ public: if (gameScreen) gameScreen->setAppearanceComposer(ac); } + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { + services_ = services; + if (gameScreen) gameScreen->setServices(services); + if (authScreen) authScreen->setServices(services); + if (characterScreen) characterScreen->setServices(services); + } + const UIServices& getServices() const { return services_; } + private: core::Window* window = nullptr; + UIServices services_; // Section 3.5: Injected services // UI Screens std::unique_ptr authScreen; diff --git a/include/ui/ui_services.hpp b/include/ui/ui_services.hpp new file mode 100644 index 00000000..fdcd4b2b --- /dev/null +++ b/include/ui/ui_services.hpp @@ -0,0 +1,55 @@ +#pragma once + +namespace wowee { + +// Forward declarations +namespace core { + class Window; + class EntitySpawner; + class AppearanceComposer; + class WorldLoader; +} +namespace rendering { class Renderer; } +namespace pipeline { class AssetManager; } +namespace game { + class GameHandler; + class ExpansionRegistry; +} +namespace addons { class AddonManager; } +namespace audio { class AudioCoordinator; } + +namespace ui { + +/** + * UI Services - Dependency injection container for UI components. + * + * Section 3.5: Break the singleton Phase B + * + * Replaces Application::getInstance() calls throughout UI code. + * Application creates this struct and injects it into UIManager, + * which propagates it to GameScreen and all child UI components. + * + * Owned by Application, shared as const pointers (non-owning). + */ +struct UIServices { + core::Window* window = nullptr; + rendering::Renderer* renderer = nullptr; + pipeline::AssetManager* assetManager = nullptr; + game::GameHandler* gameHandler = nullptr; + game::ExpansionRegistry* expansionRegistry = nullptr; + addons::AddonManager* addonManager = nullptr; + audio::AudioCoordinator* audioCoordinator = nullptr; + + // Extracted classes (also available individually for Phase A compatibility) + core::EntitySpawner* entitySpawner = nullptr; + core::AppearanceComposer* appearanceComposer = nullptr; + core::WorldLoader* worldLoader = nullptr; + + // Helper to check if core services are wired + bool isValid() const { + return window && renderer && assetManager && gameHandler; + } +}; + +} // namespace ui +} // namespace wowee diff --git a/include/ui/window_manager.hpp b/include/ui/window_manager.hpp index f899910b..a5f3564c 100644 --- a/include/ui/window_manager.hpp +++ b/include/ui/window_manager.hpp @@ -7,6 +7,7 @@ // equipment sets, skills. // ============================================================ #pragma once +#include "ui/ui_services.hpp" #include #include #include @@ -173,7 +174,11 @@ public: std::unordered_map extendedCostCache_; bool extendedCostDbLoaded_ = false; + // Section 3.5: UIServices injection (Phase B singleton breaking) + void setServices(const UIServices& services) { services_ = services; } + private: + UIServices services_; void loadExtendedCostDBC(); std::string formatExtendedCost(uint32_t extendedCostId, game::GameHandler& gameHandler); }; diff --git a/src/core/application.cpp b/src/core/application.cpp index 91a0aaff..e597cb91 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -39,6 +39,7 @@ #include "pipeline/wdt_loader.hpp" #include "pipeline/dbc_loader.hpp" #include "ui/ui_manager.hpp" +#include "ui/ui_services.hpp" #include "auth/auth_handler.hpp" #include "game/game_handler.hpp" #include "game/transport_manager.hpp" @@ -227,6 +228,20 @@ bool Application::initialize() { // Wire AppearanceComposer to UI components (Phase A singleton breaking) if (uiManager) { uiManager->setAppearanceComposer(appearanceComposer_.get()); + + // Wire all services to UI components (Phase B singleton breaking) + ui::UIServices uiServices; + uiServices.window = window.get(); + uiServices.renderer = renderer.get(); + uiServices.assetManager = assetManager.get(); + uiServices.gameHandler = gameHandler.get(); + uiServices.expansionRegistry = expansionRegistry_.get(); + uiServices.addonManager = addonManager_.get(); // May be nullptr here, re-wire later + uiServices.audioCoordinator = audioCoordinator_.get(); + uiServices.entitySpawner = entitySpawner_.get(); + uiServices.appearanceComposer = appearanceComposer_.get(); + uiServices.worldLoader = worldLoader_.get(); + uiManager->setServices(uiServices); } // Ensure the main in-world CharacterRenderer can load textures immediately. @@ -505,6 +520,22 @@ bool Application::initialize() { entitySpawner_.get(), appearanceComposer_.get(), window.get(), world.get(), addonManager_.get()); + // Re-wire UIServices now that all services (addonManager_, worldLoader_) are available + if (uiManager) { + ui::UIServices uiServices; + uiServices.window = window.get(); + uiServices.renderer = renderer.get(); + uiServices.assetManager = assetManager.get(); + uiServices.gameHandler = gameHandler.get(); + uiServices.expansionRegistry = expansionRegistry_.get(); + uiServices.addonManager = addonManager_.get(); + uiServices.audioCoordinator = audioCoordinator_.get(); + uiServices.entitySpawner = entitySpawner_.get(); + uiServices.appearanceComposer = appearanceComposer_.get(); + uiServices.worldLoader = worldLoader_.get(); + uiManager->setServices(uiServices); + } + // Start background preload for last-played character's world. // Warms the file cache so terrain tile loading is faster at Enter World. { diff --git a/src/ui/action_bar_panel.cpp b/src/ui/action_bar_panel.cpp index 7ab39af4..49460c14 100644 --- a/src/ui/action_bar_panel.cpp +++ b/src/ui/action_bar_panel.cpp @@ -172,7 +172,7 @@ void ActionBarPanel::renderActionBar(game::GameHandler& gameHandler, ImVec2 displaySize = ImGui::GetIO().DisplaySize; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenH = displaySize.y > 0.0f ? displaySize.y : 720.0f; - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; float slotSize = 48.0f * settingsPanel.pendingActionBarScale; float spacing = 4.0f; @@ -1107,7 +1107,7 @@ void ActionBarPanel::renderStanceBar(game::GameHandler& gameHandler, ImVec2 displaySize = ImGui::GetIO().DisplaySize; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenH = displaySize.y > 0.0f ? displaySize.y : 720.0f; - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; // Match the action bar slot size so they align neatly float slotSize = 38.0f; @@ -1196,7 +1196,7 @@ void ActionBarPanel::renderBagBar(game::GameHandler& gameHandler, ImVec2 displaySize = ImGui::GetIO().DisplaySize; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenH = displaySize.y > 0.0f ? displaySize.y : 720.0f; - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; float slotSize = 42.0f; float spacing = 4.0f; @@ -1232,7 +1232,7 @@ void ActionBarPanel::renderBagBar(game::GameHandler& gameHandler, if (!blpData.empty()) { auto image = pipeline::BLPLoader::load(blpData); if (image.isValid()) { - auto* w = core::Application::getInstance().getWindow(); + auto* w = services_.window; auto* vkCtx = w ? w->getVkContext() : nullptr; if (vkCtx) backpackIconTexture_ = vkCtx->uploadImGuiTexture(image.data.data(), image.width, image.height); @@ -1483,7 +1483,7 @@ void ActionBarPanel::renderXpBar(game::GameHandler& gameHandler, ImVec2 displaySize = ImGui::GetIO().DisplaySize; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenH = displaySize.y > 0.0f ? displaySize.y : 720.0f; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; (void)window; // Not used for positioning; kept for AssetManager if needed // Position just above both action bars (bar1 at screenH-barH, bar2 above that) diff --git a/src/ui/chat_panel.cpp b/src/ui/chat_panel.cpp index 8a6d0ef3..19ff5331 100644 --- a/src/ui/chat_panel.cpp +++ b/src/ui/chat_panel.cpp @@ -197,8 +197,8 @@ void ChatPanel::render(game::GameHandler& gameHandler, InventoryScreen& inventoryScreen, SpellbookScreen& spellbookScreen, QuestLogScreen& questLogScreen) { - auto* window = core::Application::getInstance().getWindow(); - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* window = services_.window; + auto* assetMgr = services_.assetManager; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; float chatW = std::min(500.0f, screenW * 0.4f); @@ -1109,7 +1109,7 @@ void ChatPanel::render(game::GameHandler& gameHandler, std::string bodyLower = mMsg.message; for (auto& c : bodyLower) c = static_cast(std::tolower(static_cast(c))); if (bodyLower.find(selfNameLower) != std::string::npos) { - if (auto* renderer = core::Application::getInstance().getRenderer()) { + if (auto* renderer = services_.renderer) { if (auto* ui = renderer->getUiSoundManager()) ui->playWhisperReceived(); } @@ -2151,7 +2151,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler, // /run — execute Lua script via addon system if ((cmdLower == "run" || cmdLower == "script") && spacePos != std::string::npos) { std::string luaCode = command.substr(spacePos + 1); - auto* am = core::Application::getInstance().getAddonManager(); + auto* am = services_.addonManager; if (am) { am->runScript(luaCode); } else { @@ -2164,7 +2164,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler, // /dump — evaluate Lua expression and print result if ((cmdLower == "dump" || cmdLower == "print") && spacePos != std::string::npos) { std::string expr = command.substr(spacePos + 1); - auto* am = core::Application::getInstance().getAddonManager(); + auto* am = services_.addonManager; if (am && am->isInitialized()) { // Wrap expression in print(tostring(...)) to display the value std::string wrapped = "local __v = " + expr + @@ -2187,7 +2187,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler, // Check addon slash commands (SlashCmdList) before built-in commands { - auto* am = core::Application::getInstance().getAddonManager(); + auto* am = services_.addonManager; if (am && am->isInitialized()) { std::string slashCmd = "/" + cmdLower; std::string slashArgs; @@ -2214,7 +2214,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler, // /reload or /reloadui — reload all addons (save variables, re-init Lua, re-scan .toc files) if (cmdLower == "reload" || cmdLower == "reloadui" || cmdLower == "rl") { - auto* am = core::Application::getInstance().getAddonManager(); + auto* am = services_.addonManager; if (am) { am->reload(); am->fireEvent("VARIABLES_LOADED"); @@ -2301,7 +2301,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler, if (cmdLower == "loc" || cmdLower == "coords" || cmdLower == "whereami") { const auto& pmi = gameHandler.getMovementInfo(); std::string zoneName; - if (auto* rend = core::Application::getInstance().getRenderer()) + if (auto* rend = services_.renderer) zoneName = rend->getCurrentZoneName(); char buf[256]; snprintf(buf, sizeof(buf), "%.1f, %.1f, %.1f%s%s", @@ -2327,7 +2327,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler, // /zone command — print current zone name if (cmdLower == "zone") { std::string zoneName; - if (auto* rend = core::Application::getInstance().getRenderer()) + if (auto* rend = services_.renderer) zoneName = rend->getCurrentZoneName(); game::MessageChatData sysMsg; sysMsg.type = game::ChatType::SYSTEM; @@ -4323,7 +4323,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler, std::string emoteText = rendering::Renderer::getEmoteText(cmdLower, targetNamePtr); if (!emoteText.empty()) { // Play the emote animation - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { renderer->playEmote(cmdLower); } @@ -4697,11 +4697,11 @@ std::string ChatPanel::replaceGenderPlaceholders(const std::string& text, game:: void ChatPanel::renderBubbles(game::GameHandler& gameHandler) { if (chatBubbles_.empty()) return; - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; auto* camera = renderer ? renderer->getCamera() : nullptr; if (!camera) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; diff --git a/src/ui/combat_ui.cpp b/src/ui/combat_ui.cpp index 8ba732e7..17b6e0c9 100644 --- a/src/ui/combat_ui.cpp +++ b/src/ui/combat_ui.cpp @@ -60,7 +60,7 @@ namespace ui { void CombatUI::renderCastBar(game::GameHandler& gameHandler, SpellIconFn getSpellIcon) { if (!gameHandler.isCasting()) return; - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; ImVec2 displaySize = ImGui::GetIO().DisplaySize; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; @@ -187,8 +187,8 @@ void CombatUI::renderCooldownTracker(game::GameHandler& gameHandler, return a.remaining > b.remaining; }); - auto* assetMgr = core::Application::getInstance().getAssetManager(); - auto* window = core::Application::getInstance().getWindow(); + auto* assetMgr = services_.assetManager; + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -268,7 +268,7 @@ void CombatUI::renderRaidWarningOverlay(game::GameHandler& gameHandler) { // Walk only the new messages (deque — iterate from back by skipping old ones) size_t toScan = newCount - raidWarnChatSeenCount_; size_t startIdx = newCount > toScan ? newCount - toScan : 0; - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; for (size_t i = startIdx; i < newCount; ++i) { const auto& msg = chatHistory[i]; if (msg.type == game::ChatType::RAID_WARNING || @@ -361,13 +361,13 @@ void CombatUI::renderCombatText(game::GameHandler& gameHandler) { const auto& entries = gameHandler.getCombatText(); if (entries.empty()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; if (!window) return; const float screenW = static_cast(window->getWidth()); const float screenH = static_cast(window->getHeight()); // Camera for world-space projection - auto* appRenderer = core::Application::getInstance().getRenderer(); + auto* appRenderer = services_.renderer; rendering::Camera* camera = appRenderer ? appRenderer->getCamera() : nullptr; glm::mat4 viewProj; if (camera) viewProj = camera->getProjectionMatrix() * camera->getViewMatrix(); @@ -785,7 +785,7 @@ void CombatUI::renderDPSMeter(game::GameHandler& gameHandler, fmtNum(hps, hpsBuf, sizeof(hpsBuf)); // Position: small floating label just above the action bar, right of center - auto* appWin = core::Application::getInstance().getWindow(); + auto* appWin = services_.window; float screenW = appWin ? static_cast(appWin->getWidth()) : 1280.0f; float screenH = appWin ? static_cast(appWin->getHeight()) : 720.0f; @@ -866,7 +866,7 @@ void CombatUI::renderBuffBar(game::GameHandler& gameHandler, } if (activeCount == 0 && !gameHandler.hasPet()) return; - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; // Position below the minimap (minimap: 200x200 at top-right, bottom edge at Y≈210) // Anchored to the right side to stay away from party frames on the left @@ -1201,7 +1201,7 @@ void CombatUI::renderBattlegroundScore(game::GameHandler& gameHandler) { if (auto mv = gameHandler.getWorldState(def->maxKey)) maxScore = *mv; } - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; // Width scales with screen but stays reasonable @@ -1598,7 +1598,7 @@ void CombatUI::renderCombatLog(game::GameHandler& gameHandler, ImGui::TextColored(color, "%s", desc); // Hover tooltip: show rich spell info for entries with a known spell if (e.spellId != 0 && ImGui::IsItemHovered()) { - auto* assetMgrLog = core::Application::getInstance().getAssetManager(); + auto* assetMgrLog = services_.assetManager; ImGui::BeginTooltip(); bool richOk = spellbookScreen.renderSpellInfoTooltip(e.spellId, gameHandler, assetMgrLog); if (!richOk) { diff --git a/src/ui/dialog_manager.cpp b/src/ui/dialog_manager.cpp index dd90a990..0677efb3 100644 --- a/src/ui/dialog_manager.cpp +++ b/src/ui/dialog_manager.cpp @@ -69,7 +69,7 @@ void DialogManager::renderLateDialogs(game::GameHandler& gameHandler) { void DialogManager::renderGroupInvitePopup(game::GameHandler& gameHandler) { if (!gameHandler.hasPendingGroupInvite()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 200), ImGuiCond_Always); @@ -93,7 +93,7 @@ void DialogManager::renderGroupInvitePopup(game::GameHandler& gameHandler) { void DialogManager::renderDuelRequestPopup(game::GameHandler& gameHandler) { if (!gameHandler.hasPendingDuelRequest()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 250), ImGuiCond_Always); @@ -158,7 +158,7 @@ void DialogManager::renderDuelCountdown(game::GameHandler& gameHandler) { void DialogManager::renderItemTextWindow(game::GameHandler& gameHandler) { if (!gameHandler.isItemTextOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -194,7 +194,7 @@ void DialogManager::renderItemTextWindow(game::GameHandler& gameHandler) { void DialogManager::renderSharedQuestPopup(game::GameHandler& gameHandler) { if (!gameHandler.hasPendingSharedQuest()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 490), ImGuiCond_Always); @@ -224,7 +224,7 @@ void DialogManager::renderSummonRequestPopup(game::GameHandler& gameHandler) { gameHandler.tickSummonTimeout(dt); if (!gameHandler.hasPendingSummonRequest()) return; // expired - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 430), ImGuiCond_Always); @@ -252,7 +252,7 @@ void DialogManager::renderSummonRequestPopup(game::GameHandler& gameHandler) { void DialogManager::renderTradeRequestPopup(game::GameHandler& gameHandler) { if (!gameHandler.hasPendingTradeRequest()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 370), ImGuiCond_Always); @@ -284,7 +284,7 @@ void DialogManager::renderTradeWindow(game::GameHandler& gameHandler, const uint64_t peerGold = gameHandler.getPeerTradeGold(); const auto& peerName = gameHandler.getTradePeerName(); - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -443,7 +443,7 @@ void DialogManager::renderLootRollPopup(game::GameHandler& gameHandler, const auto& roll = gameHandler.getPendingLootRoll(); - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 310), ImGuiCond_Always); @@ -584,7 +584,7 @@ void DialogManager::renderLootRollPopup(game::GameHandler& gameHandler, void DialogManager::renderGuildInvitePopup(game::GameHandler& gameHandler) { if (!gameHandler.hasPendingGuildInvite()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 250), ImGuiCond_Always); @@ -610,7 +610,7 @@ void DialogManager::renderGuildInvitePopup(game::GameHandler& gameHandler) { void DialogManager::renderReadyCheckPopup(game::GameHandler& gameHandler) { if (!gameHandler.hasPendingReadyCheck()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -684,7 +684,7 @@ void DialogManager::renderBgInvitePopup(game::GameHandler& gameHandler) { return; } - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -745,7 +745,7 @@ void DialogManager::renderBfMgrInvitePopup(game::GameHandler& gameHandler) { // Only shown on WotLK servers (outdoor battlefields like Wintergrasp use the BF Manager) if (!gameHandler.hasBfMgrInvite()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -802,7 +802,7 @@ void DialogManager::renderLfgProposalPopup(game::GameHandler& gameHandler) { using LfgState = game::GameHandler::LfgState; if (gameHandler.getLfgState() != LfgState::Proposal) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -851,7 +851,7 @@ void DialogManager::renderLfgRoleCheckPopup(game::GameHandler& gameHandler) { using LfgState = game::GameHandler::LfgState; if (gameHandler.getLfgState() != LfgState::RoleCheck) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -915,7 +915,7 @@ void DialogManager::renderLfgRoleCheckPopup(game::GameHandler& gameHandler) { void DialogManager::renderResurrectDialog(game::GameHandler& gameHandler) { if (!gameHandler.showResurrectDialog()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -976,7 +976,7 @@ void DialogManager::renderResurrectDialog(game::GameHandler& gameHandler) { void DialogManager::renderTalentWipeConfirmDialog(game::GameHandler& gameHandler) { if (!gameHandler.showTalentWipeConfirmDialog()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -1046,7 +1046,7 @@ void DialogManager::renderTalentWipeConfirmDialog(game::GameHandler& gameHandler void DialogManager::renderPetUnlearnConfirmDialog(game::GameHandler& gameHandler) { if (!gameHandler.showPetUnlearnDialog()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index d18566fb..1119a7d4 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -250,6 +250,22 @@ GameScreen::GameScreen() { loadSettings(); } +// Section 3.5: Set UI services and propagate to child components +void GameScreen::setServices(const UIServices& services) { + services_ = services; + // Update legacy pointer for Phase A compatibility + appearanceComposer_ = services.appearanceComposer; + // Propagate to child panels + chatPanel_.setServices(services); + toastManager_.setServices(services); + dialogManager_.setServices(services); + settingsPanel_.setServices(services); + combatUI_.setServices(services); + socialPanel_.setServices(services); + actionBarPanel_.setServices(services); + windowManager_.setServices(services); +} + void GameScreen::render(game::GameHandler& gameHandler) { // Set up chat bubble callback (once) and cache game handler in ChatPanel chatPanel_.setupCallbacks(gameHandler); @@ -269,7 +285,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { uiErrors_.push_back({msg, 0.0f}); if (uiErrors_.size() > 5) uiErrors_.erase(uiErrors_.begin()); // Play error sound for each new error (rate-limited by deque cap of 5) - if (auto* r = core::Application::getInstance().getRenderer()) { + if (auto* r = services_.renderer) { if (auto* sfx = r->getUiSoundManager()) sfx->playError(); } }); @@ -292,7 +308,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Sync minimap opacity with UI opacity { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { if (auto* minimap = renderer->getMinimap()) { minimap->setOpacity(settingsPanel_.uiOpacity_); @@ -302,7 +318,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Apply initial settings when renderer becomes available if (!settingsPanel_.minimapSettingsApplied_) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { if (auto* minimap = renderer->getMinimap()) { settingsPanel_.minimapRotate_ = false; @@ -329,7 +345,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Apply saved volume settings once when audio managers first become available if (!settingsPanel_.volumeSettingsApplied_) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer && renderer->getUiSoundManager()) { settingsPanel_.applyAudioVolumes(renderer); settingsPanel_.volumeSettingsApplied_ = true; @@ -338,7 +354,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Apply saved MSAA setting once when renderer is available if (!settingsPanel_.msaaSettingsApplied_ && settingsPanel_.pendingAntiAliasing > 0) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { static const VkSampleCountFlagBits aaSamples[] = { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT, @@ -353,7 +369,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Apply saved FXAA setting once when renderer is available if (!settingsPanel_.fxaaSettingsApplied_) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { renderer->setFXAAEnabled(settingsPanel_.pendingFXAA); settingsPanel_.fxaaSettingsApplied_ = true; @@ -362,7 +378,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Apply saved water refraction setting once when renderer is available if (!settingsPanel_.waterRefractionApplied_) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { renderer->setWaterRefractionEnabled(settingsPanel_.pendingWaterRefraction); settingsPanel_.waterRefractionApplied_ = true; @@ -371,7 +387,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Apply saved normal mapping / POM settings once when WMO renderer is available if (!settingsPanel_.normalMapSettingsApplied_) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { if (auto* wr = renderer->getWMORenderer()) { wr->setNormalMappingEnabled(settingsPanel_.pendingNormalMapping); @@ -391,7 +407,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { // Apply saved upscaling setting once when renderer is available if (!settingsPanel_.fsrSettingsApplied_) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { static constexpr float fsrScales[] = { 0.77f, 0.67f, 0.59f, 1.00f }; settingsPanel_.pendingFSRQuality = std::clamp(settingsPanel_.pendingFSRQuality, 0, 3); @@ -562,7 +578,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { questLogScreen.render(gameHandler, inventoryScreen); // Spellbook (P key toggle handled inside) - spellbookScreen.render(gameHandler, core::Application::getInstance().getAssetManager()); + spellbookScreen.render(gameHandler, services_.assetManager); // Insert spell link into chat if player shift-clicked a spellbook entry { @@ -579,7 +595,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { { uint64_t activeGuid = gameHandler.getActiveCharacterGuid(); if (activeGuid != 0 && activeGuid != inventoryScreenCharGuid_) { - auto* am = core::Application::getInstance().getAssetManager(); + auto* am = services_.assetManager; if (am) { inventoryScreen.setAssetManager(am); const auto* ch = gameHandler.getActiveCharacter(); @@ -635,7 +651,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { if (appearanceComposer_) appearanceComposer_->loadEquippedWeapons(); inventoryScreen.markPreviewDirty(); // Update renderer weapon type for animation selection - auto* r = core::Application::getInstance().getRenderer(); + auto* r = services_.renderer; if (r) { const auto& mh = gameHandler.getInventory().getEquipSlot(game::EquipSlot::MAIN_HAND); r->setEquippedWeaponType(mh.empty() ? 0 : mh.item.inventoryType); @@ -643,7 +659,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { } // Update renderer face-target position and selection circle - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { renderer->setInCombat(gameHandler.isInCombat() && !gameHandler.isPlayerDead() && @@ -1202,9 +1218,9 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { // Cursor affordance: show hand cursor over interactable entities. if (!io.WantCaptureMouse) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; auto* camera = renderer ? renderer->getCamera() : nullptr; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; if (camera && window) { glm::vec2 mousePos = input.getMousePosition(); float screenW = static_cast(window->getWidth()); @@ -1258,9 +1274,9 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { constexpr float CLICK_THRESHOLD = 5.0f; // pixels if (dragDistSq < CLICK_THRESHOLD * CLICK_THRESHOLD) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; auto* camera = renderer ? renderer->getCamera() : nullptr; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; if (camera && window) { float screenW = static_cast(window->getWidth()); @@ -1355,9 +1371,9 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { // If no target or right-clicking in world, try to pick one under cursor { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; auto* camera = renderer ? renderer->getCamera() : nullptr; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; if (camera && window) { // If a quest objective gameobject is under the cursor, prefer it over // hostile units so quest pickups (e.g. "Bundle of Wood") are reliable. @@ -1648,7 +1664,7 @@ void GameScreen::renderPlayerFrame(game::GameHandler& gameHandler) { ImGui::TextColored(ImVec4(0.9f, 0.5f, 0.2f, 1.0f), ""); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Do not disturb — /dnd to cancel"); } - if (auto* ren = core::Application::getInstance().getRenderer()) { + if (auto* ren = services_.renderer) { if (auto* cam = ren->getCameraController()) { if (cam->isAutoRunning()) { ImGui::SameLine(); @@ -2176,7 +2192,7 @@ void GameScreen::renderPetFrame(game::GameHandler& gameHandler) { // Raw slot value layout (WotLK 3.3.5): low 24 bits = spell/action ID, // high byte = flag (0x80=autocast on, 0x40=can-autocast, 0x0C=type). // Built-in commands: id=2 follow, id=3 stay/move, id=5 attack. - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; const float iconSz = 20.0f; const float spacing = 2.0f; ImGui::Separator(); @@ -2279,7 +2295,7 @@ void GameScreen::renderPetFrame(game::GameHandler& gameHandler) { else if (actionId == 6) tip = "Aggressive"; if (tip) ImGui::SetTooltip("%s", tip); } else if (actionId > 6) { - auto* spellAsset = core::Application::getInstance().getAssetManager(); + auto* spellAsset = services_.assetManager; ImGui::BeginTooltip(); bool richOk = spellbookScreen.renderSpellInfoTooltip(actionId, gameHandler, spellAsset); if (!richOk) { @@ -2400,7 +2416,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) { auto target = gameHandler.getTarget(); if (!target) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float frameW = 250.0f; @@ -2839,7 +2855,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) { else snprintf(castLabel, sizeof(castLabel), "Casting... (%.1fs)", castLeft); { - auto* tcastAsset = core::Application::getInstance().getAssetManager(); + auto* tcastAsset = services_.assetManager; VkDescriptorSet tIcon = (tspell != 0 && tcastAsset) ? getSpellIcon(tspell, tcastAsset) : VK_NULL_HANDLE; if (tIcon) { @@ -2936,7 +2952,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) { if (!a.isEmpty()) activeAuras++; } if (activeAuras > 0) { - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; constexpr float ICON_SIZE = 24.0f; constexpr int ICONS_PER_ROW = 8; @@ -3234,7 +3250,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) { int totActive = 0; for (const auto& a : *totAuras) if (!a.isEmpty()) totActive++; if (totActive > 0) { - auto* totAsset = core::Application::getInstance().getAssetManager(); + auto* totAsset = services_.assetManager; constexpr float TA_ICON = 16.0f; constexpr int TA_PER_ROW = 8; @@ -3350,7 +3366,7 @@ void GameScreen::renderFocusFrame(game::GameHandler& gameHandler) { auto focus = gameHandler.getFocus(); if (!focus) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; // Position: right side of screen, mirroring the target frame on the opposite side @@ -3652,7 +3668,7 @@ void GameScreen::renderFocusFrame(game::GameHandler& gameHandler) { else snprintf(castBuf, sizeof(castBuf), "Casting... (%.1fs)", rem); { - auto* fcAsset = core::Application::getInstance().getAssetManager(); + auto* fcAsset = services_.assetManager; VkDescriptorSet fcIcon = (focusCast->spellId != 0 && fcAsset) ? getSpellIcon(focusCast->spellId, fcAsset) : VK_NULL_HANDLE; if (fcIcon) { @@ -3678,7 +3694,7 @@ void GameScreen::renderFocusFrame(game::GameHandler& gameHandler) { int activeCount = 0; for (const auto& a : *focusAuras) if (!a.isEmpty()) activeCount++; if (activeCount > 0) { - auto* focusAsset = core::Application::getInstance().getAssetManager(); + auto* focusAsset = services_.assetManager; constexpr float FA_ICON = 20.0f; constexpr int FA_PER_ROW = 10; @@ -4349,7 +4365,7 @@ VkDescriptorSet GameScreen::getSpellIcon(uint32_t spellId, pipeline::AssetManage } // Upload to Vulkan via VkContext - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; auto* vkCtx = window ? window->getVkContext() : nullptr; if (!vkCtx) { spellIconCache_[spellId] = VK_NULL_HANDLE; @@ -4456,7 +4472,7 @@ void GameScreen::renderQuestObjectiveTracker(game::GameHandler& gameHandler) { const auto& questLog = gameHandler.getQuestLog(); if (questLog.empty()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; constexpr float TRACKER_W = 220.0f; @@ -4694,12 +4710,12 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) { // Reset mouseover each frame; we'll set it below when the cursor is over a nameplate gameHandler.setMouseoverGuid(0); - auto* appRenderer = core::Application::getInstance().getRenderer(); + auto* appRenderer = services_.renderer; if (!appRenderer) return; rendering::Camera* camera = appRenderer->getCamera(); if (!camera) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; if (!window) return; const float screenW = static_cast(window->getWidth()); const float screenH = static_cast(window->getHeight()); @@ -4908,7 +4924,7 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) { // Spell icon + name above the cast bar const std::string& spellName = gameHandler.getSpellName(cs->spellId); { - auto* castAm = core::Application::getInstance().getAssetManager(); + auto* castAm = services_.assetManager; VkDescriptorSet castIcon = (cs->spellId && castAm) ? getSpellIcon(cs->spellId, castAm) : VK_NULL_HANDLE; float iconSz = cbH + 8.0f; @@ -5301,7 +5317,7 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) { // ============================================================ void GameScreen::takeScreenshot(game::GameHandler& /*gameHandler*/) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (!renderer) return; // Build path: ~/.wowee/screenshots/WoWee_YYYYMMDD_HHMMSS.png @@ -5332,7 +5348,7 @@ void GameScreen::takeScreenshot(game::GameHandler& /*gameHandler*/) { sysMsg.type = game::ChatType::SYSTEM; sysMsg.language = game::ChatLanguage::UNIVERSAL; sysMsg.message = "Screenshot saved: " + path; - core::Application::getInstance().getGameHandler()->addLocalChatMessage(sysMsg); + services_.gameHandler->addLocalChatMessage(sysMsg); } } @@ -5412,7 +5428,7 @@ void GameScreen::renderUIErrors(game::GameHandler& /*gameHandler*/, float deltaT if (uiErrors_.empty()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -5551,9 +5567,9 @@ void GameScreen::renderQuestMarkers(game::GameHandler& gameHandler) { const auto& statuses = gameHandler.getNpcQuestStatuses(); if (statuses.empty()) return; - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; auto* camera = renderer ? renderer->getCamera() : nullptr; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; if (!camera || !window) return; float screenW = static_cast(window->getWidth()); @@ -5629,10 +5645,10 @@ void GameScreen::renderQuestMarkers(game::GameHandler& gameHandler) { void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) { const auto& statuses = gameHandler.getNpcQuestStatuses(); - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; auto* camera = renderer ? renderer->getCamera() : nullptr; auto* minimap = renderer ? renderer->getMinimap() : nullptr; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; if (!camera || !minimap || !window) return; float screenW = static_cast(window->getWidth()); @@ -6509,7 +6525,7 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) { } auto applyMuteState = [&]() { - auto* activeRenderer = core::Application::getInstance().getRenderer(); + auto* activeRenderer = services_.renderer; float masterScale = settingsPanel_.soundMuted_ ? 0.0f : static_cast(settingsPanel_.pendingMasterVolume) / 100.0f; audio::AudioEngine::instance().setMasterVolume(masterScale); if (!activeRenderer) return; @@ -6843,7 +6859,7 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) { // Calendar pending invites indicator (WotLK only) { - auto* expReg = core::Application::getInstance().getExpansionRegistry(); + auto* expReg = services_.expansionRegistry; bool isWotLK = expReg && expReg->getActive() && expReg->getActive()->id == "wotlk"; if (isWotLK) { uint32_t calPending = gameHandler.getCalendarPendingInvites(); @@ -7197,7 +7213,7 @@ void GameScreen::loadSettings() { else if (key == "shadow_distance") settingsPanel_.pendingShadowDistance = std::clamp(std::stof(val), 40.0f, 500.0f); else if (key == "brightness") { settingsPanel_.pendingBrightness = std::clamp(std::stoi(val), 0, 100); - if (auto* r = core::Application::getInstance().getRenderer()) + if (auto* r = services_.renderer) r->setBrightness(static_cast(settingsPanel_.pendingBrightness) / 50.0f); } else if (key == "water_refraction") settingsPanel_.pendingWaterRefraction = (std::stoi(val) != 0); @@ -7229,7 +7245,7 @@ void GameScreen::loadSettings() { else if (key == "camera_pivot_height") settingsPanel_.pendingPivotHeight = std::clamp(std::stof(val), 0.0f, 3.0f); else if (key == "fov") { settingsPanel_.pendingFov = std::clamp(std::stof(val), 45.0f, 110.0f); - if (auto* renderer = core::Application::getInstance().getRenderer()) { + if (auto* renderer = services_.renderer) { if (auto* camera = renderer->getCamera()) camera->setFov(settingsPanel_.pendingFov); } } diff --git a/src/ui/settings_panel.cpp b/src/ui/settings_panel.cpp index a7676d61..15acfc13 100644 --- a/src/ui/settings_panel.cpp +++ b/src/ui/settings_panel.cpp @@ -152,7 +152,7 @@ ImGui::EndChild(); void SettingsPanel::renderSettingsGameplayTab(InventoryScreen& inventoryScreen, std::function saveCallback) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; ImGui::Spacing(); ImGui::Text("Controls"); @@ -433,7 +433,7 @@ if (ImGui::Button("Reset to Defaults", ImVec2(-1, 0))) { } void SettingsPanel::renderSettingsAudioTab(std::function saveCallback) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; ImGui::Spacing(); ImGui::BeginChild("AudioSettings", ImVec2(0, 360), true); @@ -599,8 +599,8 @@ void SettingsPanel::renderSettingsWindow(InventoryScreen& inventoryScreen, ChatP std::function saveCallback) { if (!showSettingsWindow) return; - auto* window = core::Application::getInstance().getWindow(); - auto* renderer = core::Application::getInstance().getRenderer(); + auto* window = services_.window; + auto* renderer = services_.renderer; if (!window) return; static constexpr int kResolutions[][2] = { @@ -1045,7 +1045,7 @@ void SettingsPanel::renderSettingsWindow(InventoryScreen& inventoryScreen, ChatP } void SettingsPanel::applyGraphicsPreset(GraphicsPreset preset) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; // Define preset values based on quality level switch (preset) { diff --git a/src/ui/social_panel.cpp b/src/ui/social_panel.cpp index 6d0f0145..5a37fd8e 100644 --- a/src/ui/social_panel.cpp +++ b/src/ui/social_panel.cpp @@ -86,7 +86,7 @@ void SocialPanel::renderPartyFrames(game::GameHandler& gameHandler, SpellIconFn getSpellIcon) { if (!gameHandler.isInGroup()) return; - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; const auto& partyData = gameHandler.getPartyData(); const bool isRaid = (partyData.groupType == 1); float frameY = 120.0f; @@ -117,7 +117,7 @@ void SocialPanel::renderPartyFrames(game::GameHandler& gameHandler, float winW = activeSgs * (CELL_W + CELL_PAD) + CELL_PAD + 8.0f; float winH = MAX_PER_GROUP * (CELL_H + CELL_PAD) + CELL_PAD + 20.0f; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; float raidX = (screenW - winW) / 2.0f; @@ -757,7 +757,7 @@ void SocialPanel::renderPartyFrames(game::GameHandler& gameHandler, void SocialPanel::renderBossFrames(game::GameHandler& gameHandler, SpellbookScreen& spellbookScreen, SpellIconFn getSpellIcon) { - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; // Collect active boss unit slots struct BossSlot { uint32_t slot; uint64_t guid; }; @@ -1143,11 +1143,11 @@ void SocialPanel::renderGuildRoster(game::GameHandler& gameHandler, // Get zone manager for name lookup game::ZoneManager* zoneManager = nullptr; - if (auto* renderer = core::Application::getInstance().getRenderer()) { + if (auto* renderer = services_.renderer) { zoneManager = renderer->getZoneManager(); } - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -1683,7 +1683,7 @@ void SocialPanel::renderSocialFrame(game::GameHandler& gameHandler, for (const auto& c : contacts) if (c.isFriend() && c.isOnline()) ++onlineCount; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW - 230.0f, 240.0f), ImGuiCond_Once); @@ -1705,7 +1705,7 @@ void SocialPanel::renderSocialFrame(game::GameHandler& gameHandler, // Get zone manager for area name lookups game::ZoneManager* socialZoneMgr = nullptr; - if (auto* rend = core::Application::getInstance().getRenderer()) + if (auto* rend = services_.renderer) socialZoneMgr = rend->getZoneManager(); if (ImGui::BeginTabBar("##SocialTabs")) { @@ -2048,7 +2048,7 @@ void SocialPanel::renderDungeonFinderWindow(game::GameHandler& gameHandler, if (!showDungeonFinder_) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -2423,7 +2423,7 @@ void SocialPanel::renderInspectWindow(game::GameHandler& gameHandler, // Lazy-load SpellItemEnchantment.dbc for enchant name lookup static std::unordered_map s_enchantNames; static bool s_enchantDbLoaded = false; - auto* assetMgrEnchant = core::Application::getInstance().getAssetManager(); + auto* assetMgrEnchant = services_.assetManager; if (!s_enchantDbLoaded && assetMgrEnchant && assetMgrEnchant->isInitialized()) { s_enchantDbLoaded = true; auto dbc = assetMgrEnchant->loadDBC("SpellItemEnchantment.dbc"); diff --git a/src/ui/toast_manager.cpp b/src/ui/toast_manager.cpp index 1339b7f1..7f76c961 100644 --- a/src/ui/toast_manager.cpp +++ b/src/ui/toast_manager.cpp @@ -128,7 +128,7 @@ void ToastManager::setupCallbacks(game::GameHandler& gameHandler) { // --------------------------------------------------------------------------- void ToastManager::renderEarlyToasts(float deltaTime, game::GameHandler& gameHandler) { // Zone entry detection — fire a toast when the renderer's zone name changes - if (auto* rend = core::Application::getInstance().getRenderer()) { + if (auto* rend = services_.renderer) { const std::string& curZone = rend->getCurrentZoneName(); if (!curZone.empty() && curZone != lastKnownZone_) { if (!lastKnownZone_.empty()) { @@ -175,7 +175,7 @@ void ToastManager::renderRepToasts(float deltaTime) { if (repToasts_.empty()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -254,7 +254,7 @@ void ToastManager::renderQuestCompleteToasts(float deltaTime) { if (questCompleteToasts_.empty()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -329,7 +329,7 @@ void ToastManager::renderZoneToasts(float deltaTime) { if (zoneToasts_.empty()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImDrawList* draw = ImGui::GetForegroundDrawList(); @@ -395,7 +395,7 @@ void ToastManager::renderAreaTriggerToasts(float deltaTime, game::GameHandler& g areaTriggerToasts_.end()); if (areaTriggerToasts_.empty()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -461,7 +461,7 @@ void ToastManager::triggerDing(uint32_t newLevel, uint32_t hpDelta, uint32_t man dingStats_[3] = intel; dingStats_[4] = spi; - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { if (auto* sfx = renderer->getUiSoundManager()) { sfx->playLevelUp(); @@ -550,7 +550,7 @@ void ToastManager::triggerAchievementToast(uint32_t achievementId, std::string n achievementToastTimer_ = ACHIEVEMENT_TOAST_DURATION; // Play a UI sound if available - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { if (auto* sfx = renderer->getUiSoundManager()) { sfx->playAchievementAlert(); @@ -565,7 +565,7 @@ void ToastManager::renderAchievementToast() { achievementToastTimer_ -= dt; if (achievementToastTimer_ < 0.0f) achievementToastTimer_ = 0.0f; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -641,7 +641,7 @@ void ToastManager::renderDiscoveryToast() { alpha = 1.0f; alpha = std::clamp(alpha, 0.0f, 1.0f); - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -1183,7 +1183,7 @@ void ToastManager::renderZoneText(game::GameHandler& gameHandler) { // Also poll the renderer for zone name changes (covers map-level transitions // where worldStateZoneId may not change immediately). - auto* appRenderer = core::Application::getInstance().getRenderer(); + auto* appRenderer = services_.renderer; if (appRenderer) { const std::string& zoneName = appRenderer->getCurrentZoneName(); if (!zoneName.empty() && zoneName != lastKnownZoneName_) { @@ -1202,7 +1202,7 @@ void ToastManager::renderZoneText(game::GameHandler& gameHandler) { zoneTextTimer_ -= dt; if (zoneTextTimer_ < 0.0f) zoneTextTimer_ = 0.0f; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; diff --git a/src/ui/window_manager.cpp b/src/ui/window_manager.cpp index 2091a8d9..c87a3f64 100644 --- a/src/ui/window_manager.cpp +++ b/src/ui/window_manager.cpp @@ -83,7 +83,7 @@ void WindowManager::renderLootWindow(game::GameHandler& gameHandler, ChatPanel& chatPanel) { if (!gameHandler.isLootWindowOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 200), ImGuiCond_Appearing); @@ -273,7 +273,7 @@ void WindowManager::renderGossipWindow(game::GameHandler& gameHandler, ChatPanel& chatPanel) { if (!gameHandler.isGossipWindowOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 150), ImGuiCond_Appearing); @@ -445,7 +445,7 @@ void WindowManager::renderQuestDetailsWindow(game::GameHandler& gameHandler, InventoryScreen& inventoryScreen) { if (!gameHandler.isQuestDetailsOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -569,7 +569,7 @@ void WindowManager::renderQuestRequestItemsWindow(game::GameHandler& gameHandler InventoryScreen& inventoryScreen) { if (!gameHandler.isQuestRequestItemsOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -672,7 +672,7 @@ void WindowManager::renderQuestOfferRewardWindow(game::GameHandler& gameHandler, InventoryScreen& inventoryScreen) { if (!gameHandler.isQuestOfferRewardOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -845,7 +845,7 @@ void WindowManager::renderQuestOfferRewardWindow(game::GameHandler& gameHandler, void WindowManager::loadExtendedCostDBC() { if (extendedCostDbLoaded_) return; extendedCostDbLoaded_ = true; - auto* am = core::Application::getInstance().getAssetManager(); + auto* am = services_.assetManager; if (!am || !am->isInitialized()) return; auto dbc = am->loadDBC("ItemExtendedCost.dbc"); if (!dbc || !dbc->isLoaded()) return; @@ -898,7 +898,7 @@ void WindowManager::renderVendorWindow(game::GameHandler& gameHandler, ChatPanel& chatPanel) { if (!gameHandler.isVendorWindowOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 100), ImGuiCond_Appearing); @@ -1236,9 +1236,9 @@ void WindowManager::renderTrainerWindow(game::GameHandler& gameHandler, SpellIconFn getSpellIcon) { if (!gameHandler.isTrainerWindowOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; - auto* assetMgr = core::Application::getInstance().getAssetManager(); + auto* assetMgr = services_.assetManager; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 225, 100), ImGuiCond_Appearing); ImGui::SetNextWindowSize(ImVec2(500, 450), ImGuiCond_Appearing); @@ -1701,7 +1701,7 @@ void WindowManager::renderEscapeMenu(SettingsPanel& settingsPanel) { settingsPanel.showEscapeSettingsNotice = false; } if (ImGui::Button("Quit", ImVec2(-1, 0))) { - auto* renderer = core::Application::getInstance().getRenderer(); + auto* renderer = services_.renderer; if (renderer) { if (auto* music = renderer->getMusicManager()) { music->stopMusic(0.0f); @@ -1763,7 +1763,7 @@ void WindowManager::renderBarberShopWindow(game::GameHandler& gameHandler) { int maxHairColor = static_cast(game::getMaxHairColor(raceEnum, gender)); int maxFacialHair = static_cast(game::getMaxFacialFeature(raceEnum, gender)); - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; float winW = 300.0f; @@ -1847,7 +1847,7 @@ void WindowManager::renderBarberShopWindow(game::GameHandler& gameHandler) { void WindowManager::renderStableWindow(game::GameHandler& gameHandler) { if (!gameHandler.isStableWindowOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -1960,7 +1960,7 @@ void WindowManager::renderStableWindow(game::GameHandler& gameHandler) { void WindowManager::renderTaxiWindow(game::GameHandler& gameHandler) { if (!gameHandler.isTaxiWindowOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 150), ImGuiCond_Appearing); @@ -2058,7 +2058,7 @@ void WindowManager::renderTaxiWindow(game::GameHandler& gameHandler) { void WindowManager::renderLogoutCountdown(game::GameHandler& gameHandler) { if (!gameHandler.isLoggingOut()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -2127,7 +2127,7 @@ void WindowManager::renderDeathScreen(game::GameHandler& gameHandler) { deathElapsed_ += dt; } - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -2216,7 +2216,7 @@ void WindowManager::renderDeathScreen(game::GameHandler& gameHandler) { void WindowManager::renderReclaimCorpseButton(game::GameHandler& gameHandler) { if (!gameHandler.isPlayerGhost() || !gameHandler.canReclaimCorpse()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -2274,7 +2274,7 @@ void WindowManager::renderMailWindow(game::GameHandler& gameHandler, ChatPanel& chatPanel) { if (!gameHandler.isMailboxOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 250, 80), ImGuiCond_Appearing); @@ -2553,7 +2553,7 @@ void WindowManager::renderMailComposeWindow(game::GameHandler& gameHandler, InventoryScreen& inventoryScreen) { if (!gameHandler.isMailComposeOpen()) return; - auto* window = core::Application::getInstance().getWindow(); + auto* window = services_.window; float screenW = window ? static_cast(window->getWidth()) : 1280.0f; float screenH = window ? static_cast(window->getHeight()) : 720.0f; @@ -3769,7 +3769,7 @@ void WindowManager::renderAchievementWindow(game::GameHandler& gameHandler) { static bool s_criteriaDataLoaded = false; if (!s_criteriaDataLoaded) { s_criteriaDataLoaded = true; - auto* am = core::Application::getInstance().getAssetManager(); + auto* am = services_.assetManager; if (am && am->isInitialized()) { auto dbc = am->loadDBC("AchievementCriteria.dbc"); if (dbc && dbc->isLoaded() && dbc->getFieldCount() >= 10) {