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
This commit is contained in:
Paul 2026-04-01 20:59:17 +03:00
parent d43397163e
commit 1c0e9dd1df
23 changed files with 315 additions and 134 deletions

View file

@ -4,6 +4,7 @@
// XP bar, reputation bar, macro resolution. // XP bar, reputation bar, macro resolution.
// ============================================================ // ============================================================
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include <cstdint> #include <cstdint>
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
@ -70,7 +71,11 @@ public:
std::unordered_map<uint32_t, uint32_t> macroPrimarySpellCache_; std::unordered_map<uint32_t, uint32_t> macroPrimarySpellCache_;
size_t macroCacheSpellCount_ = 0; size_t macroCacheSpellCount_ = 0;
// Section 3.5: UIServices injection (Phase B singleton breaking)
void setServices(const UIServices& services) { services_ = services; }
private: private:
UIServices services_;
uint32_t resolveMacroPrimarySpellId(uint32_t macroId, game::GameHandler& gameHandler); uint32_t resolveMacroPrimarySpellId(uint32_t macroId, game::GameHandler& gameHandler);
}; };

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include "auth/auth_handler.hpp" #include "auth/auth_handler.hpp"
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <string> #include <string>
@ -30,6 +31,9 @@ public:
*/ */
void setOnSuccess(std::function<void()> callback) { onSuccess = callback; } void setOnSuccess(std::function<void()> callback) { onSuccess = callback; }
/// Set services (dependency injection)
void setServices(const UIServices& services) { services_ = services; }
/** /**
* Check if authentication is in progress * Check if authentication is in progress
@ -44,6 +48,8 @@ public:
const std::string& getStatusMessage() const { return statusMessage; } const std::string& getStatusMessage() const { return statusMessage; }
private: private:
UIServices services_; // Injected service references
struct ServerProfile { struct ServerProfile {
std::string hostname; std::string hostname;
int port = 3724; int port = 3724;

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include "game/game_handler.hpp" #include "game/game_handler.hpp"
#include <imgui.h> #include <imgui.h>
#include <string> #include <string>
@ -48,6 +49,9 @@ public:
void setOnBack(std::function<void()> cb) { onBack = std::move(cb); } void setOnBack(std::function<void()> cb) { onBack = std::move(cb); }
void setOnDeleteCharacter(std::function<void(uint64_t)> cb) { onDeleteCharacter = std::move(cb); } void setOnDeleteCharacter(std::function<void(uint64_t)> cb) { onDeleteCharacter = std::move(cb); }
/// Set services (dependency injection)
void setServices(const UIServices& services) { services_ = services; }
/** /**
* Reset selection state (e.g., when switching servers) * Reset selection state (e.g., when switching servers)
*/ */
@ -89,6 +93,8 @@ public:
void selectCharacterByName(const std::string& name); void selectCharacterByName(const std::string& name);
private: private:
UIServices services_; // Injected service references
// UI state // UI state
int selectedCharacterIndex = -1; int selectedCharacterIndex = -1;
bool characterSelected = false; bool characterSelected = false;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "game/game_handler.hpp" #include "game/game_handler.hpp"
#include "ui/ui_services.hpp"
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <imgui.h> #include <imgui.h>
#include <string> #include <string>
@ -109,10 +110,16 @@ public:
/** Reset all chat settings to defaults. */ /** Reset all chat settings to defaults. */
void restoreDefaults(); 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. */ /** Replace $g/$G and $n/$N gender/name placeholders in quest/chat text. */
std::string replaceGenderPlaceholders(const std::string& text, game::GameHandler& gameHandler); std::string replaceGenderPlaceholders(const std::string& text, game::GameHandler& gameHandler);
private: private:
// Section 3.5: Injected UI services (Phase B singleton breaking)
UIServices services_;
// ---- Chat input state ---- // ---- Chat input state ----
char chatInputBuffer_[512] = ""; char chatInputBuffer_[512] = "";
char whisperTargetBuffer_[256] = ""; char whisperTargetBuffer_[256] = "";

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include <imgui.h> #include <imgui.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <string> #include <string>
@ -70,6 +71,12 @@ public:
SpellbookScreen& spellbookScreen); SpellbookScreen& spellbookScreen);
void renderThreatWindow(game::GameHandler& gameHandler); void renderThreatWindow(game::GameHandler& gameHandler);
void renderBgScoreboard(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 } // namespace ui

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include <imgui.h> #include <imgui.h>
#include <string> #include <string>
#include <cstdint> #include <cstdint>
@ -34,7 +35,12 @@ public:
/// called in render() after reclaim corpse button /// called in render() after reclaim corpse button
void renderLateDialogs(game::GameHandler& gameHandler); void renderLateDialogs(game::GameHandler& gameHandler);
// Section 3.5: UIServices injection (Phase B singleton breaking)
void setServices(const UIServices& services) { services_ = services; }
private: private:
// Section 3.5: Injected UI services
UIServices services_;
// Common ImGui window flags for popup dialogs // Common ImGui window flags for popup dialogs
static constexpr ImGuiWindowFlags kDialogFlags = static constexpr ImGuiWindowFlags kDialogFlags =
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize; ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize;

View file

@ -17,6 +17,7 @@
#include "ui/social_panel.hpp" #include "ui/social_panel.hpp"
#include "ui/action_bar_panel.hpp" #include "ui/action_bar_panel.hpp"
#include "ui/window_manager.hpp" #include "ui/window_manager.hpp"
#include "ui/ui_services.hpp"
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <imgui.h> #include <imgui.h>
#include <string> #include <string>
@ -54,8 +55,13 @@ public:
// Dependency injection for extracted classes (Phase A singleton breaking) // Dependency injection for extracted classes (Phase A singleton breaking)
void setAppearanceComposer(core::AppearanceComposer* ac) { appearanceComposer_ = ac; } void setAppearanceComposer(core::AppearanceComposer* ac) { appearanceComposer_ = ac; }
// Section 3.5: UIServices injection (Phase B singleton breaking)
void setServices(const UIServices& services);
private: 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; core::AppearanceComposer* appearanceComposer_ = nullptr;
// Chat panel (extracted from GameScreen — owns all chat state and rendering) // Chat panel (extracted from GameScreen — owns all chat state and rendering)
ChatPanel chatPanel_; ChatPanel chatPanel_;

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <string> #include <string>
#include <functional> #include <functional>
@ -149,7 +150,12 @@ public:
/// Return the platform-specific settings file path /// Return the platform-specific settings file path
static std::string getSettingsPath(); static std::string getSettingsPath();
/// Set services (dependency injection)
void setServices(const UIServices& services) { services_ = services; }
private: private:
UIServices services_; // Injected service references
// Keybinding customization (private — only used in Controls tab) // Keybinding customization (private — only used in Controls tab)
int pendingRebindAction_ = -1; // -1 = not rebinding, otherwise action index int pendingRebindAction_ = -1; // -1 = not rebinding, otherwise action index
bool awaitingKeyPress_ = false; bool awaitingKeyPress_ = false;

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include <imgui.h> #include <imgui.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <string> #include <string>
@ -71,6 +72,12 @@ public:
ChatPanel& chatPanel); ChatPanel& chatPanel);
void renderInspectWindow(game::GameHandler& gameHandler, void renderInspectWindow(game::GameHandler& gameHandler,
InventoryScreen& inventoryScreen); InventoryScreen& inventoryScreen);
// Section 3.5: UIServices injection (Phase B singleton breaking)
void setServices(const UIServices& services) { services_ = services; }
private:
UIServices services_;
}; };
} // namespace ui } // namespace ui

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <imgui.h> #include <imgui.h>
#include <string> #include <string>
@ -40,11 +41,17 @@ public:
/// Fire achievement earned toast + sound /// Fire achievement earned toast + sound
void triggerAchievementToast(uint32_t achievementId, std::string name = {}); 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 --- // --- public state consumed by GameScreen for the golden burst overlay ---
float levelUpFlashAlpha = 0.0f; float levelUpFlashAlpha = 0.0f;
uint32_t levelUpDisplayLevel = 0; uint32_t levelUpDisplayLevel = 0;
private: private:
// Section 3.5: Injected UI services
UIServices services_;
// ---- Ding effect (own level-up) ---- // ---- Ding effect (own level-up) ----
static constexpr float DING_DURATION = 4.0f; static constexpr float DING_DURATION = 4.0f;
float dingTimer_ = 0.0f; float dingTimer_ = 0.0f;

View file

@ -5,6 +5,7 @@
#include "ui/character_create_screen.hpp" #include "ui/character_create_screen.hpp"
#include "ui/character_screen.hpp" #include "ui/character_screen.hpp"
#include "ui/game_screen.hpp" #include "ui/game_screen.hpp"
#include "ui/ui_services.hpp"
#include <memory> #include <memory>
// Forward declare SDL_Event // Forward declare SDL_Event
@ -74,8 +75,18 @@ public:
if (gameScreen) gameScreen->setAppearanceComposer(ac); 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: private:
core::Window* window = nullptr; core::Window* window = nullptr;
UIServices services_; // Section 3.5: Injected services
// UI Screens // UI Screens
std::unique_ptr<AuthScreen> authScreen; std::unique_ptr<AuthScreen> authScreen;

View file

@ -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

View file

@ -7,6 +7,7 @@
// equipment sets, skills. // equipment sets, skills.
// ============================================================ // ============================================================
#pragma once #pragma once
#include "ui/ui_services.hpp"
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@ -173,7 +174,11 @@ public:
std::unordered_map<uint32_t, ExtendedCostEntry> extendedCostCache_; std::unordered_map<uint32_t, ExtendedCostEntry> extendedCostCache_;
bool extendedCostDbLoaded_ = false; bool extendedCostDbLoaded_ = false;
// Section 3.5: UIServices injection (Phase B singleton breaking)
void setServices(const UIServices& services) { services_ = services; }
private: private:
UIServices services_;
void loadExtendedCostDBC(); void loadExtendedCostDBC();
std::string formatExtendedCost(uint32_t extendedCostId, game::GameHandler& gameHandler); std::string formatExtendedCost(uint32_t extendedCostId, game::GameHandler& gameHandler);
}; };

View file

@ -39,6 +39,7 @@
#include "pipeline/wdt_loader.hpp" #include "pipeline/wdt_loader.hpp"
#include "pipeline/dbc_loader.hpp" #include "pipeline/dbc_loader.hpp"
#include "ui/ui_manager.hpp" #include "ui/ui_manager.hpp"
#include "ui/ui_services.hpp"
#include "auth/auth_handler.hpp" #include "auth/auth_handler.hpp"
#include "game/game_handler.hpp" #include "game/game_handler.hpp"
#include "game/transport_manager.hpp" #include "game/transport_manager.hpp"
@ -227,6 +228,20 @@ bool Application::initialize() {
// Wire AppearanceComposer to UI components (Phase A singleton breaking) // Wire AppearanceComposer to UI components (Phase A singleton breaking)
if (uiManager) { if (uiManager) {
uiManager->setAppearanceComposer(appearanceComposer_.get()); 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. // Ensure the main in-world CharacterRenderer can load textures immediately.
@ -505,6 +520,22 @@ bool Application::initialize() {
entitySpawner_.get(), appearanceComposer_.get(), window.get(), entitySpawner_.get(), appearanceComposer_.get(), window.get(),
world.get(), addonManager_.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. // Start background preload for last-played character's world.
// Warms the file cache so terrain tile loading is faster at Enter World. // Warms the file cache so terrain tile loading is faster at Enter World.
{ {

View file

@ -172,7 +172,7 @@ void ActionBarPanel::renderActionBar(game::GameHandler& gameHandler,
ImVec2 displaySize = ImGui::GetIO().DisplaySize; ImVec2 displaySize = ImGui::GetIO().DisplaySize;
float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f;
float screenH = displaySize.y > 0.0f ? displaySize.y : 720.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 slotSize = 48.0f * settingsPanel.pendingActionBarScale;
float spacing = 4.0f; float spacing = 4.0f;
@ -1107,7 +1107,7 @@ void ActionBarPanel::renderStanceBar(game::GameHandler& gameHandler,
ImVec2 displaySize = ImGui::GetIO().DisplaySize; ImVec2 displaySize = ImGui::GetIO().DisplaySize;
float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f;
float screenH = displaySize.y > 0.0f ? displaySize.y : 720.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 // Match the action bar slot size so they align neatly
float slotSize = 38.0f; float slotSize = 38.0f;
@ -1196,7 +1196,7 @@ void ActionBarPanel::renderBagBar(game::GameHandler& gameHandler,
ImVec2 displaySize = ImGui::GetIO().DisplaySize; ImVec2 displaySize = ImGui::GetIO().DisplaySize;
float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f;
float screenH = displaySize.y > 0.0f ? displaySize.y : 720.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 slotSize = 42.0f;
float spacing = 4.0f; float spacing = 4.0f;
@ -1232,7 +1232,7 @@ void ActionBarPanel::renderBagBar(game::GameHandler& gameHandler,
if (!blpData.empty()) { if (!blpData.empty()) {
auto image = pipeline::BLPLoader::load(blpData); auto image = pipeline::BLPLoader::load(blpData);
if (image.isValid()) { if (image.isValid()) {
auto* w = core::Application::getInstance().getWindow(); auto* w = services_.window;
auto* vkCtx = w ? w->getVkContext() : nullptr; auto* vkCtx = w ? w->getVkContext() : nullptr;
if (vkCtx) if (vkCtx)
backpackIconTexture_ = vkCtx->uploadImGuiTexture(image.data.data(), image.width, image.height); 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; ImVec2 displaySize = ImGui::GetIO().DisplaySize;
float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f;
float screenH = displaySize.y > 0.0f ? displaySize.y : 720.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 (void)window; // Not used for positioning; kept for AssetManager if needed
// Position just above both action bars (bar1 at screenH-barH, bar2 above that) // Position just above both action bars (bar1 at screenH-barH, bar2 above that)

View file

@ -197,8 +197,8 @@ void ChatPanel::render(game::GameHandler& gameHandler,
InventoryScreen& inventoryScreen, InventoryScreen& inventoryScreen,
SpellbookScreen& spellbookScreen, SpellbookScreen& spellbookScreen,
QuestLogScreen& questLogScreen) { QuestLogScreen& questLogScreen) {
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
auto* assetMgr = core::Application::getInstance().getAssetManager(); auto* assetMgr = services_.assetManager;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
float chatW = std::min(500.0f, screenW * 0.4f); float chatW = std::min(500.0f, screenW * 0.4f);
@ -1109,7 +1109,7 @@ void ChatPanel::render(game::GameHandler& gameHandler,
std::string bodyLower = mMsg.message; std::string bodyLower = mMsg.message;
for (auto& c : bodyLower) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c))); for (auto& c : bodyLower) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
if (bodyLower.find(selfNameLower) != std::string::npos) { if (bodyLower.find(selfNameLower) != std::string::npos) {
if (auto* renderer = core::Application::getInstance().getRenderer()) { if (auto* renderer = services_.renderer) {
if (auto* ui = renderer->getUiSoundManager()) if (auto* ui = renderer->getUiSoundManager())
ui->playWhisperReceived(); ui->playWhisperReceived();
} }
@ -2151,7 +2151,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler,
// /run <lua code> — execute Lua script via addon system // /run <lua code> — execute Lua script via addon system
if ((cmdLower == "run" || cmdLower == "script") && spacePos != std::string::npos) { if ((cmdLower == "run" || cmdLower == "script") && spacePos != std::string::npos) {
std::string luaCode = command.substr(spacePos + 1); std::string luaCode = command.substr(spacePos + 1);
auto* am = core::Application::getInstance().getAddonManager(); auto* am = services_.addonManager;
if (am) { if (am) {
am->runScript(luaCode); am->runScript(luaCode);
} else { } else {
@ -2164,7 +2164,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler,
// /dump <expression> — evaluate Lua expression and print result // /dump <expression> — evaluate Lua expression and print result
if ((cmdLower == "dump" || cmdLower == "print") && spacePos != std::string::npos) { if ((cmdLower == "dump" || cmdLower == "print") && spacePos != std::string::npos) {
std::string expr = command.substr(spacePos + 1); std::string expr = command.substr(spacePos + 1);
auto* am = core::Application::getInstance().getAddonManager(); auto* am = services_.addonManager;
if (am && am->isInitialized()) { if (am && am->isInitialized()) {
// Wrap expression in print(tostring(...)) to display the value // Wrap expression in print(tostring(...)) to display the value
std::string wrapped = "local __v = " + expr + 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 // Check addon slash commands (SlashCmdList) before built-in commands
{ {
auto* am = core::Application::getInstance().getAddonManager(); auto* am = services_.addonManager;
if (am && am->isInitialized()) { if (am && am->isInitialized()) {
std::string slashCmd = "/" + cmdLower; std::string slashCmd = "/" + cmdLower;
std::string slashArgs; 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) // /reload or /reloadui — reload all addons (save variables, re-init Lua, re-scan .toc files)
if (cmdLower == "reload" || cmdLower == "reloadui" || cmdLower == "rl") { if (cmdLower == "reload" || cmdLower == "reloadui" || cmdLower == "rl") {
auto* am = core::Application::getInstance().getAddonManager(); auto* am = services_.addonManager;
if (am) { if (am) {
am->reload(); am->reload();
am->fireEvent("VARIABLES_LOADED"); am->fireEvent("VARIABLES_LOADED");
@ -2301,7 +2301,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler,
if (cmdLower == "loc" || cmdLower == "coords" || cmdLower == "whereami") { if (cmdLower == "loc" || cmdLower == "coords" || cmdLower == "whereami") {
const auto& pmi = gameHandler.getMovementInfo(); const auto& pmi = gameHandler.getMovementInfo();
std::string zoneName; std::string zoneName;
if (auto* rend = core::Application::getInstance().getRenderer()) if (auto* rend = services_.renderer)
zoneName = rend->getCurrentZoneName(); zoneName = rend->getCurrentZoneName();
char buf[256]; char buf[256];
snprintf(buf, sizeof(buf), "%.1f, %.1f, %.1f%s%s", 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 // /zone command — print current zone name
if (cmdLower == "zone") { if (cmdLower == "zone") {
std::string zoneName; std::string zoneName;
if (auto* rend = core::Application::getInstance().getRenderer()) if (auto* rend = services_.renderer)
zoneName = rend->getCurrentZoneName(); zoneName = rend->getCurrentZoneName();
game::MessageChatData sysMsg; game::MessageChatData sysMsg;
sysMsg.type = game::ChatType::SYSTEM; sysMsg.type = game::ChatType::SYSTEM;
@ -4323,7 +4323,7 @@ void ChatPanel::sendChatMessage(game::GameHandler& gameHandler,
std::string emoteText = rendering::Renderer::getEmoteText(cmdLower, targetNamePtr); std::string emoteText = rendering::Renderer::getEmoteText(cmdLower, targetNamePtr);
if (!emoteText.empty()) { if (!emoteText.empty()) {
// Play the emote animation // Play the emote animation
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
renderer->playEmote(cmdLower); renderer->playEmote(cmdLower);
} }
@ -4697,11 +4697,11 @@ std::string ChatPanel::replaceGenderPlaceholders(const std::string& text, game::
void ChatPanel::renderBubbles(game::GameHandler& gameHandler) { void ChatPanel::renderBubbles(game::GameHandler& gameHandler) {
if (chatBubbles_.empty()) return; if (chatBubbles_.empty()) return;
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
auto* camera = renderer ? renderer->getCamera() : nullptr; auto* camera = renderer ? renderer->getCamera() : nullptr;
if (!camera) return; if (!camera) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;

View file

@ -60,7 +60,7 @@ namespace ui {
void CombatUI::renderCastBar(game::GameHandler& gameHandler, SpellIconFn getSpellIcon) { void CombatUI::renderCastBar(game::GameHandler& gameHandler, SpellIconFn getSpellIcon) {
if (!gameHandler.isCasting()) return; if (!gameHandler.isCasting()) return;
auto* assetMgr = core::Application::getInstance().getAssetManager(); auto* assetMgr = services_.assetManager;
ImVec2 displaySize = ImGui::GetIO().DisplaySize; ImVec2 displaySize = ImGui::GetIO().DisplaySize;
float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f; 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; return a.remaining > b.remaining;
}); });
auto* assetMgr = core::Application::getInstance().getAssetManager(); auto* assetMgr = services_.assetManager;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(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) // Walk only the new messages (deque — iterate from back by skipping old ones)
size_t toScan = newCount - raidWarnChatSeenCount_; size_t toScan = newCount - raidWarnChatSeenCount_;
size_t startIdx = newCount > toScan ? newCount - toScan : 0; 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) { for (size_t i = startIdx; i < newCount; ++i) {
const auto& msg = chatHistory[i]; const auto& msg = chatHistory[i];
if (msg.type == game::ChatType::RAID_WARNING || if (msg.type == game::ChatType::RAID_WARNING ||
@ -361,13 +361,13 @@ void CombatUI::renderCombatText(game::GameHandler& gameHandler) {
const auto& entries = gameHandler.getCombatText(); const auto& entries = gameHandler.getCombatText();
if (entries.empty()) return; if (entries.empty()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
if (!window) return; if (!window) return;
const float screenW = static_cast<float>(window->getWidth()); const float screenW = static_cast<float>(window->getWidth());
const float screenH = static_cast<float>(window->getHeight()); const float screenH = static_cast<float>(window->getHeight());
// Camera for world-space projection // Camera for world-space projection
auto* appRenderer = core::Application::getInstance().getRenderer(); auto* appRenderer = services_.renderer;
rendering::Camera* camera = appRenderer ? appRenderer->getCamera() : nullptr; rendering::Camera* camera = appRenderer ? appRenderer->getCamera() : nullptr;
glm::mat4 viewProj; glm::mat4 viewProj;
if (camera) viewProj = camera->getProjectionMatrix() * camera->getViewMatrix(); if (camera) viewProj = camera->getProjectionMatrix() * camera->getViewMatrix();
@ -785,7 +785,7 @@ void CombatUI::renderDPSMeter(game::GameHandler& gameHandler,
fmtNum(hps, hpsBuf, sizeof(hpsBuf)); fmtNum(hps, hpsBuf, sizeof(hpsBuf));
// Position: small floating label just above the action bar, right of center // 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<float>(appWin->getWidth()) : 1280.0f; float screenW = appWin ? static_cast<float>(appWin->getWidth()) : 1280.0f;
float screenH = appWin ? static_cast<float>(appWin->getHeight()) : 720.0f; float screenH = appWin ? static_cast<float>(appWin->getHeight()) : 720.0f;
@ -866,7 +866,7 @@ void CombatUI::renderBuffBar(game::GameHandler& gameHandler,
} }
if (activeCount == 0 && !gameHandler.hasPet()) return; 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) // 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 // 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; if (auto mv = gameHandler.getWorldState(def->maxKey)) maxScore = *mv;
} }
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
// Width scales with screen but stays reasonable // Width scales with screen but stays reasonable
@ -1598,7 +1598,7 @@ void CombatUI::renderCombatLog(game::GameHandler& gameHandler,
ImGui::TextColored(color, "%s", desc); ImGui::TextColored(color, "%s", desc);
// Hover tooltip: show rich spell info for entries with a known spell // Hover tooltip: show rich spell info for entries with a known spell
if (e.spellId != 0 && ImGui::IsItemHovered()) { if (e.spellId != 0 && ImGui::IsItemHovered()) {
auto* assetMgrLog = core::Application::getInstance().getAssetManager(); auto* assetMgrLog = services_.assetManager;
ImGui::BeginTooltip(); ImGui::BeginTooltip();
bool richOk = spellbookScreen.renderSpellInfoTooltip(e.spellId, gameHandler, assetMgrLog); bool richOk = spellbookScreen.renderSpellInfoTooltip(e.spellId, gameHandler, assetMgrLog);
if (!richOk) { if (!richOk) {

View file

@ -69,7 +69,7 @@ void DialogManager::renderLateDialogs(game::GameHandler& gameHandler) {
void DialogManager::renderGroupInvitePopup(game::GameHandler& gameHandler) { void DialogManager::renderGroupInvitePopup(game::GameHandler& gameHandler) {
if (!gameHandler.hasPendingGroupInvite()) return; if (!gameHandler.hasPendingGroupInvite()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 200), ImGuiCond_Always); 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) { void DialogManager::renderDuelRequestPopup(game::GameHandler& gameHandler) {
if (!gameHandler.hasPendingDuelRequest()) return; if (!gameHandler.hasPendingDuelRequest()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 250), ImGuiCond_Always); 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) { void DialogManager::renderItemTextWindow(game::GameHandler& gameHandler) {
if (!gameHandler.isItemTextOpen()) return; if (!gameHandler.isItemTextOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -194,7 +194,7 @@ void DialogManager::renderItemTextWindow(game::GameHandler& gameHandler) {
void DialogManager::renderSharedQuestPopup(game::GameHandler& gameHandler) { void DialogManager::renderSharedQuestPopup(game::GameHandler& gameHandler) {
if (!gameHandler.hasPendingSharedQuest()) return; if (!gameHandler.hasPendingSharedQuest()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 490), ImGuiCond_Always); ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 490), ImGuiCond_Always);
@ -224,7 +224,7 @@ void DialogManager::renderSummonRequestPopup(game::GameHandler& gameHandler) {
gameHandler.tickSummonTimeout(dt); gameHandler.tickSummonTimeout(dt);
if (!gameHandler.hasPendingSummonRequest()) return; // expired if (!gameHandler.hasPendingSummonRequest()) return; // expired
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 430), ImGuiCond_Always); 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) { void DialogManager::renderTradeRequestPopup(game::GameHandler& gameHandler) {
if (!gameHandler.hasPendingTradeRequest()) return; if (!gameHandler.hasPendingTradeRequest()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 370), ImGuiCond_Always); 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 uint64_t peerGold = gameHandler.getPeerTradeGold();
const auto& peerName = gameHandler.getTradePeerName(); const auto& peerName = gameHandler.getTradePeerName();
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -443,7 +443,7 @@ void DialogManager::renderLootRollPopup(game::GameHandler& gameHandler,
const auto& roll = gameHandler.getPendingLootRoll(); const auto& roll = gameHandler.getPendingLootRoll();
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 310), ImGuiCond_Always); 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) { void DialogManager::renderGuildInvitePopup(game::GameHandler& gameHandler) {
if (!gameHandler.hasPendingGuildInvite()) return; if (!gameHandler.hasPendingGuildInvite()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 175, 250), ImGuiCond_Always); 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) { void DialogManager::renderReadyCheckPopup(game::GameHandler& gameHandler) {
if (!gameHandler.hasPendingReadyCheck()) return; if (!gameHandler.hasPendingReadyCheck()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -684,7 +684,7 @@ void DialogManager::renderBgInvitePopup(game::GameHandler& gameHandler) {
return; return;
} }
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(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) // Only shown on WotLK servers (outdoor battlefields like Wintergrasp use the BF Manager)
if (!gameHandler.hasBfMgrInvite()) return; if (!gameHandler.hasBfMgrInvite()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -802,7 +802,7 @@ void DialogManager::renderLfgProposalPopup(game::GameHandler& gameHandler) {
using LfgState = game::GameHandler::LfgState; using LfgState = game::GameHandler::LfgState;
if (gameHandler.getLfgState() != LfgState::Proposal) return; if (gameHandler.getLfgState() != LfgState::Proposal) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -851,7 +851,7 @@ void DialogManager::renderLfgRoleCheckPopup(game::GameHandler& gameHandler) {
using LfgState = game::GameHandler::LfgState; using LfgState = game::GameHandler::LfgState;
if (gameHandler.getLfgState() != LfgState::RoleCheck) return; if (gameHandler.getLfgState() != LfgState::RoleCheck) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -915,7 +915,7 @@ void DialogManager::renderLfgRoleCheckPopup(game::GameHandler& gameHandler) {
void DialogManager::renderResurrectDialog(game::GameHandler& gameHandler) { void DialogManager::renderResurrectDialog(game::GameHandler& gameHandler) {
if (!gameHandler.showResurrectDialog()) return; if (!gameHandler.showResurrectDialog()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -976,7 +976,7 @@ void DialogManager::renderResurrectDialog(game::GameHandler& gameHandler) {
void DialogManager::renderTalentWipeConfirmDialog(game::GameHandler& gameHandler) { void DialogManager::renderTalentWipeConfirmDialog(game::GameHandler& gameHandler) {
if (!gameHandler.showTalentWipeConfirmDialog()) return; if (!gameHandler.showTalentWipeConfirmDialog()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -1046,7 +1046,7 @@ void DialogManager::renderTalentWipeConfirmDialog(game::GameHandler& gameHandler
void DialogManager::renderPetUnlearnConfirmDialog(game::GameHandler& gameHandler) { void DialogManager::renderPetUnlearnConfirmDialog(game::GameHandler& gameHandler) {
if (!gameHandler.showPetUnlearnDialog()) return; if (!gameHandler.showPetUnlearnDialog()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;

View file

@ -250,6 +250,22 @@ GameScreen::GameScreen() {
loadSettings(); 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) { void GameScreen::render(game::GameHandler& gameHandler) {
// Set up chat bubble callback (once) and cache game handler in ChatPanel // Set up chat bubble callback (once) and cache game handler in ChatPanel
chatPanel_.setupCallbacks(gameHandler); chatPanel_.setupCallbacks(gameHandler);
@ -269,7 +285,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
uiErrors_.push_back({msg, 0.0f}); uiErrors_.push_back({msg, 0.0f});
if (uiErrors_.size() > 5) uiErrors_.erase(uiErrors_.begin()); if (uiErrors_.size() > 5) uiErrors_.erase(uiErrors_.begin());
// Play error sound for each new error (rate-limited by deque cap of 5) // 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(); if (auto* sfx = r->getUiSoundManager()) sfx->playError();
} }
}); });
@ -292,7 +308,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
// Sync minimap opacity with UI opacity // Sync minimap opacity with UI opacity
{ {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
if (auto* minimap = renderer->getMinimap()) { if (auto* minimap = renderer->getMinimap()) {
minimap->setOpacity(settingsPanel_.uiOpacity_); minimap->setOpacity(settingsPanel_.uiOpacity_);
@ -302,7 +318,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
// Apply initial settings when renderer becomes available // Apply initial settings when renderer becomes available
if (!settingsPanel_.minimapSettingsApplied_) { if (!settingsPanel_.minimapSettingsApplied_) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
if (auto* minimap = renderer->getMinimap()) { if (auto* minimap = renderer->getMinimap()) {
settingsPanel_.minimapRotate_ = false; settingsPanel_.minimapRotate_ = false;
@ -329,7 +345,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
// Apply saved volume settings once when audio managers first become available // Apply saved volume settings once when audio managers first become available
if (!settingsPanel_.volumeSettingsApplied_) { if (!settingsPanel_.volumeSettingsApplied_) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer && renderer->getUiSoundManager()) { if (renderer && renderer->getUiSoundManager()) {
settingsPanel_.applyAudioVolumes(renderer); settingsPanel_.applyAudioVolumes(renderer);
settingsPanel_.volumeSettingsApplied_ = true; settingsPanel_.volumeSettingsApplied_ = true;
@ -338,7 +354,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
// Apply saved MSAA setting once when renderer is available // Apply saved MSAA setting once when renderer is available
if (!settingsPanel_.msaaSettingsApplied_ && settingsPanel_.pendingAntiAliasing > 0) { if (!settingsPanel_.msaaSettingsApplied_ && settingsPanel_.pendingAntiAliasing > 0) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
static const VkSampleCountFlagBits aaSamples[] = { static const VkSampleCountFlagBits aaSamples[] = {
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT, 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 // Apply saved FXAA setting once when renderer is available
if (!settingsPanel_.fxaaSettingsApplied_) { if (!settingsPanel_.fxaaSettingsApplied_) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
renderer->setFXAAEnabled(settingsPanel_.pendingFXAA); renderer->setFXAAEnabled(settingsPanel_.pendingFXAA);
settingsPanel_.fxaaSettingsApplied_ = true; settingsPanel_.fxaaSettingsApplied_ = true;
@ -362,7 +378,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
// Apply saved water refraction setting once when renderer is available // Apply saved water refraction setting once when renderer is available
if (!settingsPanel_.waterRefractionApplied_) { if (!settingsPanel_.waterRefractionApplied_) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
renderer->setWaterRefractionEnabled(settingsPanel_.pendingWaterRefraction); renderer->setWaterRefractionEnabled(settingsPanel_.pendingWaterRefraction);
settingsPanel_.waterRefractionApplied_ = true; 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 // Apply saved normal mapping / POM settings once when WMO renderer is available
if (!settingsPanel_.normalMapSettingsApplied_) { if (!settingsPanel_.normalMapSettingsApplied_) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
if (auto* wr = renderer->getWMORenderer()) { if (auto* wr = renderer->getWMORenderer()) {
wr->setNormalMappingEnabled(settingsPanel_.pendingNormalMapping); wr->setNormalMappingEnabled(settingsPanel_.pendingNormalMapping);
@ -391,7 +407,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
// Apply saved upscaling setting once when renderer is available // Apply saved upscaling setting once when renderer is available
if (!settingsPanel_.fsrSettingsApplied_) { if (!settingsPanel_.fsrSettingsApplied_) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
static constexpr float fsrScales[] = { 0.77f, 0.67f, 0.59f, 1.00f }; static constexpr float fsrScales[] = { 0.77f, 0.67f, 0.59f, 1.00f };
settingsPanel_.pendingFSRQuality = std::clamp(settingsPanel_.pendingFSRQuality, 0, 3); settingsPanel_.pendingFSRQuality = std::clamp(settingsPanel_.pendingFSRQuality, 0, 3);
@ -562,7 +578,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
questLogScreen.render(gameHandler, inventoryScreen); questLogScreen.render(gameHandler, inventoryScreen);
// Spellbook (P key toggle handled inside) // 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 // 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(); uint64_t activeGuid = gameHandler.getActiveCharacterGuid();
if (activeGuid != 0 && activeGuid != inventoryScreenCharGuid_) { if (activeGuid != 0 && activeGuid != inventoryScreenCharGuid_) {
auto* am = core::Application::getInstance().getAssetManager(); auto* am = services_.assetManager;
if (am) { if (am) {
inventoryScreen.setAssetManager(am); inventoryScreen.setAssetManager(am);
const auto* ch = gameHandler.getActiveCharacter(); const auto* ch = gameHandler.getActiveCharacter();
@ -635,7 +651,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
if (appearanceComposer_) appearanceComposer_->loadEquippedWeapons(); if (appearanceComposer_) appearanceComposer_->loadEquippedWeapons();
inventoryScreen.markPreviewDirty(); inventoryScreen.markPreviewDirty();
// Update renderer weapon type for animation selection // Update renderer weapon type for animation selection
auto* r = core::Application::getInstance().getRenderer(); auto* r = services_.renderer;
if (r) { if (r) {
const auto& mh = gameHandler.getInventory().getEquipSlot(game::EquipSlot::MAIN_HAND); const auto& mh = gameHandler.getInventory().getEquipSlot(game::EquipSlot::MAIN_HAND);
r->setEquippedWeaponType(mh.empty() ? 0 : mh.item.inventoryType); 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 // Update renderer face-target position and selection circle
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
renderer->setInCombat(gameHandler.isInCombat() && renderer->setInCombat(gameHandler.isInCombat() &&
!gameHandler.isPlayerDead() && !gameHandler.isPlayerDead() &&
@ -1202,9 +1218,9 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) {
// Cursor affordance: show hand cursor over interactable entities. // Cursor affordance: show hand cursor over interactable entities.
if (!io.WantCaptureMouse) { if (!io.WantCaptureMouse) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
auto* camera = renderer ? renderer->getCamera() : nullptr; auto* camera = renderer ? renderer->getCamera() : nullptr;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
if (camera && window) { if (camera && window) {
glm::vec2 mousePos = input.getMousePosition(); glm::vec2 mousePos = input.getMousePosition();
float screenW = static_cast<float>(window->getWidth()); float screenW = static_cast<float>(window->getWidth());
@ -1258,9 +1274,9 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) {
constexpr float CLICK_THRESHOLD = 5.0f; // pixels constexpr float CLICK_THRESHOLD = 5.0f; // pixels
if (dragDistSq < CLICK_THRESHOLD * CLICK_THRESHOLD) { if (dragDistSq < CLICK_THRESHOLD * CLICK_THRESHOLD) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
auto* camera = renderer ? renderer->getCamera() : nullptr; auto* camera = renderer ? renderer->getCamera() : nullptr;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
if (camera && window) { if (camera && window) {
float screenW = static_cast<float>(window->getWidth()); float screenW = static_cast<float>(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 // 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* camera = renderer ? renderer->getCamera() : nullptr;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
if (camera && window) { if (camera && window) {
// If a quest objective gameobject is under the cursor, prefer it over // If a quest objective gameobject is under the cursor, prefer it over
// hostile units so quest pickups (e.g. "Bundle of Wood") are reliable. // 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), "<DND>"); ImGui::TextColored(ImVec4(0.9f, 0.5f, 0.2f, 1.0f), "<DND>");
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Do not disturb — /dnd to cancel"); 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 (auto* cam = ren->getCameraController()) {
if (cam->isAutoRunning()) { if (cam->isAutoRunning()) {
ImGui::SameLine(); 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, // 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). // high byte = flag (0x80=autocast on, 0x40=can-autocast, 0x0C=type).
// Built-in commands: id=2 follow, id=3 stay/move, id=5 attack. // 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 iconSz = 20.0f;
const float spacing = 2.0f; const float spacing = 2.0f;
ImGui::Separator(); ImGui::Separator();
@ -2279,7 +2295,7 @@ void GameScreen::renderPetFrame(game::GameHandler& gameHandler) {
else if (actionId == 6) tip = "Aggressive"; else if (actionId == 6) tip = "Aggressive";
if (tip) ImGui::SetTooltip("%s", tip); if (tip) ImGui::SetTooltip("%s", tip);
} else if (actionId > 6) { } else if (actionId > 6) {
auto* spellAsset = core::Application::getInstance().getAssetManager(); auto* spellAsset = services_.assetManager;
ImGui::BeginTooltip(); ImGui::BeginTooltip();
bool richOk = spellbookScreen.renderSpellInfoTooltip(actionId, gameHandler, spellAsset); bool richOk = spellbookScreen.renderSpellInfoTooltip(actionId, gameHandler, spellAsset);
if (!richOk) { if (!richOk) {
@ -2400,7 +2416,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) {
auto target = gameHandler.getTarget(); auto target = gameHandler.getTarget();
if (!target) return; if (!target) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float frameW = 250.0f; float frameW = 250.0f;
@ -2839,7 +2855,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) {
else else
snprintf(castLabel, sizeof(castLabel), "Casting... (%.1fs)", castLeft); snprintf(castLabel, sizeof(castLabel), "Casting... (%.1fs)", castLeft);
{ {
auto* tcastAsset = core::Application::getInstance().getAssetManager(); auto* tcastAsset = services_.assetManager;
VkDescriptorSet tIcon = (tspell != 0 && tcastAsset) VkDescriptorSet tIcon = (tspell != 0 && tcastAsset)
? getSpellIcon(tspell, tcastAsset) : VK_NULL_HANDLE; ? getSpellIcon(tspell, tcastAsset) : VK_NULL_HANDLE;
if (tIcon) { if (tIcon) {
@ -2936,7 +2952,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) {
if (!a.isEmpty()) activeAuras++; if (!a.isEmpty()) activeAuras++;
} }
if (activeAuras > 0) { if (activeAuras > 0) {
auto* assetMgr = core::Application::getInstance().getAssetManager(); auto* assetMgr = services_.assetManager;
constexpr float ICON_SIZE = 24.0f; constexpr float ICON_SIZE = 24.0f;
constexpr int ICONS_PER_ROW = 8; constexpr int ICONS_PER_ROW = 8;
@ -3234,7 +3250,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) {
int totActive = 0; int totActive = 0;
for (const auto& a : *totAuras) if (!a.isEmpty()) totActive++; for (const auto& a : *totAuras) if (!a.isEmpty()) totActive++;
if (totActive > 0) { if (totActive > 0) {
auto* totAsset = core::Application::getInstance().getAssetManager(); auto* totAsset = services_.assetManager;
constexpr float TA_ICON = 16.0f; constexpr float TA_ICON = 16.0f;
constexpr int TA_PER_ROW = 8; constexpr int TA_PER_ROW = 8;
@ -3350,7 +3366,7 @@ void GameScreen::renderFocusFrame(game::GameHandler& gameHandler) {
auto focus = gameHandler.getFocus(); auto focus = gameHandler.getFocus();
if (!focus) return; if (!focus) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
// Position: right side of screen, mirroring the target frame on the opposite side // Position: right side of screen, mirroring the target frame on the opposite side
@ -3652,7 +3668,7 @@ void GameScreen::renderFocusFrame(game::GameHandler& gameHandler) {
else else
snprintf(castBuf, sizeof(castBuf), "Casting... (%.1fs)", rem); snprintf(castBuf, sizeof(castBuf), "Casting... (%.1fs)", rem);
{ {
auto* fcAsset = core::Application::getInstance().getAssetManager(); auto* fcAsset = services_.assetManager;
VkDescriptorSet fcIcon = (focusCast->spellId != 0 && fcAsset) VkDescriptorSet fcIcon = (focusCast->spellId != 0 && fcAsset)
? getSpellIcon(focusCast->spellId, fcAsset) : VK_NULL_HANDLE; ? getSpellIcon(focusCast->spellId, fcAsset) : VK_NULL_HANDLE;
if (fcIcon) { if (fcIcon) {
@ -3678,7 +3694,7 @@ void GameScreen::renderFocusFrame(game::GameHandler& gameHandler) {
int activeCount = 0; int activeCount = 0;
for (const auto& a : *focusAuras) if (!a.isEmpty()) activeCount++; for (const auto& a : *focusAuras) if (!a.isEmpty()) activeCount++;
if (activeCount > 0) { if (activeCount > 0) {
auto* focusAsset = core::Application::getInstance().getAssetManager(); auto* focusAsset = services_.assetManager;
constexpr float FA_ICON = 20.0f; constexpr float FA_ICON = 20.0f;
constexpr int FA_PER_ROW = 10; constexpr int FA_PER_ROW = 10;
@ -4349,7 +4365,7 @@ VkDescriptorSet GameScreen::getSpellIcon(uint32_t spellId, pipeline::AssetManage
} }
// Upload to Vulkan via VkContext // Upload to Vulkan via VkContext
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
auto* vkCtx = window ? window->getVkContext() : nullptr; auto* vkCtx = window ? window->getVkContext() : nullptr;
if (!vkCtx) { if (!vkCtx) {
spellIconCache_[spellId] = VK_NULL_HANDLE; spellIconCache_[spellId] = VK_NULL_HANDLE;
@ -4456,7 +4472,7 @@ void GameScreen::renderQuestObjectiveTracker(game::GameHandler& gameHandler) {
const auto& questLog = gameHandler.getQuestLog(); const auto& questLog = gameHandler.getQuestLog();
if (questLog.empty()) return; if (questLog.empty()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
constexpr float TRACKER_W = 220.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 // Reset mouseover each frame; we'll set it below when the cursor is over a nameplate
gameHandler.setMouseoverGuid(0); gameHandler.setMouseoverGuid(0);
auto* appRenderer = core::Application::getInstance().getRenderer(); auto* appRenderer = services_.renderer;
if (!appRenderer) return; if (!appRenderer) return;
rendering::Camera* camera = appRenderer->getCamera(); rendering::Camera* camera = appRenderer->getCamera();
if (!camera) return; if (!camera) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
if (!window) return; if (!window) return;
const float screenW = static_cast<float>(window->getWidth()); const float screenW = static_cast<float>(window->getWidth());
const float screenH = static_cast<float>(window->getHeight()); const float screenH = static_cast<float>(window->getHeight());
@ -4908,7 +4924,7 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) {
// Spell icon + name above the cast bar // Spell icon + name above the cast bar
const std::string& spellName = gameHandler.getSpellName(cs->spellId); const std::string& spellName = gameHandler.getSpellName(cs->spellId);
{ {
auto* castAm = core::Application::getInstance().getAssetManager(); auto* castAm = services_.assetManager;
VkDescriptorSet castIcon = (cs->spellId && castAm) VkDescriptorSet castIcon = (cs->spellId && castAm)
? getSpellIcon(cs->spellId, castAm) : VK_NULL_HANDLE; ? getSpellIcon(cs->spellId, castAm) : VK_NULL_HANDLE;
float iconSz = cbH + 8.0f; float iconSz = cbH + 8.0f;
@ -5301,7 +5317,7 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) {
// ============================================================ // ============================================================
void GameScreen::takeScreenshot(game::GameHandler& /*gameHandler*/) { void GameScreen::takeScreenshot(game::GameHandler& /*gameHandler*/) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (!renderer) return; if (!renderer) return;
// Build path: ~/.wowee/screenshots/WoWee_YYYYMMDD_HHMMSS.png // Build path: ~/.wowee/screenshots/WoWee_YYYYMMDD_HHMMSS.png
@ -5332,7 +5348,7 @@ void GameScreen::takeScreenshot(game::GameHandler& /*gameHandler*/) {
sysMsg.type = game::ChatType::SYSTEM; sysMsg.type = game::ChatType::SYSTEM;
sysMsg.language = game::ChatLanguage::UNIVERSAL; sysMsg.language = game::ChatLanguage::UNIVERSAL;
sysMsg.message = "Screenshot saved: " + path; 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; if (uiErrors_.empty()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -5551,9 +5567,9 @@ void GameScreen::renderQuestMarkers(game::GameHandler& gameHandler) {
const auto& statuses = gameHandler.getNpcQuestStatuses(); const auto& statuses = gameHandler.getNpcQuestStatuses();
if (statuses.empty()) return; if (statuses.empty()) return;
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
auto* camera = renderer ? renderer->getCamera() : nullptr; auto* camera = renderer ? renderer->getCamera() : nullptr;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
if (!camera || !window) return; if (!camera || !window) return;
float screenW = static_cast<float>(window->getWidth()); float screenW = static_cast<float>(window->getWidth());
@ -5629,10 +5645,10 @@ void GameScreen::renderQuestMarkers(game::GameHandler& gameHandler) {
void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) { void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) {
const auto& statuses = gameHandler.getNpcQuestStatuses(); const auto& statuses = gameHandler.getNpcQuestStatuses();
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
auto* camera = renderer ? renderer->getCamera() : nullptr; auto* camera = renderer ? renderer->getCamera() : nullptr;
auto* minimap = renderer ? renderer->getMinimap() : nullptr; auto* minimap = renderer ? renderer->getMinimap() : nullptr;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
if (!camera || !minimap || !window) return; if (!camera || !minimap || !window) return;
float screenW = static_cast<float>(window->getWidth()); float screenW = static_cast<float>(window->getWidth());
@ -6509,7 +6525,7 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) {
} }
auto applyMuteState = [&]() { auto applyMuteState = [&]() {
auto* activeRenderer = core::Application::getInstance().getRenderer(); auto* activeRenderer = services_.renderer;
float masterScale = settingsPanel_.soundMuted_ ? 0.0f : static_cast<float>(settingsPanel_.pendingMasterVolume) / 100.0f; float masterScale = settingsPanel_.soundMuted_ ? 0.0f : static_cast<float>(settingsPanel_.pendingMasterVolume) / 100.0f;
audio::AudioEngine::instance().setMasterVolume(masterScale); audio::AudioEngine::instance().setMasterVolume(masterScale);
if (!activeRenderer) return; if (!activeRenderer) return;
@ -6843,7 +6859,7 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) {
// Calendar pending invites indicator (WotLK only) // 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"; bool isWotLK = expReg && expReg->getActive() && expReg->getActive()->id == "wotlk";
if (isWotLK) { if (isWotLK) {
uint32_t calPending = gameHandler.getCalendarPendingInvites(); 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 == "shadow_distance") settingsPanel_.pendingShadowDistance = std::clamp(std::stof(val), 40.0f, 500.0f);
else if (key == "brightness") { else if (key == "brightness") {
settingsPanel_.pendingBrightness = std::clamp(std::stoi(val), 0, 100); 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<float>(settingsPanel_.pendingBrightness) / 50.0f); r->setBrightness(static_cast<float>(settingsPanel_.pendingBrightness) / 50.0f);
} }
else if (key == "water_refraction") settingsPanel_.pendingWaterRefraction = (std::stoi(val) != 0); 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 == "camera_pivot_height") settingsPanel_.pendingPivotHeight = std::clamp(std::stof(val), 0.0f, 3.0f);
else if (key == "fov") { else if (key == "fov") {
settingsPanel_.pendingFov = std::clamp(std::stof(val), 45.0f, 110.0f); 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); if (auto* camera = renderer->getCamera()) camera->setFov(settingsPanel_.pendingFov);
} }
} }

View file

@ -152,7 +152,7 @@ ImGui::EndChild();
void SettingsPanel::renderSettingsGameplayTab(InventoryScreen& inventoryScreen, void SettingsPanel::renderSettingsGameplayTab(InventoryScreen& inventoryScreen,
std::function<void()> saveCallback) { std::function<void()> saveCallback) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
ImGui::Spacing(); ImGui::Spacing();
ImGui::Text("Controls"); ImGui::Text("Controls");
@ -433,7 +433,7 @@ if (ImGui::Button("Reset to Defaults", ImVec2(-1, 0))) {
} }
void SettingsPanel::renderSettingsAudioTab(std::function<void()> saveCallback) { void SettingsPanel::renderSettingsAudioTab(std::function<void()> saveCallback) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
ImGui::Spacing(); ImGui::Spacing();
ImGui::BeginChild("AudioSettings", ImVec2(0, 360), true); ImGui::BeginChild("AudioSettings", ImVec2(0, 360), true);
@ -599,8 +599,8 @@ void SettingsPanel::renderSettingsWindow(InventoryScreen& inventoryScreen, ChatP
std::function<void()> saveCallback) { std::function<void()> saveCallback) {
if (!showSettingsWindow) return; if (!showSettingsWindow) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (!window) return; if (!window) return;
static constexpr int kResolutions[][2] = { static constexpr int kResolutions[][2] = {
@ -1045,7 +1045,7 @@ void SettingsPanel::renderSettingsWindow(InventoryScreen& inventoryScreen, ChatP
} }
void SettingsPanel::applyGraphicsPreset(GraphicsPreset preset) { void SettingsPanel::applyGraphicsPreset(GraphicsPreset preset) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
// Define preset values based on quality level // Define preset values based on quality level
switch (preset) { switch (preset) {

View file

@ -86,7 +86,7 @@ void SocialPanel::renderPartyFrames(game::GameHandler& gameHandler,
SpellIconFn getSpellIcon) { SpellIconFn getSpellIcon) {
if (!gameHandler.isInGroup()) return; if (!gameHandler.isInGroup()) return;
auto* assetMgr = core::Application::getInstance().getAssetManager(); auto* assetMgr = services_.assetManager;
const auto& partyData = gameHandler.getPartyData(); const auto& partyData = gameHandler.getPartyData();
const bool isRaid = (partyData.groupType == 1); const bool isRaid = (partyData.groupType == 1);
float frameY = 120.0f; 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 winW = activeSgs * (CELL_W + CELL_PAD) + CELL_PAD + 8.0f;
float winH = MAX_PER_GROUP * (CELL_H + CELL_PAD) + CELL_PAD + 20.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<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
float raidX = (screenW - winW) / 2.0f; float raidX = (screenW - winW) / 2.0f;
@ -757,7 +757,7 @@ void SocialPanel::renderPartyFrames(game::GameHandler& gameHandler,
void SocialPanel::renderBossFrames(game::GameHandler& gameHandler, void SocialPanel::renderBossFrames(game::GameHandler& gameHandler,
SpellbookScreen& spellbookScreen, SpellbookScreen& spellbookScreen,
SpellIconFn getSpellIcon) { SpellIconFn getSpellIcon) {
auto* assetMgr = core::Application::getInstance().getAssetManager(); auto* assetMgr = services_.assetManager;
// Collect active boss unit slots // Collect active boss unit slots
struct BossSlot { uint32_t slot; uint64_t guid; }; struct BossSlot { uint32_t slot; uint64_t guid; };
@ -1143,11 +1143,11 @@ void SocialPanel::renderGuildRoster(game::GameHandler& gameHandler,
// Get zone manager for name lookup // Get zone manager for name lookup
game::ZoneManager* zoneManager = nullptr; game::ZoneManager* zoneManager = nullptr;
if (auto* renderer = core::Application::getInstance().getRenderer()) { if (auto* renderer = services_.renderer) {
zoneManager = renderer->getZoneManager(); zoneManager = renderer->getZoneManager();
} }
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -1683,7 +1683,7 @@ void SocialPanel::renderSocialFrame(game::GameHandler& gameHandler,
for (const auto& c : contacts) for (const auto& c : contacts)
if (c.isFriend() && c.isOnline()) ++onlineCount; if (c.isFriend() && c.isOnline()) ++onlineCount;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW - 230.0f, 240.0f), ImGuiCond_Once); 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 // Get zone manager for area name lookups
game::ZoneManager* socialZoneMgr = nullptr; game::ZoneManager* socialZoneMgr = nullptr;
if (auto* rend = core::Application::getInstance().getRenderer()) if (auto* rend = services_.renderer)
socialZoneMgr = rend->getZoneManager(); socialZoneMgr = rend->getZoneManager();
if (ImGui::BeginTabBar("##SocialTabs")) { if (ImGui::BeginTabBar("##SocialTabs")) {
@ -2048,7 +2048,7 @@ void SocialPanel::renderDungeonFinderWindow(game::GameHandler& gameHandler,
if (!showDungeonFinder_) return; if (!showDungeonFinder_) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -2423,7 +2423,7 @@ void SocialPanel::renderInspectWindow(game::GameHandler& gameHandler,
// Lazy-load SpellItemEnchantment.dbc for enchant name lookup // Lazy-load SpellItemEnchantment.dbc for enchant name lookup
static std::unordered_map<uint32_t, std::string> s_enchantNames; static std::unordered_map<uint32_t, std::string> s_enchantNames;
static bool s_enchantDbLoaded = false; static bool s_enchantDbLoaded = false;
auto* assetMgrEnchant = core::Application::getInstance().getAssetManager(); auto* assetMgrEnchant = services_.assetManager;
if (!s_enchantDbLoaded && assetMgrEnchant && assetMgrEnchant->isInitialized()) { if (!s_enchantDbLoaded && assetMgrEnchant && assetMgrEnchant->isInitialized()) {
s_enchantDbLoaded = true; s_enchantDbLoaded = true;
auto dbc = assetMgrEnchant->loadDBC("SpellItemEnchantment.dbc"); auto dbc = assetMgrEnchant->loadDBC("SpellItemEnchantment.dbc");

View file

@ -128,7 +128,7 @@ void ToastManager::setupCallbacks(game::GameHandler& gameHandler) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
void ToastManager::renderEarlyToasts(float deltaTime, game::GameHandler& gameHandler) { void ToastManager::renderEarlyToasts(float deltaTime, game::GameHandler& gameHandler) {
// Zone entry detection — fire a toast when the renderer's zone name changes // 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(); const std::string& curZone = rend->getCurrentZoneName();
if (!curZone.empty() && curZone != lastKnownZone_) { if (!curZone.empty() && curZone != lastKnownZone_) {
if (!lastKnownZone_.empty()) { if (!lastKnownZone_.empty()) {
@ -175,7 +175,7 @@ void ToastManager::renderRepToasts(float deltaTime) {
if (repToasts_.empty()) return; if (repToasts_.empty()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -254,7 +254,7 @@ void ToastManager::renderQuestCompleteToasts(float deltaTime) {
if (questCompleteToasts_.empty()) return; if (questCompleteToasts_.empty()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -329,7 +329,7 @@ void ToastManager::renderZoneToasts(float deltaTime) {
if (zoneToasts_.empty()) return; if (zoneToasts_.empty()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImDrawList* draw = ImGui::GetForegroundDrawList(); ImDrawList* draw = ImGui::GetForegroundDrawList();
@ -395,7 +395,7 @@ void ToastManager::renderAreaTriggerToasts(float deltaTime, game::GameHandler& g
areaTriggerToasts_.end()); areaTriggerToasts_.end());
if (areaTriggerToasts_.empty()) return; if (areaTriggerToasts_.empty()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -461,7 +461,7 @@ void ToastManager::triggerDing(uint32_t newLevel, uint32_t hpDelta, uint32_t man
dingStats_[3] = intel; dingStats_[3] = intel;
dingStats_[4] = spi; dingStats_[4] = spi;
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
if (auto* sfx = renderer->getUiSoundManager()) { if (auto* sfx = renderer->getUiSoundManager()) {
sfx->playLevelUp(); sfx->playLevelUp();
@ -550,7 +550,7 @@ void ToastManager::triggerAchievementToast(uint32_t achievementId, std::string n
achievementToastTimer_ = ACHIEVEMENT_TOAST_DURATION; achievementToastTimer_ = ACHIEVEMENT_TOAST_DURATION;
// Play a UI sound if available // Play a UI sound if available
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
if (auto* sfx = renderer->getUiSoundManager()) { if (auto* sfx = renderer->getUiSoundManager()) {
sfx->playAchievementAlert(); sfx->playAchievementAlert();
@ -565,7 +565,7 @@ void ToastManager::renderAchievementToast() {
achievementToastTimer_ -= dt; achievementToastTimer_ -= dt;
if (achievementToastTimer_ < 0.0f) achievementToastTimer_ = 0.0f; if (achievementToastTimer_ < 0.0f) achievementToastTimer_ = 0.0f;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -641,7 +641,7 @@ void ToastManager::renderDiscoveryToast() {
alpha = 1.0f; alpha = 1.0f;
alpha = std::clamp(alpha, 0.0f, 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<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(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 // Also poll the renderer for zone name changes (covers map-level transitions
// where worldStateZoneId may not change immediately). // where worldStateZoneId may not change immediately).
auto* appRenderer = core::Application::getInstance().getRenderer(); auto* appRenderer = services_.renderer;
if (appRenderer) { if (appRenderer) {
const std::string& zoneName = appRenderer->getCurrentZoneName(); const std::string& zoneName = appRenderer->getCurrentZoneName();
if (!zoneName.empty() && zoneName != lastKnownZoneName_) { if (!zoneName.empty() && zoneName != lastKnownZoneName_) {
@ -1202,7 +1202,7 @@ void ToastManager::renderZoneText(game::GameHandler& gameHandler) {
zoneTextTimer_ -= dt; zoneTextTimer_ -= dt;
if (zoneTextTimer_ < 0.0f) zoneTextTimer_ = 0.0f; if (zoneTextTimer_ < 0.0f) zoneTextTimer_ = 0.0f;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;

View file

@ -83,7 +83,7 @@ void WindowManager::renderLootWindow(game::GameHandler& gameHandler,
ChatPanel& chatPanel) { ChatPanel& chatPanel) {
if (!gameHandler.isLootWindowOpen()) return; if (!gameHandler.isLootWindowOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 200), ImGuiCond_Appearing); ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 150, 200), ImGuiCond_Appearing);
@ -273,7 +273,7 @@ void WindowManager::renderGossipWindow(game::GameHandler& gameHandler,
ChatPanel& chatPanel) { ChatPanel& chatPanel) {
if (!gameHandler.isGossipWindowOpen()) return; if (!gameHandler.isGossipWindowOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 150), ImGuiCond_Appearing); ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 150), ImGuiCond_Appearing);
@ -445,7 +445,7 @@ void WindowManager::renderQuestDetailsWindow(game::GameHandler& gameHandler,
InventoryScreen& inventoryScreen) { InventoryScreen& inventoryScreen) {
if (!gameHandler.isQuestDetailsOpen()) return; if (!gameHandler.isQuestDetailsOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -569,7 +569,7 @@ void WindowManager::renderQuestRequestItemsWindow(game::GameHandler& gameHandler
InventoryScreen& inventoryScreen) { InventoryScreen& inventoryScreen) {
if (!gameHandler.isQuestRequestItemsOpen()) return; if (!gameHandler.isQuestRequestItemsOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -672,7 +672,7 @@ void WindowManager::renderQuestOfferRewardWindow(game::GameHandler& gameHandler,
InventoryScreen& inventoryScreen) { InventoryScreen& inventoryScreen) {
if (!gameHandler.isQuestOfferRewardOpen()) return; if (!gameHandler.isQuestOfferRewardOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -845,7 +845,7 @@ void WindowManager::renderQuestOfferRewardWindow(game::GameHandler& gameHandler,
void WindowManager::loadExtendedCostDBC() { void WindowManager::loadExtendedCostDBC() {
if (extendedCostDbLoaded_) return; if (extendedCostDbLoaded_) return;
extendedCostDbLoaded_ = true; extendedCostDbLoaded_ = true;
auto* am = core::Application::getInstance().getAssetManager(); auto* am = services_.assetManager;
if (!am || !am->isInitialized()) return; if (!am || !am->isInitialized()) return;
auto dbc = am->loadDBC("ItemExtendedCost.dbc"); auto dbc = am->loadDBC("ItemExtendedCost.dbc");
if (!dbc || !dbc->isLoaded()) return; if (!dbc || !dbc->isLoaded()) return;
@ -898,7 +898,7 @@ void WindowManager::renderVendorWindow(game::GameHandler& gameHandler,
ChatPanel& chatPanel) { ChatPanel& chatPanel) {
if (!gameHandler.isVendorWindowOpen()) return; if (!gameHandler.isVendorWindowOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 100), ImGuiCond_Appearing); ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 100), ImGuiCond_Appearing);
@ -1236,9 +1236,9 @@ void WindowManager::renderTrainerWindow(game::GameHandler& gameHandler,
SpellIconFn getSpellIcon) { SpellIconFn getSpellIcon) {
if (!gameHandler.isTrainerWindowOpen()) return; if (!gameHandler.isTrainerWindowOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
auto* assetMgr = core::Application::getInstance().getAssetManager(); auto* assetMgr = services_.assetManager;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 225, 100), ImGuiCond_Appearing); ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 225, 100), ImGuiCond_Appearing);
ImGui::SetNextWindowSize(ImVec2(500, 450), ImGuiCond_Appearing); ImGui::SetNextWindowSize(ImVec2(500, 450), ImGuiCond_Appearing);
@ -1701,7 +1701,7 @@ void WindowManager::renderEscapeMenu(SettingsPanel& settingsPanel) {
settingsPanel.showEscapeSettingsNotice = false; settingsPanel.showEscapeSettingsNotice = false;
} }
if (ImGui::Button("Quit", ImVec2(-1, 0))) { if (ImGui::Button("Quit", ImVec2(-1, 0))) {
auto* renderer = core::Application::getInstance().getRenderer(); auto* renderer = services_.renderer;
if (renderer) { if (renderer) {
if (auto* music = renderer->getMusicManager()) { if (auto* music = renderer->getMusicManager()) {
music->stopMusic(0.0f); music->stopMusic(0.0f);
@ -1763,7 +1763,7 @@ void WindowManager::renderBarberShopWindow(game::GameHandler& gameHandler) {
int maxHairColor = static_cast<int>(game::getMaxHairColor(raceEnum, gender)); int maxHairColor = static_cast<int>(game::getMaxHairColor(raceEnum, gender));
int maxFacialHair = static_cast<int>(game::getMaxFacialFeature(raceEnum, gender)); int maxFacialHair = static_cast<int>(game::getMaxFacialFeature(raceEnum, gender));
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
float winW = 300.0f; float winW = 300.0f;
@ -1847,7 +1847,7 @@ void WindowManager::renderBarberShopWindow(game::GameHandler& gameHandler) {
void WindowManager::renderStableWindow(game::GameHandler& gameHandler) { void WindowManager::renderStableWindow(game::GameHandler& gameHandler) {
if (!gameHandler.isStableWindowOpen()) return; if (!gameHandler.isStableWindowOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -1960,7 +1960,7 @@ void WindowManager::renderStableWindow(game::GameHandler& gameHandler) {
void WindowManager::renderTaxiWindow(game::GameHandler& gameHandler) { void WindowManager::renderTaxiWindow(game::GameHandler& gameHandler) {
if (!gameHandler.isTaxiWindowOpen()) return; if (!gameHandler.isTaxiWindowOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 200, 150), ImGuiCond_Appearing); 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) { void WindowManager::renderLogoutCountdown(game::GameHandler& gameHandler) {
if (!gameHandler.isLoggingOut()) return; if (!gameHandler.isLoggingOut()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -2127,7 +2127,7 @@ void WindowManager::renderDeathScreen(game::GameHandler& gameHandler) {
deathElapsed_ += dt; deathElapsed_ += dt;
} }
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -2216,7 +2216,7 @@ void WindowManager::renderDeathScreen(game::GameHandler& gameHandler) {
void WindowManager::renderReclaimCorpseButton(game::GameHandler& gameHandler) { void WindowManager::renderReclaimCorpseButton(game::GameHandler& gameHandler) {
if (!gameHandler.isPlayerGhost() || !gameHandler.canReclaimCorpse()) return; if (!gameHandler.isPlayerGhost() || !gameHandler.canReclaimCorpse()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -2274,7 +2274,7 @@ void WindowManager::renderMailWindow(game::GameHandler& gameHandler,
ChatPanel& chatPanel) { ChatPanel& chatPanel) {
if (!gameHandler.isMailboxOpen()) return; if (!gameHandler.isMailboxOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 250, 80), ImGuiCond_Appearing); ImGui::SetNextWindowPos(ImVec2(screenW / 2 - 250, 80), ImGuiCond_Appearing);
@ -2553,7 +2553,7 @@ void WindowManager::renderMailComposeWindow(game::GameHandler& gameHandler,
InventoryScreen& inventoryScreen) { InventoryScreen& inventoryScreen) {
if (!gameHandler.isMailComposeOpen()) return; if (!gameHandler.isMailComposeOpen()) return;
auto* window = core::Application::getInstance().getWindow(); auto* window = services_.window;
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f; float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f; float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
@ -3769,7 +3769,7 @@ void WindowManager::renderAchievementWindow(game::GameHandler& gameHandler) {
static bool s_criteriaDataLoaded = false; static bool s_criteriaDataLoaded = false;
if (!s_criteriaDataLoaded) { if (!s_criteriaDataLoaded) {
s_criteriaDataLoaded = true; s_criteriaDataLoaded = true;
auto* am = core::Application::getInstance().getAssetManager(); auto* am = services_.assetManager;
if (am && am->isInitialized()) { if (am && am->isInitialized()) {
auto dbc = am->loadDBC("AchievementCriteria.dbc"); auto dbc = am->loadDBC("AchievementCriteria.dbc");
if (dbc && dbc->isLoaded() && dbc->getFieldCount() >= 10) { if (dbc && dbc->isLoaded() && dbc->getFieldCount() >= 10) {