Kelsidavis-WoWee/src/core/ui_screen_callback_handler.cpp
Paul 6dcc06697b refactor(core): decompose Application::setupUICallbacks() into 7 domain handlers
Extract ~1,700 lines / 60+ inline [this]-capturing lambdas from the monolithic
Application::setupUICallbacks() into 7 focused callback handler classes following
the ToastManager/ChatPanel::setupCallbacks() pattern already in the codebase.

New handlers (include/core/ + src/core/):
  - NPCInteractionCallbackHandler  NPC greeting/farewell/vendor/aggro voice
  - AudioCallbackHandler           Music, positional sound, level-up, achievement, LFG
  - EntitySpawnCallbackHandler     Creature/player/GO spawn, despawn, move, state
  - AnimationCallbackHandler       Death, respawn, combat, emotes, charge, sprint, vehicle
  - TransportCallbackHandler       Mount, taxi, transport spawn/move
  - WorldEntryCallbackHandler      World entry, unstuck, hearthstone, bind point
  - UIScreenCallbackHandler        Auth, realm selection, char selection/creation/deletion

application.cpp:  4,462 → 2,791 lines  (−1,671)
setupUICallbacks: ~1,700 → ~50 lines (thin orchestrator)

Deduplication:
  resolveSoundEntryPath()   — was 3× copy-paste of SoundEntries.dbc lookup
  resolveNpcVoiceType()     — was 4× copy-paste of display-ID→voice detection
  precacheNearbyTiles()     — was 3× copy-paste of 17×17 tile loop
  4 helper lambdas          — promoted to private methods on WorldEntryCallbackHandler

State migration out of Application:
  charge* (6 vars)          → AnimationCallbackHandler
  hearth*/worldEntry*/taxi* → WorldEntryCallbackHandler
  pendingCreatedCharacterName_ → UIScreenCallbackHandler

Bug fixes:
  - Duplicate `namespace core {` in application.hpp caused wowee::std pollution
  - AppState forward decl in ui_screen_callback_handler.hpp was at wrong scope
  - world_loader.cpp accessed moved member vars directly via friend; now uses handler API
2026-04-05 16:48:17 +03:00

182 lines
7.3 KiB
C++

#include "core/ui_screen_callback_handler.hpp"
#include "core/application.hpp" // AppState
#include "core/logger.hpp"
#include "ui/ui_manager.hpp"
#include "auth/auth_handler.hpp"
#include "game/game_handler.hpp"
#include "game/expansion_profile.hpp"
#include "game/world_packets.hpp"
#include "pipeline/asset_manager.hpp"
namespace wowee { namespace core {
UIScreenCallbackHandler::UIScreenCallbackHandler(
ui::UIManager& uiManager,
game::GameHandler& gameHandler,
auth::AuthHandler& authHandler,
game::ExpansionRegistry* expansionRegistry,
pipeline::AssetManager* assetManager,
SetStateFn setState)
: uiManager_(uiManager)
, gameHandler_(gameHandler)
, authHandler_(authHandler)
, expansionRegistry_(expansionRegistry)
, assetManager_(assetManager)
, setState_(std::move(setState))
{
}
void UIScreenCallbackHandler::setupCallbacks() {
// Authentication screen callback
uiManager_.getAuthScreen().setOnSuccess([this]() {
LOG_INFO("Authentication successful, transitioning to realm selection");
setState_(AppState::REALM_SELECTION);
});
// Realm selection callback
uiManager_.getRealmScreen().setOnRealmSelected([this](const std::string& realmName, const std::string& realmAddress) {
LOG_INFO("Realm selected: ", realmName, " (", realmAddress, ")");
// Parse realm address (format: "hostname:port")
std::string host = realmAddress;
uint16_t port = 8085; // Default world server port
size_t colonPos = realmAddress.find(':');
if (colonPos != std::string::npos) {
host = realmAddress.substr(0, colonPos);
try { port = static_cast<uint16_t>(std::stoi(realmAddress.substr(colonPos + 1))); }
catch (...) { LOG_WARNING("Invalid port in realm address: ", realmAddress); }
}
// Connect to world server
const auto& sessionKey = authHandler_.getSessionKey();
std::string accountName = authHandler_.getUsername();
if (accountName.empty()) {
LOG_WARNING("Auth username missing; falling back to TESTACCOUNT");
accountName = "TESTACCOUNT";
}
uint32_t realmId = 0;
uint16_t realmBuild = 0;
{
// WotLK AUTH_SESSION includes a RealmID field; some servers reject if it's wrong/zero.
const auto& realms = authHandler_.getRealms();
for (const auto& r : realms) {
if (r.name == realmName && r.address == realmAddress) {
realmId = r.id;
realmBuild = r.build;
break;
}
}
LOG_INFO("Selected realmId=", realmId, " realmBuild=", realmBuild);
}
uint32_t clientBuild = 12340; // default WotLK
if (expansionRegistry_) {
auto* profile = expansionRegistry_->getActive();
if (profile) clientBuild = profile->worldBuild;
}
// Prefer realm-reported build when available (e.g. vanilla servers
// that report build 5875 in the realm list)
if (realmBuild != 0) {
clientBuild = realmBuild;
LOG_INFO("Using realm-reported build: ", clientBuild);
}
if (gameHandler_.connect(host, port, sessionKey, accountName, clientBuild, realmId)) {
LOG_INFO("Connected to world server, transitioning to character selection");
setState_(AppState::CHARACTER_SELECTION);
} else {
LOG_ERROR("Failed to connect to world server");
}
});
// Realm screen back button - return to login
uiManager_.getRealmScreen().setOnBack([this]() {
authHandler_.disconnect();
uiManager_.getRealmScreen().reset();
setState_(AppState::AUTHENTICATION);
});
// Character selection callback
uiManager_.getCharacterScreen().setOnCharacterSelected([this](uint64_t characterGuid) {
LOG_INFO("Character selected: GUID=0x", std::hex, characterGuid, std::dec);
// Always set the active character GUID
gameHandler_.setActiveCharacterGuid(characterGuid);
// Keep CHARACTER_SELECTION active until world entry is fully loaded.
// This avoids exposing pre-load hitching before the loading screen/intro.
});
// Character create screen callbacks
uiManager_.getCharacterCreateScreen().setOnCreate([this](const game::CharCreateData& data) {
pendingCreatedCharacterName_ = data.name; // Store name for auto-selection
gameHandler_.createCharacter(data);
});
uiManager_.getCharacterCreateScreen().setOnCancel([this]() {
setState_(AppState::CHARACTER_SELECTION);
});
// Character create result callback
gameHandler_.setCharCreateCallback([this](bool success, const std::string& msg) {
if (success) {
// Auto-select the newly created character
if (!pendingCreatedCharacterName_.empty()) {
uiManager_.getCharacterScreen().selectCharacterByName(pendingCreatedCharacterName_);
pendingCreatedCharacterName_.clear();
}
setState_(AppState::CHARACTER_SELECTION);
} else {
uiManager_.getCharacterCreateScreen().setStatus(msg, true);
pendingCreatedCharacterName_.clear();
}
});
// Character login failure callback
gameHandler_.setCharLoginFailCallback([this](const std::string& reason) {
LOG_WARNING("Character login failed: ", reason);
setState_(AppState::CHARACTER_SELECTION);
uiManager_.getCharacterScreen().setStatus("Login failed: " + reason, true);
});
// "Create Character" button on character screen
uiManager_.getCharacterScreen().setOnCreateCharacter([this]() {
uiManager_.getCharacterCreateScreen().reset();
// Apply expansion race/class constraints before showing the screen
if (expansionRegistry_ && expansionRegistry_->getActive()) {
auto* profile = expansionRegistry_->getActive();
uiManager_.getCharacterCreateScreen().setExpansionConstraints(
profile->races, profile->classes);
}
uiManager_.getCharacterCreateScreen().initializePreview(assetManager_);
setState_(AppState::CHARACTER_CREATION);
});
// "Back" button on character screen
uiManager_.getCharacterScreen().setOnBack([this]() {
// Disconnect from world server and reset UI state for fresh realm selection
gameHandler_.disconnect();
uiManager_.getRealmScreen().reset();
uiManager_.getCharacterScreen().reset();
setState_(AppState::REALM_SELECTION);
});
// "Delete Character" button on character screen
uiManager_.getCharacterScreen().setOnDeleteCharacter([this](uint64_t guid) {
gameHandler_.deleteCharacter(guid);
});
// Character delete result callback
gameHandler_.setCharDeleteCallback([this](bool success) {
if (success) {
uiManager_.getCharacterScreen().setStatus("Character deleted.");
// Refresh character list
gameHandler_.requestCharacterList();
} else {
uint8_t code = gameHandler_.getLastCharDeleteResult();
uiManager_.getCharacterScreen().setStatus(
"Delete failed (code " + std::to_string(static_cast<int>(code)) + ").", true);
}
});
}
}} // namespace wowee::core