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

@ -152,6 +152,7 @@ bool Application::initialize() {
// Populate game services — all subsystems now available
gameServices_.renderer = renderer.get();
gameServices_.audioCoordinator = audioCoordinator_.get();
gameServices_.assetManager = assetManager.get();
gameServices_.expansionRegistry = expansionRegistry_.get();
@ -1091,7 +1092,7 @@ void Application::logoutToLogin() {
}
renderer->clearMount();
renderer->setCharacterFollow(0);
if (auto* music = renderer->getMusicManager()) {
if (auto* music = audioCoordinator_ ? audioCoordinator_->getMusicManager() : nullptr) {
music->stopMusic(0.0f);
}
}
@ -2828,7 +2829,7 @@ void Application::setupUICallbacks() {
// Resolves soundId → SoundEntries.dbc → MPQ path → MusicManager.
gameHandler->setPlayMusicCallback([this](uint32_t soundId) {
if (!assetManager || !renderer) return;
auto* music = renderer->getMusicManager();
auto* music = audioCoordinator_ ? audioCoordinator_->getMusicManager() : nullptr;
if (!music) return;
auto dbc = assetManager->loadDBC("SoundEntries.dbc");
@ -3418,7 +3419,7 @@ void Application::setupUICallbacks() {
// NPC greeting callback - play voice line
gameHandler->setNpcGreetingCallback([this](uint64_t guid, const glm::vec3& position) {
if (renderer && renderer->getNpcVoiceManager()) {
if (audioCoordinator_ && audioCoordinator_->getNpcVoiceManager()) {
// Convert canonical to render coords for 3D audio
glm::vec3 renderPos = core::coords::canonicalToRender(position);
@ -3431,13 +3432,13 @@ void Application::setupUICallbacks() {
voiceType = entitySpawner_->detectVoiceTypeFromDisplayId(displayId);
}
renderer->getNpcVoiceManager()->playGreeting(guid, voiceType, renderPos);
audioCoordinator_->getNpcVoiceManager()->playGreeting(guid, voiceType, renderPos);
}
});
// NPC farewell callback - play farewell voice line
gameHandler->setNpcFarewellCallback([this](uint64_t guid, const glm::vec3& position) {
if (renderer && renderer->getNpcVoiceManager()) {
if (audioCoordinator_ && audioCoordinator_->getNpcVoiceManager()) {
glm::vec3 renderPos = core::coords::canonicalToRender(position);
audio::VoiceType voiceType = audio::VoiceType::GENERIC;
@ -3448,13 +3449,13 @@ void Application::setupUICallbacks() {
voiceType = entitySpawner_->detectVoiceTypeFromDisplayId(displayId);
}
renderer->getNpcVoiceManager()->playFarewell(guid, voiceType, renderPos);
audioCoordinator_->getNpcVoiceManager()->playFarewell(guid, voiceType, renderPos);
}
});
// NPC vendor callback - play vendor voice line
gameHandler->setNpcVendorCallback([this](uint64_t guid, const glm::vec3& position) {
if (renderer && renderer->getNpcVoiceManager()) {
if (audioCoordinator_ && audioCoordinator_->getNpcVoiceManager()) {
glm::vec3 renderPos = core::coords::canonicalToRender(position);
audio::VoiceType voiceType = audio::VoiceType::GENERIC;
@ -3465,13 +3466,13 @@ void Application::setupUICallbacks() {
voiceType = entitySpawner_->detectVoiceTypeFromDisplayId(displayId);
}
renderer->getNpcVoiceManager()->playVendor(guid, voiceType, renderPos);
audioCoordinator_->getNpcVoiceManager()->playVendor(guid, voiceType, renderPos);
}
});
// NPC aggro callback - play combat start voice line
gameHandler->setNpcAggroCallback([this](uint64_t guid, const glm::vec3& position) {
if (renderer && renderer->getNpcVoiceManager()) {
if (audioCoordinator_ && audioCoordinator_->getNpcVoiceManager()) {
glm::vec3 renderPos = core::coords::canonicalToRender(position);
audio::VoiceType voiceType = audio::VoiceType::GENERIC;
@ -3482,7 +3483,7 @@ void Application::setupUICallbacks() {
voiceType = entitySpawner_->detectVoiceTypeFromDisplayId(displayId);
}
renderer->getNpcVoiceManager()->playAggro(guid, voiceType, renderPos);
audioCoordinator_->getNpcVoiceManager()->playAggro(guid, voiceType, renderPos);
}
});
@ -3718,7 +3719,7 @@ void Application::spawnPlayerCharacter() {
playerCharacterSpawned = true;
// Set voice profile to match character race/gender
if (auto* asm_ = renderer->getActivitySoundManager()) {
if (auto* asm_ = audioCoordinator_ ? audioCoordinator_->getActivitySoundManager() : nullptr) {
const char* raceFolder = "Human";
const char* raceBase = "Human";
switch (playerRace_) {