Unravel Engine C++ Reference
Loading...
Searching...
No Matches
asset_manager.h
Go to the documentation of this file.
1#pragma once
2#include <engine/engine_export.h>
3
4#include "asset_flags.h"
5#include "asset_storage.h"
6#include <cassert>
7#include <map>
8#include <mutex>
9#include <unordered_map>
10
11namespace unravel
12{
13
19{
20public:
26
31
36 void set_parent(asset_manager* parent);
37
43 auto init(rtti::context& ctx) -> bool;
44
50 auto deinit(rtti::context& ctx) -> bool;
51
55 void unload_all();
56
61 void unload_group(const std::string& group);
62
68 auto load_database(const std::string& protocol) -> bool;
69
75 void save_database(const std::string& protocol, const fs::path& path);
76
81 void remove_asset_info_for_path(const fs::path& path);
82
87 void remove_asset_info_for_key(const std::string& key);
88
89
90 void register_asset_info_for_path(const fs::path& path, bool override);
97 auto add_asset_info_for_path(const fs::path& path, const asset_meta& meta, bool override) -> hpp::uuid;
98
105 auto add_asset_info_for_key(const std::string& key, const asset_meta& meta, bool override) -> hpp::uuid;
106
112 auto get_metadata(const hpp::uuid& uid) const -> asset_database::meta;
113 auto get_metadata_for_path(const fs::path& path) const -> asset_database::meta;
114 auto get_metadata_for_key(const std::string& key) const -> asset_database::meta;
115 auto generate_metadata(const fs::path& p) const -> asset_meta;
116
123 template<typename HeaderT>
124 auto get_header(const hpp::uuid& uid) const -> std::shared_ptr<HeaderT>
125 {
126 auto meta = get_metadata(uid);
127 if(meta.meta.header && meta.meta.header->is<HeaderT>())
128 {
129 return std::static_pointer_cast<HeaderT>(meta.meta.header);
130 }
131 return nullptr;
132 }
133
141 template<typename S, typename... Args>
142 auto add_storage(Args&&... args) -> asset_storage<S>&
143 {
144 auto operation = storages_.emplace(hpp::type_id<asset_storage<S>>().hash_code(),
145 std::make_unique<asset_storage<S>>(std::forward<Args>(args)...));
146
147 return static_cast<asset_storage<S>&>(*operation.first->second);
148 }
149
158 template<typename T>
159 auto get_asset(const std::string& key,
162 {
163 auto& storage = get_storage<T>();
164 return load_asset_from_file_impl<T>(key,
165 flags,
166 mode,
167 storage.container_mutex,
168 storage.container,
169 storage.load_from_file);
170 }
171
180 template<typename T>
181 auto get_asset(const hpp::uuid& uid,
184 {
185 auto meta = get_metadata(uid);
186 if(!meta.location.empty())
187 {
188 const auto& key = meta.location;
189 return get_asset<T>(key, flags, mode);
190 }
191
192 if(parent_)
193 {
194 return parent_->get_asset<T>(uid, flags, mode);
195 }
196 return {};
197 }
198
206 template<typename T>
207 auto register_asset(const std::string& key) -> asset_handle<T>
208 {
209 auto& storage = get_storage<T>();
210 return register_asset_impl<T>(key,
211 storage.container_mutex,
212 storage.container,
213 storage.load_from_file);
214 }
215
223 template<typename T>
224 auto register_asset(const hpp::uuid& uid) -> asset_handle<T>
225 {
226 auto meta = get_metadata(uid);
227 if(!meta.location.empty())
228 {
229 return register_asset<T>(meta.location);
230 }
231 if(parent_)
232 {
233 return parent_->register_asset<T>(uid);
234 }
235 return {};
236 }
237
243 template<typename T>
245 {
246 auto& storage = get_storage<T>();
247 storage.preload_all();
248 }
249
255 void preload_all_assets();
256
263 template<typename T>
264 auto find_asset(const std::string& key) const -> const asset_handle<T>&
265 {
266 auto& storage = get_storage<T>();
267 return find_asset_impl<T>(key, storage.container_mutex, storage.container);
268 }
269
277 template<typename T>
278 auto get_asset_from_instance(const std::string& key, std::shared_ptr<T> entry) -> asset_handle<T>
279 {
280 auto& storage = get_storage<T>();
281 return get_asset_from_instance_impl(key,
282 entry,
283 storage.container_mutex,
284 storage.container,
285 storage.load_from_instance);
286 }
287
294 template<typename T>
295 void rename_asset(const std::string& key, const std::string& new_key)
296 {
297 for(auto& kvp : databases_)
298 {
299 auto& db = kvp.second;
300 db.rename_asset(key, new_key);
301 }
302
303 auto& storage = get_storage<T>();
304
305 std::lock_guard<std::recursive_mutex> lock(storage.container_mutex);
306 auto it = storage.container.find(key);
307 if(it != storage.container.end())
308 {
309 auto& handle = it->second;
310 handle.set_internal_id(new_key);
311 storage.container[new_key] = handle;
312 storage.container.erase(it);
313 }
314
315 if(parent_)
316 {
317 parent_->rename_asset<T>(key, new_key);
318 }
319 }
320
326 template<typename T>
327 void unload_asset(const std::string& key)
328 {
329 auto& storage = get_storage<T>();
330 storage.unload_single(pool_, key);
331
332 if(parent_)
333 {
334 parent_->unload_asset<T>(key);
335 }
336 }
337
344 template<typename T>
345 auto get_assets(const std::string& group = {}) const -> std::vector<asset_handle<T>>
346 {
347 auto& storage = get_storage<T>();
348 auto assets = storage.get_group(group);
349
350 if(parent_)
351 {
352 auto passets = parent_->get_assets<T>(group);
353 std::move(std::begin(passets), std::end(passets), std::back_inserter(assets));
354 }
355
356 return assets;
357 }
358
366 template<typename T, typename F>
367 auto get_assets_with_predicate(F&& predicate) const -> std::vector<asset_handle<T>>
368 {
369 auto& storage = get_storage<T>();
370 return storage.get_with_condition(std::forward<F>(predicate));
371 }
372
379 template<typename T, typename F>
380 void for_each_asset(F&& callback)
381 {
382 auto& storage = get_storage<T>();
383 std::lock_guard<std::recursive_mutex> lock(storage.container_mutex);
384
385 for(const auto& el : storage.container)
386 {
387 callback(el);
388 }
389
390 if(parent_)
391 {
392 parent_->for_each_asset<T, F>(std::forward<F>(callback));
393 }
394 }
395
400 auto get_all_assets(const std::string& group) const -> std::vector<std::string>;
401
408 void evict_unused_assets(const std::string& group, std::chrono::steady_clock::duration max_idle);
409
415 auto add_asset(const std::string& key, bool override = false) -> hpp::uuid;
416
423 auto add_asset_for_path(const fs::path& path, bool override = false) -> hpp::uuid;
424
425
426private:
432 auto get_database(const std::string& group) -> asset_database&;
433
438 void remove_database(const std::string& group);
439
440
453 template<typename T, typename F>
454 auto load_asset_from_file_impl(const std::string& key,
455 load_flags flags,
456 load_mode mode,
457 std::recursive_mutex& container_mutex,
458 typename asset_storage<T>::request_container_t& container,
459 F&& load_func) -> asset_handle<T>
460 {
461 if(flags != load_flags::reload)
462 {
463 auto inst = find_asset_impl<T>(key, container_mutex, container);
464 if(inst)
465 {
466 return inst;
467 }
468 }
469
470 std::unique_lock<std::recursive_mutex> lock(container_mutex);
471
472 auto& handle = container[key];
473 if(load_func)
474 {
475 auto uid = add_asset(key);
476
477 if(handle.task_id())
478 {
479 pool_.stop(handle.task_id());
480 handle.invalidate();
481 }
482
483 handle.set_internal_ids(uid, key);
484 load_func(pool_, handle, key, mode);
485 }
486
487 return handle;
488 }
489
500 template<typename T>
501 auto register_asset_impl(const std::string& key,
502 std::recursive_mutex& container_mutex,
503 typename asset_storage<T>::request_container_t& container,
505 {
506 auto inst = find_asset_impl<T>(key, container_mutex, container);
507 if(inst)
508 {
509 return inst;
510 }
511
512 std::lock_guard<std::recursive_mutex> lock(container_mutex);
513
514 auto& handle = container[key];
515 auto uid = add_asset(key);
516 handle.set_internal_ids(uid, key);
517 load_func(pool_, handle, key, load_mode::deferred);
518
519 return handle;
520 }
521
533 template<typename T, typename F>
534 auto get_asset_from_instance_impl(const std::string& key,
535 std::shared_ptr<T> entry,
536 std::recursive_mutex& container_mutex,
537 typename asset_storage<T>::request_container_t& container,
538 F&& load_func) -> asset_handle<T>
539 {
540 auto inst = find_asset_impl<T>(key, container_mutex, container);
541 if(inst)
542 {
543 return inst;
544 }
545
546 std::lock_guard<std::recursive_mutex> lock(container_mutex);
547
548 auto& handle = container[key];
549 // Dispatch the loading
550 if(load_func)
551 {
552 auto uid = add_asset(key);
553
554 // loading on a locked mutex is ok
555 // since we dont expect this to actually
556 // do much except add tasks to the
557 // executor
558 handle.set_internal_ids(uid, key);
559 load_func(pool_, handle, entry);
560 }
561
562 return handle;
563 }
564
573 template<typename T>
574 auto find_asset_impl(const std::string& key,
575 std::recursive_mutex& container_mutex,
576 typename asset_storage<T>::request_container_t& container) const -> const asset_handle<T>&
577 {
578 std::lock_guard<std::recursive_mutex> lock(container_mutex);
579 auto it = container.find(key);
580 if(it != container.end())
581 {
582 return it->second;
583 }
584
585 if(parent_)
586 {
587 return parent_->find_asset_impl<T>(key, container_mutex, container);
588 }
589
591 }
592
598 template<typename S>
599 auto get_storage() -> asset_storage<S>&
600 {
601 auto it = storages_.find(hpp::type_id<asset_storage<S>>().hash_code());
602 assert(it != storages_.end());
603 return (static_cast<asset_storage<S>&>(*it->second.get()));
604 }
605
611 template<typename S>
612 auto get_storage() const -> asset_storage<S>&
613 {
614 auto& storage = storages_.at(hpp::type_id<asset_storage<S>>().hash_code());
615 return (static_cast<asset_storage<S>&>(*storage.get()));
616 }
617
619 tpp::thread_pool& pool_;
621 std::unordered_map<std::size_t, std::unique_ptr<basic_storage>> storages_{};
623 mutable std::mutex db_mutex_;
625 std::map<std::string, asset_database, std::less<>> databases_{};
627 asset_manager* parent_{};
628};
629
630} // namespace unravel
Manages asset metadata and provides functionality for adding, removing, and querying assets.
Manages assets, including loading, unloading, and storage.
auto load_database(const std::string &protocol) -> bool
Loads an asset database from a protocol.
void preload_all_assets()
Triggers loading on all deferred handles across every registered storage. Non-blocking: starts backgr...
void save_database(const std::string &protocol, const fs::path &path)
Saves the asset database to a specified path.
asset_manager(rtti::context &ctx)
Constructs an asset manager with the given context.
auto generate_metadata(const fs::path &p) const -> asset_meta
auto get_all_assets(const std::string &group) const -> std::vector< std::string >
Gets all assets.
auto register_asset(const hpp::uuid &uid) -> asset_handle< T >
Registers an asset by UUID without loading it. The actual load is triggered on the first handle....
auto register_asset(const std::string &key) -> asset_handle< T >
Registers an asset by key without loading it. The actual load is triggered on the first handle....
auto get_metadata_for_path(const fs::path &path) const -> asset_database::meta
void evict_unused_assets(const std::string &group, std::chrono::steady_clock::duration max_idle)
Evicts full-loaded assets not accessed within the given duration. Demotes them back to deferred state...
void unload_all()
Unloads all assets.
auto init(rtti::context &ctx) -> bool
Initializes the asset manager with the given context.
~asset_manager()
Destructs the asset manager.
void unload_asset(const std::string &key)
Unloads an asset by its key.
void for_each_asset(F &&callback)
Applies a callback function to each asset.
auto add_asset(const std::string &key, bool override=false) -> hpp::uuid
Adds an asset with a specified key.
auto get_metadata(const hpp::uuid &uid) const -> asset_database::meta
Gets metadata for a resource uid.
auto get_header(const hpp::uuid &uid) const -> std::shared_ptr< HeaderT >
Gets typed header info for an asset without loading it.
void preload_assets()
Triggers loading on all deferred handles of a given type. Non-blocking: starts background loads but d...
auto get_assets_with_predicate(F &&predicate) const -> std::vector< asset_handle< T > >
Gets all assets that satisfy a predicate.
auto deinit(rtti::context &ctx) -> bool
Deinitializes the asset manager with the given context.
auto add_storage(Args &&... args) -> asset_storage< S > &
Adds a storage for a specific type.
auto get_assets(const std::string &group={}) const -> std::vector< asset_handle< T > >
Gets all assets in a specified group.
auto get_asset(const hpp::uuid &uid, load_flags flags=load_flags::standard, load_mode mode=load_mode::immediate) -> asset_handle< T >
Gets an asset by its UUID.
void remove_asset_info_for_key(const std::string &key)
Removes asset information for a specified key.
auto get_asset(const std::string &key, load_flags flags=load_flags::standard, load_mode mode=load_mode::immediate) -> asset_handle< T >
Gets an asset by its key.
auto get_metadata_for_key(const std::string &key) const -> asset_database::meta
auto add_asset_info_for_key(const std::string &key, const asset_meta &meta, bool override) -> hpp::uuid
Adds asset information for a specified key.
auto add_asset_info_for_path(const fs::path &path, const asset_meta &meta, bool override) -> hpp::uuid
Adds asset information for a specified path.
void remove_asset_info_for_path(const fs::path &path)
Removes asset information for a specified path.
auto find_asset(const std::string &key) const -> const asset_handle< T > &
Finds an asset by its key.
void rename_asset(const std::string &key, const std::string &new_key)
Renames an asset.
auto add_asset_for_path(const fs::path &path, bool override=false) -> hpp::uuid
Adds an asset with a specified path.
void register_asset_info_for_path(const fs::path &path, bool override)
void unload_group(const std::string &group)
Unloads all assets in a specified group.
void set_parent(asset_manager *parent)
Sets the parent asset manager.
auto get_asset_from_instance(const std::string &key, std::shared_ptr< T > entry) -> asset_handle< T >
Gets an asset handle from an instance.
load_mode
Controls whether an asset is loaded immediately or deferred until first access.
Definition asset_flags.h:17
@ deferred
Register handle only; load triggered on first .get() call.
@ immediate
Schedule load on thread pool now (default, backward compatible).
Thread-safe handle to an asset.
static auto get_empty() -> const asset_handle &
Gets an empty asset handle.
Metadata information for an asset including its location.
Metadata for an asset, including its UUID and type.
Manages storage and loading of assets of a specific type.
callable< bool(tpp::thread_pool &pool, asset_handle< T > &, const std::string &, load_mode)> load_from_file_t
Function type for loading from file.
std::unordered_map< std::string, asset_handle< T > > request_container_t
Container for asset requests.
gfx::uniform_handle handle
Definition uniform.cpp:9
std::vector< GitHubAsset > assets