chore(renderer): extract AnimationController and remove audio pass-throughs

Extract ~1,500 lines of character animation state from Renderer into a dedicated
AnimationController class, and complete the AudioCoordinator migration by removing
all 10 audio pass-through getters from Renderer.

AnimationController:
- New: include/rendering/animation_controller.hpp (182 lines)
- New: src/rendering/animation_controller.cpp (1,703 lines)
- Moves: locomotion state machine (50+ members), mount animation (40+ members),
  emote system, footstep triggering, surface detection, melee combat animations
- Renderer holds std::unique_ptr<AnimationController> and delegates completely
- AnimationController accesses audio via renderer_->getAudioCoordinator()

Audio caller migration:
- Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator
  directly, grouped by access pattern:
  - UIServices: settings_panel, game_screen, toast_manager, chat_panel,
    combat_ui, window_manager
  - GameServices: game_handler, spell_handler, inventory_handler, quest_handler,
    social_handler, combat_handler
  - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp
- Remove 10 pass-through getter definitions from renderer.cpp
- Remove 10 pass-through getter declarations from renderer.hpp
- Remove individual audio manager forward declarations from renderer.hpp
- Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly
- game_handler.cpp: withSoundManager template uses services_.audioCoordinator;
  MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager
- GameServices struct: add AudioCoordinator* audioCoordinator member
- settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
This commit is contained in:
Paul 2026-04-02 13:06:31 +03:00
parent 5ef600098a
commit 5af9f7aa4b
22 changed files with 2208 additions and 1958 deletions

View file

@ -4,6 +4,7 @@
#include "game/entity.hpp"
#include "game/packet_parsers.hpp"
#include "rendering/renderer.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/ui_sound_manager.hpp"
#include "core/application.hpp"
#include "core/logger.hpp"
@ -70,9 +71,9 @@ void InventoryHandler::registerOpcodes(DispatchTable& table) {
}
if (!alreadyAnnounced) {
owner_.addSystemChatMessage("Looted: " + formatCopperAmount(amount));
auto* renderer = owner_.services().renderer;
if (renderer) {
if (auto* sfx = renderer->getUiSoundManager()) {
auto* ac = owner_.services().audioCoordinator;
if (ac) {
if (auto* sfx = ac->getUiSoundManager()) {
if (amount >= 10000) sfx->playLootCoinLarge();
else sfx->playLootCoinSmall();
}
@ -222,8 +223,8 @@ void InventoryHandler::registerOpcodes(DispatchTable& table) {
std::string msg = "Received item: " + link;
if (count > 1) msg += " x" + std::to_string(count);
owner_.addSystemChatMessage(msg);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager())
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager())
sfx->playLootItem();
}
if (owner_.addonEventCallback_) {
@ -253,8 +254,8 @@ void InventoryHandler::registerOpcodes(DispatchTable& table) {
" result=", static_cast<int>(result));
if (result == 0) {
pendingSellToBuyback_.erase(itemGuid);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager())
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager())
sfx->playDropOnGround();
}
if (owner_.addonEventCallback_) {
@ -295,8 +296,8 @@ void InventoryHandler::registerOpcodes(DispatchTable& table) {
const char* msg = (result < 7) ? sellErrors[result] : "Unknown sell error";
owner_.addUIError(std::string("Sell failed: ") + msg);
owner_.addSystemChatMessage(std::string("Sell failed: ") + msg);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager())
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager())
sfx->playError();
}
LOG_WARNING("SMSG_SELL_ITEM error: ", (int)result, " (", msg, ")");
@ -392,8 +393,8 @@ void InventoryHandler::registerOpcodes(DispatchTable& table) {
std::string msg = errMsg ? errMsg : "Inventory error (" + std::to_string(error) + ").";
owner_.addUIError(msg);
owner_.addSystemChatMessage(msg);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager())
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager())
sfx->playError();
}
}
@ -450,8 +451,8 @@ void InventoryHandler::registerOpcodes(DispatchTable& table) {
}
owner_.addUIError(msg);
owner_.addSystemChatMessage(msg);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager())
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager())
sfx->playError();
}
}
@ -474,8 +475,8 @@ void InventoryHandler::registerOpcodes(DispatchTable& table) {
std::string msg = "Purchased: " + buildItemLink(pendingBuyItemId_, buyQuality, itemLabel);
if (itemCount > 1) msg += " x" + std::to_string(itemCount);
owner_.addSystemChatMessage(msg);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager())
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager())
sfx->playPickupBag();
}
}
@ -766,8 +767,8 @@ void InventoryHandler::handleLootRemoved(network::Packet& packet) {
std::string msgStr = "Looted: " + link;
if (it->count > 1) msgStr += " x" + std::to_string(it->count);
owner_.addSystemChatMessage(msgStr);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager())
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager())
sfx->playLootItem();
}
currentLoot_.items.erase(it);
@ -2382,8 +2383,8 @@ void InventoryHandler::handleItemQueryResponse(network::Packet& packet) {
std::string msg = "Received: " + link;
if (it->count > 1) msg += " x" + std::to_string(it->count);
owner_.addSystemChatMessage(msg);
if (auto* renderer = owner_.services().renderer) {
if (auto* sfx = renderer->getUiSoundManager()) sfx->playLootItem();
if (auto* ac = owner_.services().audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager()) sfx->playLootItem();
}
if (owner_.itemLootCallback_) owner_.itemLootCallback_(data.entry, it->count, data.quality, itemName);
it = owner_.pendingItemPushNotifs_.erase(it);
@ -3149,8 +3150,8 @@ void InventoryHandler::handleTrainerBuySucceeded(network::Packet& packet) {
owner_.addSystemChatMessage("You have learned " + name + ".");
else
owner_.addSystemChatMessage("Spell learned.");
if (auto* renderer = owner_.services().renderer)
if (auto* sfx = renderer->getUiSoundManager()) sfx->playQuestActivate();
if (auto* ac = owner_.services().audioCoordinator)
if (auto* sfx = ac->getUiSoundManager()) sfx->playQuestActivate();
owner_.fireAddonEvent("TRAINER_UPDATE", {});
owner_.fireAddonEvent("SPELLS_CHANGED", {});
}
@ -3171,8 +3172,8 @@ void InventoryHandler::handleTrainerBuyFailed(network::Packet& packet) {
else if (errorCode != 0) msg += " (error " + std::to_string(errorCode) + ")";
owner_.addUIError(msg);
owner_.addSystemChatMessage(msg);
if (auto* renderer = owner_.services().renderer)
if (auto* sfx = renderer->getUiSoundManager()) sfx->playError();
if (auto* ac = owner_.services().audioCoordinator)
if (auto* sfx = ac->getUiSoundManager()) sfx->playError();
}
// ============================================================