chore(game-ui): extract GameScreen domains

- Extracted `GameScreen` functionality into dedicated UI domains
- Added new panels:
  - `action_bar_panel`
  - `combat_ui`
  - `social_panel`
  - `window_manager`
- Updated `game_screen` + CMakeLists.txt integration
- Added new headers and sources under ui and ui
This commit is contained in:
Paul 2026-03-31 19:49:52 +03:00
parent af9874484a
commit c9353853f8
11 changed files with 11054 additions and 10395 deletions

View file

@ -13,6 +13,10 @@
#include "ui/toast_manager.hpp"
#include "ui/dialog_manager.hpp"
#include "ui/settings_panel.hpp"
#include "ui/combat_ui.hpp"
#include "ui/social_panel.hpp"
#include "ui/action_bar_panel.hpp"
#include "ui/window_manager.hpp"
#include <vulkan/vulkan.h>
#include <imgui.h>
#include <string>
@ -59,9 +63,17 @@ private:
// Settings panel (extracted from GameScreen — owns all settings UI and config state)
SettingsPanel settingsPanel_;
// Action bar error-flash: spellId → wall-clock time (seconds) when the flash ends.
// Populated by the SpellCastFailedCallback; queried during action bar button rendering.
std::unordered_map<uint32_t, float> actionFlashEndTimes_;
// Combat UI (extracted from GameScreen — owns all combat overlay rendering)
CombatUI combatUI_;
// Social panel (extracted from GameScreen — owns all social/group UI rendering)
SocialPanel socialPanel_;
// Action bar panel (extracted from GameScreen — owns action/stance/bag/xp/rep bars)
ActionBarPanel actionBarPanel_;
// Window manager (extracted from GameScreen — owns NPC windows, popups, overlays)
WindowManager windowManager_;
// UI state
bool showEntityWindow = false;
@ -74,59 +86,21 @@ private:
float damageFlashAlpha_ = 0.0f; // Screen edge flash intensity (fades to 0)
// Raid Warning / Boss Emote big-text overlay (center-screen, fades after 5s)
struct RaidWarnEntry {
std::string text;
float age = 0.0f;
bool isBossEmote = false; // true = amber, false (raid warning) = red+yellow
static constexpr float LIFETIME = 5.0f;
};
std::vector<RaidWarnEntry> raidWarnEntries_;
bool raidWarnCallbackSet_ = false;
size_t raidWarnChatSeenCount_ = 0; // index into chat history for unread scan
// UIErrorsFrame: WoW-style center-bottom error messages (spell fails, out of range, etc.)
struct UIErrorEntry { std::string text; float age = 0.0f; };
std::vector<UIErrorEntry> uiErrors_;
bool uiErrorCallbackSet_ = false;
static constexpr float kUIErrorLifetime = 2.5f;
bool castFailedCallbackSet_ = false;
static constexpr float kActionFlashDuration = 0.5f; // seconds for error-red overlay to fade
// Death screen: elapsed time since the death dialog first appeared
float deathElapsed_ = 0.0f;
bool deathTimerRunning_ = false;
// WoW forces release after ~6 minutes; show countdown until then
static constexpr float kForcedReleaseSec = 360.0f;
bool showPlayerInfo = false;
bool showSocialFrame_ = false; // O key toggles social/friends list
bool showGuildRoster_ = false;
bool showRaidFrames_ = true; // F key toggles raid/party frames
bool showWorldMap_ = false; // W key toggles world map
std::string selectedGuildMember_;
bool showGuildNoteEdit_ = false;
bool editingOfficerNote_ = false;
char guildNoteEditBuffer_[256] = {0};
int guildRosterTab_ = 0; // 0=Roster, 1=Guild Info
char guildMotdEditBuffer_[256] = {0};
bool showMotdEdit_ = false;
char petitionNameBuffer_[64] = {0};
char addRankNameBuffer_[64] = {0};
bool showAddRankModal_ = false;
bool vendorBagsOpened_ = false; // Track if bags were auto-opened for current vendor session
ImVec2 questTrackerPos_ = ImVec2(-1.0f, -1.0f); // <0 = use default
ImVec2 questTrackerSize_ = ImVec2(220.0f, 200.0f); // saved size
float questTrackerRightOffset_ = -1.0f; // pixels from right edge; <0 = use default
bool questTrackerPosInit_ = false;
bool showEscapeMenu = false;
// Macro editor popup state
uint32_t macroEditorId_ = 0; // macro index being edited
bool macroEditorOpen_ = false; // deferred OpenPopup flag
char macroEditorBuf_[256] = {}; // edit buffer
/**
* Render player info window
@ -170,51 +144,13 @@ private:
*/
void updateCharacterTextures(game::Inventory& inventory);
// ---- New UI renders ----
void renderActionBar(game::GameHandler& gameHandler);
void renderStanceBar(game::GameHandler& gameHandler);
void renderBagBar(game::GameHandler& gameHandler);
void renderXpBar(game::GameHandler& gameHandler);
void renderRepBar(game::GameHandler& gameHandler);
void renderCastBar(game::GameHandler& gameHandler);
void renderMirrorTimers(game::GameHandler& gameHandler);
void renderCooldownTracker(game::GameHandler& gameHandler);
void renderCombatText(game::GameHandler& gameHandler);
void renderRaidWarningOverlay(game::GameHandler& gameHandler);
void renderPartyFrames(game::GameHandler& gameHandler);
void renderBossFrames(game::GameHandler& gameHandler);
void renderUIErrors(game::GameHandler& gameHandler, float deltaTime);
void renderBuffBar(game::GameHandler& gameHandler);
void renderSocialFrame(game::GameHandler& gameHandler);
void renderLootWindow(game::GameHandler& gameHandler);
void renderGossipWindow(game::GameHandler& gameHandler);
void renderQuestDetailsWindow(game::GameHandler& gameHandler);
void renderQuestRequestItemsWindow(game::GameHandler& gameHandler);
void renderQuestOfferRewardWindow(game::GameHandler& gameHandler);
void renderVendorWindow(game::GameHandler& gameHandler);
void renderTrainerWindow(game::GameHandler& gameHandler);
void renderBarberShopWindow(game::GameHandler& gameHandler);
void renderStableWindow(game::GameHandler& gameHandler);
void renderTaxiWindow(game::GameHandler& gameHandler);
void renderLogoutCountdown(game::GameHandler& gameHandler);
void renderDeathScreen(game::GameHandler& gameHandler);
void renderReclaimCorpseButton(game::GameHandler& gameHandler);
void renderEscapeMenu();
void renderMirrorTimers(game::GameHandler& gameHandler);
void renderUIErrors(game::GameHandler& gameHandler, float deltaTime);
void renderQuestMarkers(game::GameHandler& gameHandler);
void renderMinimapMarkers(game::GameHandler& gameHandler);
void renderQuestObjectiveTracker(game::GameHandler& gameHandler);
void renderGuildRoster(game::GameHandler& gameHandler);
void renderMailWindow(game::GameHandler& gameHandler);
void renderMailComposeWindow(game::GameHandler& gameHandler);
void renderBankWindow(game::GameHandler& gameHandler);
void renderGuildBankWindow(game::GameHandler& gameHandler);
void renderAuctionHouseWindow(game::GameHandler& gameHandler);
void renderDungeonFinderWindow(game::GameHandler& gameHandler);
void renderInstanceLockouts(game::GameHandler& gameHandler);
void renderNameplates(game::GameHandler& gameHandler);
void renderBattlegroundScore(game::GameHandler& gameHandler);
void renderDPSMeter(game::GameHandler& gameHandler);
void renderDurabilityWarning(game::GameHandler& gameHandler);
void takeScreenshot(game::GameHandler& gameHandler);
@ -239,144 +175,13 @@ private:
bool spellIconDbLoaded_ = false;
VkDescriptorSet getSpellIcon(uint32_t spellId, pipeline::AssetManager* am);
// ItemExtendedCost.dbc cache: extendedCostId -> cost details
struct ExtendedCostEntry {
uint32_t honorPoints = 0;
uint32_t arenaPoints = 0;
uint32_t itemId[5] = {};
uint32_t itemCount[5] = {};
};
std::unordered_map<uint32_t, ExtendedCostEntry> extendedCostCache_;
bool extendedCostDbLoaded_ = false;
void loadExtendedCostDBC();
std::string formatExtendedCost(uint32_t extendedCostId, game::GameHandler& gameHandler);
// Macro cooldown cache: maps macro ID → resolved primary spell ID (0 = no spell found)
std::unordered_map<uint32_t, uint32_t> macroPrimarySpellCache_;
size_t macroCacheSpellCount_ = 0; // invalidates cache when spell list changes
uint32_t resolveMacroPrimarySpellId(uint32_t macroId, game::GameHandler& gameHandler);
// Death Knight rune bar: client-predicted fill (0.0=depleted, 1.0=ready) for smooth animation
float runeClientFill_[6] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
// Action bar drag state (-1 = not dragging)
int actionBarDragSlot_ = -1;
VkDescriptorSet actionBarDragIcon_ = VK_NULL_HANDLE;
// Bag bar state
VkDescriptorSet backpackIconTexture_ = VK_NULL_HANDLE;
VkDescriptorSet emptyBagSlotTexture_ = VK_NULL_HANDLE;
int bagBarPickedSlot_ = -1; // Visual drag in progress (-1 = none)
int bagBarDragSource_ = -1; // Mouse pressed on this slot, waiting for drag or click (-1 = none)
// Who Results window
bool showWhoWindow_ = false;
void renderWhoWindow(game::GameHandler& gameHandler);
// Combat Log window
bool showCombatLog_ = false;
void renderCombatLog(game::GameHandler& gameHandler);
// Instance Lockouts window
bool showInstanceLockouts_ = false;
// Dungeon Finder state
bool showDungeonFinder_ = false;
// Achievements window
bool showAchievementWindow_ = false;
char achievementSearchBuf_[128] = {};
void renderAchievementWindow(game::GameHandler& gameHandler);
// Skills / Professions window (K key)
bool showSkillsWindow_ = false;
void renderSkillsWindow(game::GameHandler& gameHandler);
// Titles window
bool showTitlesWindow_ = false;
void renderTitlesWindow(game::GameHandler& gameHandler);
// Equipment Set Manager window
bool showEquipSetWindow_ = false;
void renderEquipSetWindow(game::GameHandler& gameHandler);
// GM Ticket window
bool showGmTicketWindow_ = false;
bool gmTicketWindowWasOpen_ = false; ///< Previous frame state; used to fire one-shot query
char gmTicketBuf_[2048] = {};
void renderGmTicketWindow(game::GameHandler& gameHandler);
// Pet rename modal (triggered from pet frame context menu)
bool petRenameOpen_ = false;
char petRenameBuf_[16] = {};
// Inspect window
bool showInspectWindow_ = false;
void renderInspectWindow(game::GameHandler& gameHandler);
// Readable text window (books / scrolls / notes)
bool showBookWindow_ = false;
int bookCurrentPage_ = 0;
void renderBookWindow(game::GameHandler& gameHandler);
// Threat window
bool showThreatWindow_ = false;
void renderThreatWindow(game::GameHandler& gameHandler);
// BG scoreboard window
bool showBgScoreboard_ = false;
void renderBgScoreboard(game::GameHandler& gameHandler);
uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps)
uint32_t lfgSelectedDungeon_ = 861; // default: random dungeon (entry 861 = Random Dungeon WotLK)
// Mail compose state
char mailRecipientBuffer_[256] = "";
char mailSubjectBuffer_[256] = "";
char mailBodyBuffer_[2048] = "";
int mailComposeMoney_[3] = {0, 0, 0}; // gold, silver, copper
// Vendor search filter
char vendorSearchFilter_[128] = "";
// Vendor purchase confirmation for expensive items
bool vendorConfirmOpen_ = false;
uint64_t vendorConfirmGuid_ = 0;
uint32_t vendorConfirmItemId_ = 0;
uint32_t vendorConfirmSlot_ = 0;
uint32_t vendorConfirmQty_ = 1;
uint32_t vendorConfirmPrice_ = 0;
std::string vendorConfirmItemName_;
// Barber shop UI state
int barberHairStyle_ = 0;
int barberHairColor_ = 0;
int barberFacialHair_ = 0;
int barberOrigHairStyle_ = 0;
int barberOrigHairColor_ = 0;
int barberOrigFacialHair_ = 0;
bool barberInitialized_ = false;
// Trainer search filter
char trainerSearchFilter_[128] = "";
// Auction house UI state
char auctionSearchName_[256] = "";
int auctionLevelMin_ = 0;
int auctionLevelMax_ = 0;
int auctionQuality_ = 0;
int auctionSellDuration_ = 2; // 0=12h, 1=24h, 2=48h
int auctionSellBid_[3] = {0, 0, 0}; // gold, silver, copper
int auctionSellBuyout_[3] = {0, 0, 0}; // gold, silver, copper
int auctionSelectedItem_ = -1;
int auctionSellSlotIndex_ = -1; // Selected backpack slot for selling
uint32_t auctionBrowseOffset_ = 0; // Pagination offset for browse results
int auctionItemClass_ = -1; // Item class filter (-1 = All)
int auctionItemSubClass_ = -1; // Item subclass filter (-1 = All)
bool auctionUsableOnly_ = false; // Filter to items usable by current class/level
// Guild bank money input
int guildBankMoneyInput_[3] = {0, 0, 0}; // gold, silver, copper
// Left-click targeting: distinguish click from camera drag
glm::vec2 leftClickPressPos_ = glm::vec2(0.0f);
bool leftClickWasPress_ = false;
@ -390,15 +195,8 @@ private:
void renderWeatherOverlay(game::GameHandler& gameHandler);
// DPS / HPS meter
float dpsCombatAge_ = 0.0f; // seconds in current combat (for accurate early-combat DPS)
bool dpsWasInCombat_ = false;
float dpsEncounterDamage_ = 0.0f; // total player damage this combat
float dpsEncounterHeal_ = 0.0f; // total player healing this combat
size_t dpsLogSeenCount_ = 0; // log entries already scanned
public:
void openDungeonFinder() { showDungeonFinder_ = true; }
void openDungeonFinder() { socialPanel_.showDungeonFinder_ = true; }
ToastManager& toastManager() { return toastManager_; }
};