CoriEngine
Loading...
Searching...
No Matches
AssetManager.hpp
Go to the documentation of this file.
1#pragma once
2namespace Cori {
3 namespace Core {
4 class Application;
5 }
6
7 namespace Internal {
11 template<typename T>
12 concept IsDescriptor = requires(const T& a, const T& b) {
13 { a.GetRuntimeID() } -> std::same_as<uint32_t>;
14 { a.m_Name } -> std::convertible_to<std::string>;
15 { a == b } -> std::convertible_to<bool>;
16 typename T::AssetType;
17 typename T::Hasher;
18 };
19
23 template<typename Descriptor>
24 concept CanBeLoaded = IsDescriptor<Descriptor> && requires(const Descriptor& d) {
25 { Descriptor::AssetType::Create(d) } -> std::same_as<std::shared_ptr<typename Descriptor::AssetType>>;
26 };
27
31 template<typename Asset>
33 }
34
35 //PS: This is ass, need to move to using handles + uuid/metadata + hub-and-spoke model. And this will allow async loading.
36
46 struct Cache {
47 std::unordered_map<std::type_index, std::any> m_Caches;
48 std::mutex m_CacheMutex;
49 std::unordered_map<std::type_index, std::any> m_Placeholders;
50 };
51
52 public:
59 template <Internal::CanBeLoaded Descriptor>
60 static std::shared_ptr<typename Descriptor::AssetType> Get(const Descriptor& descriptor) {
62 std::lock_guard lock(s_Cache->m_CacheMutex);
63
64 auto& cache = GetCache<typename Descriptor::AssetType>();
65 if (const auto it = cache.find(descriptor.GetRuntimeID()); it != cache.end()) {
66 return it->second;
67 }
68
69 CORI_CORE_DEBUG_TAGGED({ Logger::Tags::AssetManager::Self }, "Cache miss for type <{}>, name: '{}' (RuntimeID: {}). Loading...", CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType) , descriptor.m_Name, descriptor.GetRuntimeID());
70
71 std::shared_ptr<typename Descriptor::AssetType> newAsset = Descriptor::AssetType::Create(descriptor);
72 cache[descriptor.GetRuntimeID()] = newAsset;
73 return newAsset;
74 }
75
76
83 template <Internal::CanBeLoaded Descriptor>
84 static void Preload(const std::initializer_list<Descriptor> descriptors) {
85
86 CORI_CORE_INFO_TAGGED({ Logger::Tags::AssetManager::Self }, "Preloading {} <{}(s/es)>", descriptors.size(), CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType));
87 for (const auto& descriptor : descriptors) {
88 Get(descriptor);
89 }
90 CORI_CORE_INFO_TAGGED({ Logger::Tags::AssetManager::Self }, "Preloaded {} <{}(s/es)>", descriptors.size(), CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType));
91 }
92
99 template <Internal::IsDescriptor Descriptor>
100 static void Unload(const std::initializer_list<Descriptor>& descriptors) {
101 std::lock_guard lock(s_Cache->m_CacheMutex);
102
103 CORI_CORE_INFO_TAGGED({ Logger::Tags::AssetManager::Self }, "Unloading {} <{}(s/es)>", descriptors.size(), CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType));
104 for (const auto& descriptor : descriptors) {
105 auto& cache = GetCache<typename Descriptor::AssetType>();
106
107 if (!cache.contains(descriptor.GetRuntimeID())) {
108 CORI_CORE_WARN_TAGGED({ Logger::Tags::AssetManager::Self }, "Trying to unload <{}> that is not loaded, name '{}', (RuntimeID: {})", CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType), descriptor.m_Name, descriptor.GetRuntimeID());
109 return;
110 }
111
112 auto ptr = cache.at(descriptor.GetRuntimeID());
113 if (ptr.use_count() > 1) {
114 CORI_CORE_WARN_TAGGED({ Logger::Tags::AssetManager::Self }, "Trying to unload <{}>, name '{}' that is still used somewhere, it will be freed, as soon as refcount drops to 0. (RuntimeID: {})", CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType), descriptor.m_Name, descriptor.GetRuntimeID());
115 }
116
117 cache.erase(descriptor.GetRuntimeID());
118 CORI_CORE_DEBUG_TAGGED({ Logger::Tags::AssetManager::Self }, "Unloaded <{}>, name: '{}' (RuntimeID: {}).", CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType), descriptor.m_Name, descriptor.GetRuntimeID());
119 }
120
121 CORI_CORE_INFO_TAGGED({ Logger::Tags::AssetManager::Self }, "Unloaded {} <{}(s/es)>", descriptors.size(), CORI_CLEAN_TYPE_NAME(typename Descriptor::AssetType));
122 }
123
129 template<Internal::IsAsset AssetType>
130 static void RegisterPlaceholder(const std::shared_ptr<AssetType>& placeholderInstance) {
131 CORI_CORE_INFO_TAGGED({ Logger::Tags::AssetManager::Self }, "Registering placeholder for type <{}>", CORI_CLEAN_TYPE_NAME(AssetType));
132 if (!s_Cache->m_Placeholders.contains(std::type_index(typeid(AssetType)))) {
133 s_Cache->m_Placeholders[std::type_index(typeid(AssetType))] = placeholderInstance;
134 CORI_CORE_INFO_TAGGED({ Logger::Tags::AssetManager::Self }, "Registered placeholder for type <{}>", CORI_CLEAN_TYPE_NAME(AssetType));
135 return;
136 }
137
138 CORI_CORE_WARN_TAGGED({ Logger::Tags::AssetManager::Self }, "Placeholder for type <{}> already exists.", CORI_CLEAN_TYPE_NAME(AssetType));
139 }
140
146 template<Internal::IsAsset AssetType>
147 static std::shared_ptr<AssetType> GetPlaceholder() {
148 if (s_Cache->m_Placeholders.contains(std::type_index(typeid(AssetType)))) {
149 return std::any_cast<std::shared_ptr<AssetType>>(s_Cache->m_Placeholders[std::type_index(typeid(AssetType))]);
150 }
151
152 CORI_CORE_ERROR_TAGGED({ Logger::Tags::AssetManager::Self }, "Placeholder for type <{}> doesnt exists, returned nullptr.", CORI_CLEAN_TYPE_NAME(AssetType));
153 return nullptr;
154 }
155
161 template<Internal::IsAsset AssetType>
162 static bool HasPlaceholder() {
163 return s_Cache->m_Placeholders.contains(std::type_index(typeid(AssetType)));
164 }
165
171 template <typename AssetType>
172 static void ClearCache() {
173 std::lock_guard lock(s_Cache->m_CacheMutex);
174
175 if (s_Cache->m_Caches.contains(std::type_index(typeid(AssetType)))) {
176 GetCache<AssetType>().clear();
177 CORI_CORE_DEBUG_TAGGED({ Logger::Tags::AssetManager::Self }, "Cleared cache for type <{}>", CORI_CLEAN_TYPE_NAME(AssetType));
178 }
179 }
180 private:
181 friend Core::Application;
182 static void Init();
183 static void Shutdown();
184 static void RegisterPlaceholders();
185
186 template <typename AssetType>
187 static std::unordered_map<uint32_t, std::shared_ptr<AssetType>>& GetCache() {
188 const auto typeIndex = std::type_index(typeid(AssetType));
189 if (!s_Cache->m_Caches.contains(typeIndex)) {
190 s_Cache->m_Caches[typeIndex] = std::unordered_map<uint32_t, std::shared_ptr<AssetType>>();
191 }
192 return std::any_cast<std::unordered_map<uint32_t, std::shared_ptr<AssetType>>&>(s_Cache->m_Caches.at(typeIndex));
193 }
194
195 static Cache* s_Cache;
196 };
197}
#define CORI_CLEAN_TYPE_NAME(tn)
#define CORI_CORE_DEBUG_TAGGED(...)
Definition Logger.hpp:1026
#define CORI_CORE_ERROR_TAGGED(...)
Definition Logger.hpp:1039
#define CORI_CORE_WARN_TAGGED(...)
Definition Logger.hpp:1038
#define CORI_CORE_INFO_TAGGED(...)
Definition Logger.hpp:1027
#define CORI_PROFILE_FUNCTION()
Definition Profiler.hpp:9
Used when you want to manually control the asset lifetime, loading, preloading, unloading.
static void Unload(const std::initializer_list< Descriptor > &descriptors)
Unloads a group (or one) of assets from the cache.
static std::shared_ptr< typename Descriptor::AssetType > Get(const Descriptor &descriptor)
Gets the asset from the asset manager cache, it works with any asset that has a Descriptor defined.
static void Preload(const std::initializer_list< Descriptor > descriptors)
Preloads a group (or one) of assets into the cache.
static void ClearCache()
Clears cache for o specified asset type.
static std::shared_ptr< AssetType > GetPlaceholder()
Retrieves the instance of placeholder for a specified asset type.
static bool HasPlaceholder()
Checks if an asset type have placeholder registered.
static void RegisterPlaceholder(const std::shared_ptr< AssetType > &placeholderInstance)
This allows you to register a placeholder for a specific asset that you can later retrieve.
Main Application object, there can only be one Application object. Basically a root of the program.
Checks if AssetType of Descriptor can be loaded by the AssetManager.
Checks if Asset is an asset type that AssetManager can work with.
Checks T can be considered a descriptor.
Core systems of the engine are here.
Global engine namespace.
static constexpr char Self[]
Definition Logger.hpp:43