载入中...
搜索中...
未找到
Resource.cpp
浏览该文件的文档.
1#include "common/Resource.h"
2#include "common/Capability.h"
3
4#include <mutex>
5
6namespace eve {
7
9 // Intentionally leaked: cached CPU resources may own third-party handles
10 // (FreeType faces, Assimp scenes, image decode handlers) whose libraries
11 // are torn down at process exit in an unspecified TU order. Destroying
12 // cached entries from the singleton destructor can therefore crash at
13 // exit. Keeping the singleton alive until the OS reclaims it avoids
14 // exit-time destructors entirely; explicit unload()/clear() still release
15 // entries during the run.
16 static ResourceManager* instance = new ResourceManager();
17 instance->ensureRegistered();
18 return *instance;
19}
20
21std::string ResourceManager::normalizePath(std::string path) {
22 for (char &c : path) {
23 if (c == '\\') c = '/';
24 }
25 while (path.size() >= 2 && path[0] == '.' && path[1] == '/') path.erase(0, 2);
26 while (path.size() > 1 && path.back() == '/') path.pop_back();
27 return path;
28}
29
30std::string ResourceManager::makeKey(const std::string &path, const std::string &query) {
31 std::string key = normalizePath(path);
32 if (!query.empty()) {
33 key += '?';
34 key += query;
35 }
36 return key;
37}
38
39std::string ResourceManager::pathOfKey(const std::string &key) {
40 const auto q = key.find('?');
41 return normalizePath(q == std::string::npos ? key : key.substr(0, q));
42}
43
45 std::lock_guard<std::mutex> lock(mu_);
46 if (registered_) return;
48 registered_ = true;
49}
50
51size_t ResourceManager::count() const {
52 std::lock_guard<std::mutex> lock(mu_);
53 return resources.size();
54}
55
56Resource *ResourceManager::get(std::string key) {
57 const std::string norm = makeKey(std::move(key));
58 if (norm.empty()) return nullptr;
59
60 {
61 std::lock_guard<std::mutex> lock(mu_);
62 auto it = resources.find(norm);
63 if (it != resources.end()) return it->second.get();
64 }
65
66 // The provider load (file read + decode) is the expensive part; run it
67 // outside the lock so concurrent insertions are not serialized behind it.
68 Resource *loaded = nullptr;
70 if (r == this) return false; // the cache itself never loads
71 if (!r->handlesPath(norm)) return false;
72 loaded = r->load(norm);
73 return loaded != nullptr;
74 });
75
76 if (loaded == nullptr) return nullptr;
77 loaded->setUri(norm);
78
79 std::lock_guard<std::mutex> lock(mu_);
80 auto [it, inserted] = resources.emplace(norm, loaded);
81 if (!inserted) {
82 // A concurrent get() may have won the race; emplace does not consume
83 // the arguments when the key already exists, so discard our instance.
84 delete loaded;
85 }
86 return it->second.get();
87}
88
89void ResourceManager::unload(std::string key) {
90 std::lock_guard<std::mutex> lock(mu_);
91 resources.erase(makeKey(std::move(key)));
92}
93
94void ResourceManager::unloadPath(const std::string &path) {
95 const std::string norm = normalizePath(path);
96 std::lock_guard<std::mutex> lock(mu_);
97 for (auto it = resources.begin(); it != resources.end();) {
98 if (pathOfKey(it->first) == norm)
99 it = resources.erase(it);
100 else
101 ++it;
102 }
103}
104
106 {
107 std::lock_guard<std::mutex> lock(mu_);
108 resources.clear();
109 }
110 if (registered_) {
112 registered_ = false;
113 }
114}
115
116bool ResourceManager::handlesPath(const std::string &normPath) const {
117 const std::string norm = normalizePath(normPath);
118 if (norm.empty()) return false;
119 std::lock_guard<std::mutex> lock(mu_);
120 for (const auto &kv : resources) {
121 if (pathOfKey(kv.first) == norm) return true;
122 }
123 return false;
124}
125
126bool ResourceManager::reload(const std::string &normPath) {
127 const std::string norm = normalizePath(normPath);
128 if (norm.empty()) return false;
129
130 std::vector<std::string> keys;
131 {
132 std::lock_guard<std::mutex> lock(mu_);
133 for (const auto &kv : resources) {
134 if (pathOfKey(kv.first) == norm) keys.push_back(kv.first);
135 }
136 }
137
138 std::set<std::string> visited;
139 bool any = false;
140 for (const auto &key : keys) {
141 if (refreshEntry(key, visited)) any = true;
142 }
143 return any;
144}
145
146bool ResourceManager::refreshEntry(const std::string &key, std::set<std::string> &visited) {
147 if (!visited.insert(key).second) return false; // cycle guard
148
149 Resource *cached = nullptr;
150 {
151 std::lock_guard<std::mutex> lock(mu_);
152 auto it = resources.find(key);
153 if (it == resources.end()) return false;
154 cached = it->second.get(); // identity token; the cache entry keeps it alive
155 }
156
157 Resource *replacement = nullptr;
159 if (r == this) return false;
160 if (!r->handlesPath(key)) return false;
161 try {
162 replacement = r->load(key);
163 } catch (...) {
164 replacement = nullptr; // keep the previous contents on a failed reload
165 }
166 return replacement != nullptr;
167 });
168 if (replacement == nullptr) return false;
169
170 {
171 std::lock_guard<std::mutex> lock(mu_);
172 auto it = resources.find(key);
173 if (it == resources.end()) {
174 delete replacement; // entry unloaded while we were loading
175 return false;
176 }
177 it->second->adopt(*replacement);
178 }
179 delete replacement;
180
181 refreshDependents(cached, visited);
182 return true;
183}
184
185void ResourceManager::refreshDependents(Resource *updated, std::set<std::string> &visited) {
186 std::vector<std::string> dependents;
187 {
188 std::lock_guard<std::mutex> lock(mu_);
189 for (auto &kv : resources) {
190 if (visited.count(kv.first)) continue;
191 for (auto dep : kv.second->getDependencies()) { // copy: operator-> is non-const
192 if (dep.get() == updated) {
193 dependents.push_back(kv.first);
194 break;
195 }
196 }
197 }
198 }
199 for (const auto &key : dependents) refreshEntry(key, visited);
200}
201
202} // namespace eve
std::vector< JobImpl * > dependents
uint32_t c
ResourceManager is a singleton that manages all resources in the game. It provides a way to load,...
Definition Resource.h:87
ResourceManager()=default
void unloadPath(const std::string &path)
Drop every cache entry whose path matches, whatever its parameters.
Definition Resource.cpp:94
bool handlesPath(const std::string &normPath) const override
Definition Resource.cpp:116
void unload(std::string key)
Drop the exact cache entry key (parameters included). The resource stays alive while other holders st...
Definition Resource.cpp:89
Resource * get(std::string key)
Get the cached resource for key; on a miss, load it through the registered IAssetReloader providers a...
Definition Resource.cpp:56
std::map< std::string, ref< Resource > > resources
Definition Resource.h:141
bool reload(const std::string &normPath) override
Definition Resource.cpp:126
static std::string pathOfKey(const std::string &key)
The path part of a cache key (everything before the first '?').
Definition Resource.cpp:39
bool refreshEntry(const std::string &key, std::set< std::string > &visited)
Definition Resource.cpp:146
static std::string normalizePath(std::string path)
Normalize a VFS path: backslashes to '/', strip leading "./" and trailing '/'.
Definition Resource.cpp:21
void clear()
Drop every entry and re-arm lazy registration (tests / teardown).
Definition Resource.cpp:105
static std::string makeKey(const std::string &path, const std::string &query="")
Build a cache key from a path and optional ?query parameters.
Definition Resource.cpp:30
size_t count() const
Number of cached entries.
Definition Resource.cpp:51
void refreshDependents(Resource *updated, std::set< std::string > &visited)
Definition Resource.cpp:185
static ResourceManager & getInstance()
Definition Resource.cpp:8
Resource is a game object that is managed by the ResourceManager. It can be loaded from a file or gen...
Definition Resource.h:35
virtual void adopt(eve::Resource &replacement)=0
Replace this instance's contents with replacement's. The ResourceManager keeps instance identity stab...
void setUri(std::string value)
Set the resource URI (the cache key). Used by ResourceManager.
Definition Resource.h:58
virtual bool handlesPath(const std::string &normPath) const =0
virtual Resource * load(const std::string &key)
I * query()
Definition Capability.h:77
Definition Build.cpp:11