载入中...
搜索中...
未找到
AnimClipRegistry.cpp
浏览该文件的文档.
2
6
8#include "common/Capability.h"
9
10#include <algorithm>
11#include <cctype>
12#include <map>
13#include <utility>
14
15namespace eve::animation {
16namespace {
17
18using EntryMap = std::map<std::string, std::vector<AnimClip*>>;
19
20EntryMap& entries() {
21 static EntryMap map;
22 return map;
23}
24
27 return observer;
28}
29
30std::uint64_t& reloadCallbackFailures() {
31 static std::uint64_t failures = 0;
32 return failures;
33}
34
35void notifyReload(AnimClipRegistry::ReloadEvent event) {
36 static_cast<void>(reloadObservers().notifyChecked([]() noexcept { ++reloadCallbackFailures(); }, event));
37}
38
39bool isAnimationFixtureTextPath(const std::string& path) {
40 constexpr std::string_view suffix = ".anim.txt";
41 if (path.size() < suffix.size()) return false;
42 std::string ext = path.substr(path.size() - suffix.size());
43 for (char& c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
44 return ext == suffix;
45}
46
48class AnimClipReloader : public eve::caps::IAssetReloader {
49public:
50 const char* reloadKind() const override { return "animclip"; }
51
52 bool handlesPath(const std::string& normPath) const override {
53 return isAnimationFixtureTextPath(AnimClipRegistry::normalizePath(normPath));
54 }
55
56 eve::Result<bool> reload(const std::string& normPath) override {
57 auto result = AnimClipRegistry::reloadPath(normPath);
58 if (!result) return eve::Result<bool>::failure(result.status());
59 return eve::Result<bool>::success(std::move(result).takeValue() > 0);
60 }
61};
62
63struct Register {
64 Register() {
65 static AnimClipReloader reloader;
66 eve::cap::addListener<eve::caps::IAssetReloader>(&reloader, eve::caps::IAssetReloader::kConsumer);
67 }
68} g_register;
69
70} // namespace
71
72std::string AnimClipRegistry::normalizePath(const std::string& path) {
73 std::string out = path;
74 for (char& c : out)
75 if (c == '\\') c = '/';
76 return out;
77}
78
80 if (!clip) return;
81 std::vector<AnimClip*>& list = entries()[normalizePath(path)];
82 if (std::find(list.begin(), list.end(), clip) == list.end()) list.push_back(clip);
83}
84
86 if (!clip) return;
87 for (auto it = entries().begin(); it != entries().end();) {
88 std::vector<AnimClip*>& list = it->second;
89 list.erase(std::remove(list.begin(), list.end(), clip), list.end());
90 if (list.empty())
91 it = entries().erase(it);
92 else
93 ++it;
94 }
95}
96
97std::vector<AnimClip*> AnimClipRegistry::findByPath(const std::string& path) {
98 const auto it = entries().find(normalizePath(path));
99 return it == entries().end() ? std::vector<AnimClip*>() : it->second;
100}
101
102bool AnimClipRegistry::hasPath(const std::string& path) { return entries().count(normalizePath(path)) > 0; }
103
105 const std::string norm = normalizePath(path);
106 const auto it = entries().find(norm);
107 if (it == entries().end() || it->second.empty()) {
108 notifyReload({norm, 0, false});
110 }
111
112 AnimSkeleton* skeleton = nullptr;
113 AnimClip* fresh = nullptr;
114 try {
115 AnimImporter::importAnimationFixtureTextFile(norm, &skeleton, &fresh);
116 } catch (...) {
117 delete skeleton;
118 delete fresh;
119 notifyReload({norm, 0, false});
121 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "animation clip reload import failed", norm));
122 }
123 if (!fresh) {
124 delete skeleton;
125 notifyReload({norm, 0, false});
127 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "animation clip reload produced no clip", norm));
128 }
129 for (AnimClip* clip : it->second) clip->adopt(*fresh);
130 const int refreshed = static_cast<int>(it->second.size());
131 delete fresh;
132 delete skeleton;
133 notifyReload({norm, refreshed, true});
135}
136
138 return reloadObservers().subscribe(std::move(callback));
139}
140
141std::uint64_t AnimClipRegistry::reloadCallbackFailureCount() { return reloadCallbackFailures(); }
142
144 int n = 0;
145 for (const auto& kv : entries()) n += static_cast<int>(kv.second.size());
146 return n;
147}
148
149void AnimClipRegistry::clear() { entries().clear(); }
150
151} // namespace eve::animation
int observer
Definition AnimSmr.cpp:162
std::unordered_map< std::string, QuestRuntime > entries
glm::vec4 clip
glm::vec3 n
Definition Grass.cpp:63
std::int32_t c
std::string path
Definition PlayHost.cpp:110
float begin
ViewPreparation callback
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
Thread-affine callback registry with mutation-safe dispatch.
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
Move-only RAII token that owns one observer registration.
static eve::Subscription subscribeReload(ReloadCallback callback)
Subscribe to reload attempts; token disposal is owner-thread-affine.
static std::string normalizePath(const std::string &path)
Normalize a path to the registry key form.
std::function< void(const ReloadEvent &)> ReloadCallback
static std::uint64_t reloadCallbackFailureCount()
Number of reload listener exceptions contained so far.
static void unregister(AnimClip *clip)
Forget a clip everywhere (called from ~AnimClip).
static void registerPath(const std::string &path, AnimClip *clip)
Track a clip under a source path (keys are normalized).
static int count()
Total registered clips (tests).
static eve::Result< int > reloadPath(const std::string &path)
Reload a path and report a structured import failure.
static bool hasPath(const std::string &path)
Whether any clip is registered under this path.
static void clear()
Drop all entries (tests).
static std::vector< AnimClip * > findByPath(const std::string &path)
Clips registered under a path; may be empty.
Keyframed skeletal animation clip (local TRS tracks per bone). Script type: AnimClip.
Definition AnimClip.h:145
static void importAnimationFixtureTextFile(const std::string &path, AnimSkeleton **skeletonOut, AnimClip **clipOut)
Load from an *.anim.txt fixture path.
3D bone hierarchy + bind-pose local TRS for skeletal animation. Independent of ik::Skeleton3D (FABRIK...
EVENGINE_API_FOUNDATION public API.