2026-02-03 19:49:56 -08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "audio/footstep_manager.hpp"
|
2026-02-03 22:24:17 -08:00
|
|
|
#include "platform/process.hpp"
|
2026-02-03 19:49:56 -08:00
|
|
|
#include <array>
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <random>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
namespace wowee {
|
|
|
|
|
namespace pipeline { class AssetManager; }
|
|
|
|
|
namespace audio {
|
|
|
|
|
|
|
|
|
|
class ActivitySoundManager {
|
|
|
|
|
public:
|
|
|
|
|
ActivitySoundManager();
|
|
|
|
|
~ActivitySoundManager();
|
|
|
|
|
|
|
|
|
|
bool initialize(pipeline::AssetManager* assets);
|
|
|
|
|
void shutdown();
|
|
|
|
|
void update(float deltaTime);
|
|
|
|
|
bool isInitialized() const { return initialized; }
|
|
|
|
|
|
|
|
|
|
void playJump();
|
|
|
|
|
void playLanding(FootstepSurface surface, bool hardLanding);
|
|
|
|
|
void setSwimmingState(bool swimming, bool moving);
|
|
|
|
|
void setCharacterVoiceProfile(const std::string& modelName);
|
|
|
|
|
void playWaterEnter();
|
|
|
|
|
void playWaterExit();
|
2026-02-05 14:01:26 -08:00
|
|
|
void playMeleeSwing();
|
2026-02-19 21:31:37 -08:00
|
|
|
void playAttackGrunt();
|
|
|
|
|
void playWound(bool isCrit = false);
|
|
|
|
|
void playDeath();
|
2026-02-05 17:32:21 -08:00
|
|
|
void setVolumeScale(float scale) { volumeScale = scale; }
|
|
|
|
|
float getVolumeScale() const { return volumeScale; }
|
2026-02-03 19:49:56 -08:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct Sample {
|
|
|
|
|
std::string path;
|
|
|
|
|
std::vector<uint8_t> data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct SurfaceLandingSet {
|
|
|
|
|
std::vector<Sample> clips;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool initialized = false;
|
|
|
|
|
pipeline::AssetManager* assetManager = nullptr;
|
|
|
|
|
|
|
|
|
|
std::vector<Sample> jumpClips;
|
|
|
|
|
std::vector<Sample> splashEnterClips;
|
|
|
|
|
std::vector<Sample> splashExitClips;
|
|
|
|
|
std::vector<Sample> swimLoopClips;
|
|
|
|
|
std::vector<Sample> hardLandClips;
|
2026-02-05 14:01:26 -08:00
|
|
|
std::vector<Sample> meleeSwingClips;
|
2026-02-19 21:31:37 -08:00
|
|
|
std::vector<Sample> attackGruntClips;
|
|
|
|
|
std::vector<Sample> woundClips;
|
|
|
|
|
std::vector<Sample> woundCritClips;
|
|
|
|
|
std::vector<Sample> deathClips;
|
2026-02-03 19:49:56 -08:00
|
|
|
std::array<SurfaceLandingSet, 7> landingSets;
|
|
|
|
|
|
|
|
|
|
bool swimmingActive = false;
|
|
|
|
|
bool swimMoving = false;
|
2026-02-03 22:24:17 -08:00
|
|
|
ProcessHandle swimLoopPid = INVALID_PROCESS;
|
|
|
|
|
ProcessHandle oneShotPid = INVALID_PROCESS;
|
|
|
|
|
std::string loopTempPath = platform::getTempFilePath("wowee_swim_loop.wav");
|
|
|
|
|
std::string oneShotTempPath = platform::getTempFilePath("wowee_activity.wav");
|
2026-02-03 19:49:56 -08:00
|
|
|
std::mt19937 rng;
|
|
|
|
|
|
|
|
|
|
std::chrono::steady_clock::time_point lastJumpAt{};
|
|
|
|
|
std::chrono::steady_clock::time_point lastLandAt{};
|
|
|
|
|
std::chrono::steady_clock::time_point lastSplashAt{};
|
2026-02-05 14:01:26 -08:00
|
|
|
std::chrono::steady_clock::time_point lastMeleeSwingAt{};
|
2026-02-19 21:31:37 -08:00
|
|
|
std::chrono::steady_clock::time_point lastAttackGruntAt{};
|
|
|
|
|
std::chrono::steady_clock::time_point lastWoundAt{};
|
2026-02-09 14:50:14 -08:00
|
|
|
std::chrono::steady_clock::time_point lastSwimStrokeAt{};
|
2026-02-05 14:01:26 -08:00
|
|
|
bool meleeSwingWarned = false;
|
2026-02-03 19:49:56 -08:00
|
|
|
std::string voiceProfileKey;
|
2026-02-05 17:32:21 -08:00
|
|
|
float volumeScale = 1.0f;
|
2026-02-03 19:49:56 -08:00
|
|
|
|
|
|
|
|
void preloadCandidates(std::vector<Sample>& out, const std::vector<std::string>& candidates);
|
|
|
|
|
void preloadLandingSet(FootstepSurface surface, const std::string& material);
|
|
|
|
|
void rebuildJumpClipsForProfile(const std::string& raceFolder, const std::string& raceBase, bool male);
|
|
|
|
|
void rebuildSwimLoopClipsForProfile(const std::string& raceFolder, const std::string& raceBase, bool male);
|
|
|
|
|
void rebuildHardLandClipsForProfile(const std::string& raceFolder, const std::string& raceBase, bool male);
|
2026-02-19 21:31:37 -08:00
|
|
|
void rebuildCombatVocalClipsForProfile(const std::string& raceFolder, const std::string& raceBase, bool male);
|
2026-02-03 19:49:56 -08:00
|
|
|
bool playOneShot(const std::vector<Sample>& clips, float volume, float pitchLo, float pitchHi);
|
|
|
|
|
void startSwimLoop();
|
|
|
|
|
void stopSwimLoop();
|
|
|
|
|
void stopOneShot();
|
|
|
|
|
void reapProcesses();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace audio
|
|
|
|
|
} // namespace wowee
|