载入中...
搜索中...
未找到
AudioAttackVfx.cpp
浏览该文件的文档.
1#include "common/Capability.h"
3
4#if defined(EVE_STYLIZE_ACTION_AUDIO)
5#include "audio/Audio.h"
6#include "audio/Source.h"
7#include "common/Module.h"
8#include "common/Resource.h"
9#include "sound/Sound.h"
10#include "sound/SoundData.h"
11
12#include <cstdint>
13#include <exception>
14#include <memory>
15#include <string>
16#include <unordered_map>
17#include <utility>
18#endif
19
20namespace eve::stylize_action {
21
22#if defined(EVE_STYLIZE_ACTION_AUDIO)
23namespace {
24
25float layerParam(const eve::stylize::AttackVfxLayerStartRequest& request, const char* key,
26 float fallback) {
27 if (request.layer) {
28 const auto found = request.layer->floatParams.find(key);
29 if (found != request.layer->floatParams.end()) return found->second;
30 }
31 return fallback;
32}
33
34class AudioAttackVfxExecutor final : public eve::stylize::IAttackVfxLayerExecutor {
35public:
36 eve::stylize::AttackVfxLayerRole role() const noexcept override {
38 }
39
42 if (!request.layer)
44 eve::DiagnosticCode::InvalidArgument, "AttackVfx audio layer is null", "layer"));
45 if (request.layer->uri.empty())
47 eve::DiagnosticCode::InvalidArgument, "AttackVfx audio layer uri is empty", "uri"));
48
49 auto* audio = eve::ModuleManager::getInstance<eve::audio::Audio>("Audio");
50 auto* sound = eve::ModuleManager::getInstance<eve::sound::Sound>("Sound");
51 if (!audio || !sound)
53 eve::DiagnosticCode::NotFound, "Audio/Sound modules are unavailable", "audio"));
54
55 try {
56 auto* data = sound->newSoundDataFromFile(request.layer->uri);
57 auto pin = eve::ResourceManager::getInstance().pin(data);
58 if (!pin.ok())
60 eve::DiagnosticCode::NotFound, "audio resource is no longer cached", "uri"));
61 eve::ResourcePin keepAlive = std::move(pin).takeValue();
62 auto* live = static_cast<eve::sound::SoundData*>(keepAlive.get());
63 std::unique_ptr<eve::audio::Source> source(audio->newSource(live));
64 if (!source)
66 eve::DiagnosticCode::Failed, "audio Source could not be created", "uri"));
67
68 const float volume = layerParam(request, "volume", 1.f);
69 const float pitch = layerParam(request, "pitch", 1.f);
70 source->setVolume(volume);
71 source->setPitch(pitch);
72 source->setLooping(layerParam(request, "looping", 0.f) > 0.5f);
73 source->setRelative(true);
74 // Placement uses authored floatParams; entity ids are not world coordinates.
75 const float x = layerParam(request, "x", 0.f);
76 const float y = layerParam(request, "y", 0.f);
77 const float z = layerParam(request, "z", 0.f);
78 source->setPosition(x, y, z);
79 source->play();
80
81 Live owned;
82 owned.pin = std::move(keepAlive);
83 owned.source = std::move(source);
84 const auto id = ++nextId_;
85 live_.emplace(id, std::move(owned));
88 } catch (const std::exception& error) {
90 eve::DiagnosticCode::NotFound, error.what(), "uri"));
91 }
92 }
93
96 const auto found = live_.find(handle.id);
97 if (found == live_.end())
99 eve::DiagnosticCode::StaleHandle, "audio AttackVfx layer handle is stale", "handle"));
100 if (found->second.draining) {
101 const bool playing = found->second.source && found->second.source->isPlaying();
102 if (!playing) {
103 live_.erase(found);
105 }
106 }
108 }
109
111 eve::stylize::AttackVfxStopBehavior behavior) override {
112 const auto found = live_.find(handle.id);
113 if (found == live_.end())
115 eve::DiagnosticCode::StaleHandle, "audio AttackVfx layer handle is stale", "handle"));
117 if (found->second.source) {
118 found->second.source->stop();
119 found->second.source->seek(0.0);
120 }
121 live_.erase(found);
123 }
124 // StopEmitting: do not cut the oneshot; let playback finish via update().
125 found->second.draining = true;
126 if (found->second.source && found->second.source->isLooping())
127 found->second.source->setLooping(false);
129 }
130
131private:
132 struct Live {
134 std::unique_ptr<eve::audio::Source> source;
135 bool draining = false;
136 };
137
138 std::uint64_t nextId_ = 1;
139 std::unordered_map<std::uint64_t, Live> live_;
140};
141
142AudioAttackVfxExecutor& audioExecutor() {
143 static AudioAttackVfxExecutor instance;
144 return instance;
145}
146
147bool gAudioRegistered = false;
148
149} // namespace
150
152 if (gAudioRegistered) return;
153 eve::cap::addListener<eve::stylize::IAttackVfxLayerExecutor>(&audioExecutor());
154 gAudioRegistered = true;
155}
156
158 if (!gAudioRegistered) return;
159 eve::cap::removeListener<eve::stylize::IAttackVfxLayerExecutor>(&audioExecutor());
160 gAudioRegistered = false;
161}
162
163#else
164
167
168#endif
169
170} // namespace eve::stylize_action
Duration start
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
Pluggable AttackVfx layer backends registered via capability listeners.
OwnedAudio audio
ActiveSource owned
double volume
bool draining
const GltfImportRequest & request
std::uint32_t key
std::string error
Definition Package.cpp:60
PrimitiveHandle handle
bool found
const UnitySourceAsset & source
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
eve::Result< ResourcePin > pin(Resource *resource)
Keeps one cached resource alive across unload()/clear()/reload.
Definition Resource.cpp:311
static ResourceManager & getInstance()
Returns the instance.
Definition Resource.cpp:15
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
RAII keep-alive for one RuntimeObjectRegistry entry.
T * get() const noexcept
Borrows the pinned object; valid until the pin is released.
Raw PCM audio buffer with format metadata (samples/rate/bit depth/channels).
Definition SoundData.h:15
Optional open backend for one AttackVfxLayerRole.
void unregisterAudioAttackVfxExecutor()
AttackVfxLayerRole
Which existing presentation backend a layer binds to.
AttackVfxStopBehavior
Exit policy when a phase or instance stops.
Opaque executor-owned layer instance identity.
Borrowed start context for one layer inside an entering phase.