mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-03 20:03:50 +00:00
refactor: decouple Application singleton by extracting core subsystems and updating interfaces
- Add `audio::AudioCoordinator` interface and implementation - Modify `Application` to reduce singleton usage and move controller responsibilities: - application.hpp - application.cpp - Update UI and audio headers/sources: - game_screen.hpp - game_screen.cpp - ui_manager.hpp - audio_coordinator.hpp - audio_coordinator.cpp - Project config touched: - CMakeLists.txt
This commit is contained in:
parent
9b38e64f84
commit
d43397163e
8 changed files with 179 additions and 3 deletions
|
|
@ -544,6 +544,7 @@ set(WOWEE_SOURCES
|
||||||
|
|
||||||
# Audio
|
# Audio
|
||||||
src/audio/audio_engine.cpp
|
src/audio/audio_engine.cpp
|
||||||
|
src/audio/audio_coordinator.cpp
|
||||||
src/audio/music_manager.cpp
|
src/audio/music_manager.cpp
|
||||||
src/audio/footstep_manager.cpp
|
src/audio/footstep_manager.cpp
|
||||||
src/audio/activity_sound_manager.cpp
|
src/audio/activity_sound_manager.cpp
|
||||||
|
|
|
||||||
66
include/audio/audio_coordinator.hpp
Normal file
66
include/audio/audio_coordinator.hpp
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace wowee {
|
||||||
|
namespace pipeline { class AssetManager; }
|
||||||
|
namespace audio {
|
||||||
|
|
||||||
|
class MusicManager;
|
||||||
|
class FootstepManager;
|
||||||
|
class ActivitySoundManager;
|
||||||
|
class MountSoundManager;
|
||||||
|
class NpcVoiceManager;
|
||||||
|
class AmbientSoundManager;
|
||||||
|
class UiSoundManager;
|
||||||
|
class CombatSoundManager;
|
||||||
|
class SpellSoundManager;
|
||||||
|
class MovementSoundManager;
|
||||||
|
|
||||||
|
/// Coordinates all audio subsystems.
|
||||||
|
/// Extracted from Renderer to separate audio lifecycle from rendering.
|
||||||
|
/// Owned by Application; Renderer and UI components access through Application.
|
||||||
|
class AudioCoordinator {
|
||||||
|
public:
|
||||||
|
AudioCoordinator();
|
||||||
|
~AudioCoordinator();
|
||||||
|
|
||||||
|
/// Initialize the audio engine and all managers.
|
||||||
|
/// @return true if audio is available (engine initialized successfully)
|
||||||
|
bool initialize();
|
||||||
|
|
||||||
|
/// Initialize managers that need AssetManager (music lookups, sound banks).
|
||||||
|
void initializeWithAssets(pipeline::AssetManager* assetManager);
|
||||||
|
|
||||||
|
/// Shutdown all audio managers and engine.
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
// Accessors for all audio managers (same interface as Renderer had)
|
||||||
|
MusicManager* getMusicManager() { return musicManager_.get(); }
|
||||||
|
FootstepManager* getFootstepManager() { return footstepManager_.get(); }
|
||||||
|
ActivitySoundManager* getActivitySoundManager() { return activitySoundManager_.get(); }
|
||||||
|
MountSoundManager* getMountSoundManager() { return mountSoundManager_.get(); }
|
||||||
|
NpcVoiceManager* getNpcVoiceManager() { return npcVoiceManager_.get(); }
|
||||||
|
AmbientSoundManager* getAmbientSoundManager() { return ambientSoundManager_.get(); }
|
||||||
|
UiSoundManager* getUiSoundManager() { return uiSoundManager_.get(); }
|
||||||
|
CombatSoundManager* getCombatSoundManager() { return combatSoundManager_.get(); }
|
||||||
|
SpellSoundManager* getSpellSoundManager() { return spellSoundManager_.get(); }
|
||||||
|
MovementSoundManager* getMovementSoundManager() { return movementSoundManager_.get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<MusicManager> musicManager_;
|
||||||
|
std::unique_ptr<FootstepManager> footstepManager_;
|
||||||
|
std::unique_ptr<ActivitySoundManager> activitySoundManager_;
|
||||||
|
std::unique_ptr<MountSoundManager> mountSoundManager_;
|
||||||
|
std::unique_ptr<NpcVoiceManager> npcVoiceManager_;
|
||||||
|
std::unique_ptr<AmbientSoundManager> ambientSoundManager_;
|
||||||
|
std::unique_ptr<UiSoundManager> uiSoundManager_;
|
||||||
|
std::unique_ptr<CombatSoundManager> combatSoundManager_;
|
||||||
|
std::unique_ptr<SpellSoundManager> spellSoundManager_;
|
||||||
|
std::unique_ptr<MovementSoundManager> movementSoundManager_;
|
||||||
|
|
||||||
|
bool audioAvailable_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace wowee
|
||||||
|
|
@ -29,7 +29,7 @@ namespace ui { class UIManager; }
|
||||||
namespace auth { class AuthHandler; }
|
namespace auth { class AuthHandler; }
|
||||||
namespace game { class GameHandler; class World; class ExpansionRegistry; }
|
namespace game { class GameHandler; class World; class ExpansionRegistry; }
|
||||||
namespace pipeline { class AssetManager; class DBCLayout; struct M2Model; struct WMOModel; }
|
namespace pipeline { class AssetManager; class DBCLayout; struct M2Model; struct WMOModel; }
|
||||||
namespace audio { enum class VoiceType; }
|
namespace audio { enum class VoiceType; class AudioCoordinator; }
|
||||||
namespace addons { class AddonManager; }
|
namespace addons { class AddonManager; }
|
||||||
|
|
||||||
namespace core {
|
namespace core {
|
||||||
|
|
@ -104,6 +104,9 @@ public:
|
||||||
// World loader access
|
// World loader access
|
||||||
WorldLoader* getWorldLoader() { return worldLoader_.get(); }
|
WorldLoader* getWorldLoader() { return worldLoader_.get(); }
|
||||||
|
|
||||||
|
// Audio coordinator access (Section 4.1: extracted audio subsystem)
|
||||||
|
audio::AudioCoordinator* getAudioCoordinator() { return audioCoordinator_.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
void render();
|
void render();
|
||||||
|
|
@ -129,6 +132,7 @@ private:
|
||||||
std::unique_ptr<EntitySpawner> entitySpawner_;
|
std::unique_ptr<EntitySpawner> entitySpawner_;
|
||||||
std::unique_ptr<AppearanceComposer> appearanceComposer_;
|
std::unique_ptr<AppearanceComposer> appearanceComposer_;
|
||||||
std::unique_ptr<WorldLoader> worldLoader_;
|
std::unique_ptr<WorldLoader> worldLoader_;
|
||||||
|
std::unique_ptr<audio::AudioCoordinator> audioCoordinator_;
|
||||||
|
|
||||||
AppState state = AppState::AUTHENTICATION;
|
AppState state = AppState::AUTHENTICATION;
|
||||||
bool running = false;
|
bool running = false;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace wowee {
|
namespace wowee {
|
||||||
|
namespace core { class AppearanceComposer; }
|
||||||
namespace pipeline { class AssetManager; }
|
namespace pipeline { class AssetManager; }
|
||||||
namespace rendering { class Renderer; }
|
namespace rendering { class Renderer; }
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
@ -50,7 +51,12 @@ public:
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
|
|
||||||
|
// Dependency injection for extracted classes (Phase A singleton breaking)
|
||||||
|
void setAppearanceComposer(core::AppearanceComposer* ac) { appearanceComposer_ = ac; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Injected dependencies (replaces getInstance() calls)
|
||||||
|
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_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ union SDL_Event;
|
||||||
namespace wowee {
|
namespace wowee {
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace core { class Window; enum class AppState; }
|
namespace core { class Window; class AppearanceComposer; enum class AppState; }
|
||||||
namespace auth { class AuthHandler; }
|
namespace auth { class AuthHandler; }
|
||||||
namespace game { class GameHandler; }
|
namespace game { class GameHandler; }
|
||||||
|
|
||||||
|
|
@ -69,6 +69,11 @@ public:
|
||||||
CharacterScreen& getCharacterScreen() { return *characterScreen; }
|
CharacterScreen& getCharacterScreen() { return *characterScreen; }
|
||||||
GameScreen& getGameScreen() { return *gameScreen; }
|
GameScreen& getGameScreen() { return *gameScreen; }
|
||||||
|
|
||||||
|
// Dependency injection forwarding (Phase A singleton breaking)
|
||||||
|
void setAppearanceComposer(core::AppearanceComposer* ac) {
|
||||||
|
if (gameScreen) gameScreen->setAppearanceComposer(ac);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::Window* window = nullptr;
|
core::Window* window = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
87
src/audio/audio_coordinator.cpp
Normal file
87
src/audio/audio_coordinator.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include "audio/audio_coordinator.hpp"
|
||||||
|
#include "audio/audio_engine.hpp"
|
||||||
|
#include "audio/music_manager.hpp"
|
||||||
|
#include "audio/footstep_manager.hpp"
|
||||||
|
#include "audio/activity_sound_manager.hpp"
|
||||||
|
#include "audio/mount_sound_manager.hpp"
|
||||||
|
#include "audio/npc_voice_manager.hpp"
|
||||||
|
#include "audio/ambient_sound_manager.hpp"
|
||||||
|
#include "audio/ui_sound_manager.hpp"
|
||||||
|
#include "audio/combat_sound_manager.hpp"
|
||||||
|
#include "audio/spell_sound_manager.hpp"
|
||||||
|
#include "audio/movement_sound_manager.hpp"
|
||||||
|
#include "pipeline/asset_manager.hpp"
|
||||||
|
#include "core/logger.hpp"
|
||||||
|
|
||||||
|
namespace wowee {
|
||||||
|
namespace audio {
|
||||||
|
|
||||||
|
AudioCoordinator::AudioCoordinator() = default;
|
||||||
|
|
||||||
|
AudioCoordinator::~AudioCoordinator() {
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioCoordinator::initialize() {
|
||||||
|
// Initialize AudioEngine (singleton)
|
||||||
|
if (!AudioEngine::instance().initialize()) {
|
||||||
|
LOG_WARNING("Failed to initialize AudioEngine - audio will be disabled");
|
||||||
|
audioAvailable_ = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
audioAvailable_ = true;
|
||||||
|
|
||||||
|
// Create all audio managers (initialized later with asset manager)
|
||||||
|
musicManager_ = std::make_unique<MusicManager>();
|
||||||
|
footstepManager_ = std::make_unique<FootstepManager>();
|
||||||
|
activitySoundManager_ = std::make_unique<ActivitySoundManager>();
|
||||||
|
mountSoundManager_ = std::make_unique<MountSoundManager>();
|
||||||
|
npcVoiceManager_ = std::make_unique<NpcVoiceManager>();
|
||||||
|
ambientSoundManager_ = std::make_unique<AmbientSoundManager>();
|
||||||
|
uiSoundManager_ = std::make_unique<UiSoundManager>();
|
||||||
|
combatSoundManager_ = std::make_unique<CombatSoundManager>();
|
||||||
|
spellSoundManager_ = std::make_unique<SpellSoundManager>();
|
||||||
|
movementSoundManager_ = std::make_unique<MovementSoundManager>();
|
||||||
|
|
||||||
|
LOG_INFO("AudioCoordinator initialized with ", 10, " audio managers");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCoordinator::initializeWithAssets(pipeline::AssetManager* assetManager) {
|
||||||
|
if (!audioAvailable_ || !assetManager) return;
|
||||||
|
|
||||||
|
// MusicManager needs asset manager for zone music lookups
|
||||||
|
if (musicManager_) {
|
||||||
|
musicManager_->initialize(assetManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other managers may need asset manager for sound bank loading
|
||||||
|
// (Add similar calls as needed for other managers)
|
||||||
|
|
||||||
|
LOG_INFO("AudioCoordinator initialized with asset manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCoordinator::shutdown() {
|
||||||
|
// Reset all managers first (they may reference AudioEngine)
|
||||||
|
movementSoundManager_.reset();
|
||||||
|
spellSoundManager_.reset();
|
||||||
|
combatSoundManager_.reset();
|
||||||
|
uiSoundManager_.reset();
|
||||||
|
ambientSoundManager_.reset();
|
||||||
|
npcVoiceManager_.reset();
|
||||||
|
mountSoundManager_.reset();
|
||||||
|
activitySoundManager_.reset();
|
||||||
|
footstepManager_.reset();
|
||||||
|
musicManager_.reset();
|
||||||
|
|
||||||
|
// Shutdown audio engine last
|
||||||
|
if (audioAvailable_) {
|
||||||
|
AudioEngine::instance().shutdown();
|
||||||
|
audioAvailable_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("AudioCoordinator shutdown complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace wowee
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "audio/footstep_manager.hpp"
|
#include "audio/footstep_manager.hpp"
|
||||||
#include "audio/activity_sound_manager.hpp"
|
#include "audio/activity_sound_manager.hpp"
|
||||||
#include "audio/audio_engine.hpp"
|
#include "audio/audio_engine.hpp"
|
||||||
|
#include "audio/audio_coordinator.hpp"
|
||||||
#include "addons/addon_manager.hpp"
|
#include "addons/addon_manager.hpp"
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include "pipeline/m2_loader.hpp"
|
#include "pipeline/m2_loader.hpp"
|
||||||
|
|
@ -223,6 +224,11 @@ bool Application::initialize() {
|
||||||
renderer.get(), assetManager.get(), gameHandler.get(),
|
renderer.get(), assetManager.get(), gameHandler.get(),
|
||||||
dbcLayout_.get(), entitySpawner_.get());
|
dbcLayout_.get(), entitySpawner_.get());
|
||||||
|
|
||||||
|
// Wire AppearanceComposer to UI components (Phase A singleton breaking)
|
||||||
|
if (uiManager) {
|
||||||
|
uiManager->setAppearanceComposer(appearanceComposer_.get());
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the main in-world CharacterRenderer can load textures immediately.
|
// Ensure the main in-world CharacterRenderer can load textures immediately.
|
||||||
// Previously this was only wired during terrain initialization, which meant early spawns
|
// Previously this was only wired during terrain initialization, which meant early spawns
|
||||||
// (before terrain load) would render with white fallback textures (notably hair).
|
// (before terrain load) would render with white fallback textures (notably hair).
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include "ui/ui_colors.hpp"
|
#include "ui/ui_colors.hpp"
|
||||||
#include "rendering/vk_context.hpp"
|
#include "rendering/vk_context.hpp"
|
||||||
#include "core/application.hpp"
|
#include "core/application.hpp"
|
||||||
|
#include "core/appearance_composer.hpp"
|
||||||
#include "addons/addon_manager.hpp"
|
#include "addons/addon_manager.hpp"
|
||||||
#include "core/coordinates.hpp"
|
#include "core/coordinates.hpp"
|
||||||
#include "core/input.hpp"
|
#include "core/input.hpp"
|
||||||
|
|
@ -631,7 +632,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
if (inventoryScreen.consumeEquipmentDirty() || gameHandler.consumeOnlineEquipmentDirty()) {
|
if (inventoryScreen.consumeEquipmentDirty() || gameHandler.consumeOnlineEquipmentDirty()) {
|
||||||
updateCharacterGeosets(gameHandler.getInventory());
|
updateCharacterGeosets(gameHandler.getInventory());
|
||||||
updateCharacterTextures(gameHandler.getInventory());
|
updateCharacterTextures(gameHandler.getInventory());
|
||||||
if (auto* ac = core::Application::getInstance().getAppearanceComposer()) ac->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 = core::Application::getInstance().getRenderer();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue