ezEngine  Milestone 9
ResourceManager_inl.h
1 #pragma once
2 
3 #include <Foundation/Logging/Log.h>
4 
5 template <typename ResourceType>
6 ResourceType* ezResourceManager::GetResource(const char* szResourceID, bool bIsReloadable)
7 {
8  return static_cast<ResourceType*>(GetResource(ezGetStaticRTTI<ResourceType>(), szResourceID, bIsReloadable));
9 }
10 
11 template <typename ResourceType>
13 {
14  return ezTypedResourceHandle<ResourceType>(GetResource<ResourceType>(szResourceID, true));
15 }
16 
17 template <typename ResourceType>
18 ezTypedResourceHandle<ResourceType> ezResourceManager::LoadResource(const char* szResourceID, ezResourcePriority Priority,
19  ezTypedResourceHandle<ResourceType> hLoadingFallback)
20 {
21  ezTypedResourceHandle<ResourceType> hResource(GetResource<ResourceType>(szResourceID, true));
22 
23  ResourceType* pResource = ezResourceManager::BeginAcquireResource(hResource, ezResourceAcquireMode::PointerOnly,
25 
26  if (hLoadingFallback.IsValid())
27  {
28  pResource->SetLoadingFallbackResource(hLoadingFallback);
29  }
30 
32 
33  return hResource;
34 }
35 
36 template <typename ResourceType>
38 {
39  ezResource* pResource = nullptr;
40 
41  const ezTempHashedString sResourceHash(szResourceID);
42 
43  EZ_LOCK(s_ResourceMutex);
44 
45  const ezRTTI* pRtti = FindResourceTypeOverride(ezGetStaticRTTI<ResourceType>(), szResourceID);
46 
47  if (s_LoadedResources[pRtti].m_Resources.TryGetValue(sResourceHash, pResource))
48  return ezTypedResourceHandle<ResourceType>((ResourceType*)pResource);
49 
51 }
52 
53 template <typename ResourceType, typename DescriptorType>
54 ezTypedResourceHandle<ResourceType> ezResourceManager::CreateResource(const char* szResourceID, DescriptorType&& descriptor,
55  const char* szResourceDescription)
56 {
57  static_assert(std::is_rvalue_reference<DescriptorType&&>::value, "Please std::move the descriptor into this function");
58 
59  EZ_LOG_BLOCK("ezResourceManager::CreateResource", szResourceID);
60 
61  EZ_LOCK(s_ResourceMutex);
62 
63  ezTypedResourceHandle<ResourceType> hResource(GetResource<ResourceType>(szResourceID, false));
64 
65  ResourceType* pResource = BeginAcquireResource(hResource, ezResourceAcquireMode::PointerOnly);
66  pResource->SetResourceDescription(szResourceDescription);
67  pResource->m_Flags.Add(ezResourceFlags::IsCreatedResource);
68 
69  EZ_ASSERT_DEV(pResource->GetLoadingState() == ezResourceState::Unloaded,
70  "CreateResource was called on a resource that is already created");
71 
72  // If this does not compile, you either passed in the wrong descriptor type for the given resource type
73  // or you forgot to std::move the descriptor when calling CreateResource
74  {
75  auto localDescriptor = std::move(descriptor);
76  ezResourceLoadDesc ld = pResource->CreateResource(std::move(localDescriptor));
77  pResource->VerifyAfterCreateResource(ld);
78  }
79 
80  EZ_ASSERT_DEV(pResource->GetLoadingState() != ezResourceState::Unloaded, "CreateResource did not set the loading state properly.");
81 
82  EndAcquireResource(pResource);
83 
84  return hResource;
85 }
86 
87 template <typename ResourceType>
88 ResourceType* ezResourceManager::BeginAcquireResource(const ezTypedResourceHandle<ResourceType>& hResource, ezResourceAcquireMode mode,
89  const ezTypedResourceHandle<ResourceType>& hFallbackResource,
90  ezResourcePriority Priority, ezResourceAcquireResult* out_AcquireResult /*= nullptr*/)
91 {
92  // EZ_LOCK(s_ResourceMutex);
93 
94  EZ_ASSERT_DEV(hResource.IsValid(), "Cannot acquire a resource through an invalid handle!");
95 
96  ResourceType* pResource = (ResourceType*)hResource.m_Typeless.m_pResource;
97 
98  EZ_ASSERT_DEV(pResource->m_iLockCount < 20,
99  "You probably forgot somewhere to call 'EndAcquireResource' in sync with 'BeginAcquireResource'.");
100  EZ_ASSERT_DEBUG(pResource->GetDynamicRTTI()->IsDerivedFrom<ResourceType>(),
101  "The requested resource does not have the same type ('{0}') as the resource handle ('{1}').",
102  pResource->GetDynamicRTTI()->GetTypeName(), ezGetStaticRTTI<ResourceType>()->GetTypeName());
103 
104  if (mode == ezResourceAcquireMode::PointerOnly ||
105  (mode == ezResourceAcquireMode::MetaInfo && pResource->GetLoadingState() >= ezResourceState::UnloadedMetaInfoAvailable))
106  {
107  if (Priority != ezResourcePriority::Unchanged)
108  pResource->SetPriority(Priority);
109 
110  if (out_AcquireResult)
111  *out_AcquireResult = ezResourceAcquireResult::Final;
112 
113  pResource->m_iLockCount.Increment();
114  return pResource;
115  }
116 
117  // only set the last accessed time stamp, if it is actually needed, pointer-only access might not mean that the resource is used
118  // productively
119  pResource->m_LastAcquire = s_LastFrameUpdate;
120 
121  if (pResource->GetLoadingState() != ezResourceState::LoadedResourceMissing)
122  {
123  if (pResource->GetLoadingState() != ezResourceState::Loaded)
124  {
125  // only modify the priority, if the resource is not yet loaded
126  if (Priority != ezResourcePriority::Unchanged)
127  pResource->SetPriority(Priority);
128 
129  // will prepend this at the preload array, thus will be loaded immediately
130  // even after recalculating priorities, it will end up as top priority
131  InternalPreloadResource(pResource, true);
132 
133  if (mode == ezResourceAcquireMode::AllowFallback && (pResource->m_hLoadingFallback.IsValid() || hFallbackResource.IsValid() ||
134  GetResourceTypeLoadingFallback<ResourceType>().IsValid()))
135  {
136  // return the fallback resource for now, if there is one
137  if (out_AcquireResult)
138  *out_AcquireResult = ezResourceAcquireResult::LoadingFallback;
139 
140  // Fallback order is as follows:
141  // 1) Prefer any resource specific fallback resource
142  // 2) If not available, use the fallback that is given to BeginAcquireResource, as that is at least specific to the situation
143  // 3) If nothing else is available, take the fallback for the whole resource type
144 
145  if (pResource->m_hLoadingFallback.IsValid())
146  return (ResourceType*)BeginAcquireResource(pResource->m_hLoadingFallback, ezResourceAcquireMode::NoFallback);
147  else if (hFallbackResource.IsValid())
148  return (ResourceType*)BeginAcquireResource(hFallbackResource, ezResourceAcquireMode::NoFallback);
149  else
150  return (ResourceType*)BeginAcquireResource(GetResourceTypeLoadingFallback<ResourceType>(), ezResourceAcquireMode::NoFallback);
151  }
152 
153  const ezResourceState RequestedState =
154  (mode == ezResourceAcquireMode::MetaInfo) ? ezResourceState::UnloadedMetaInfoAvailable : ezResourceState::Loaded;
155 
156  EnsureResourceLoadingState(pResource, RequestedState);
157  }
158  else
159  {
160  // as long as there are more quality levels available, schedule the resource for more loading
161  if (pResource->m_Flags.IsSet(ezResourceFlags::IsPreloading) == false && pResource->GetNumQualityLevelsLoadable() > 0)
162  InternalPreloadResource(pResource, false);
163  }
164  }
165 
166  if (pResource->GetLoadingState() == ezResourceState::LoadedResourceMissing)
167  {
168  // When you get a crash with a stack overflow in this code path, then the resource to be used as the
169  // 'missing resource' replacement might be missing itself.
170 
171  if (/*mode == ezResourceAcquireMode::AllowFallback && (hFallbackResource.IsValid() || */ ezResourceManager::
172  GetResourceTypeMissingFallback<ResourceType>()
173  .IsValid()) //)
174  {
175  if (out_AcquireResult)
176  *out_AcquireResult = ezResourceAcquireResult::MissingFallback;
177 
178  // prefer the fallback given for this situation (might e.g. be a default normal map)
179  // use the type specific missing resource otherwise
180 
181  // if (hFallbackResource.IsValid())
182  // return (ResourceType*) BeginAcquireResource(hFallbackResource, ezResourceAcquireMode::NoFallback);
183  // else
184  return (ResourceType*)BeginAcquireResource(ezResourceManager::GetResourceTypeMissingFallback<ResourceType>(),
185  ezResourceAcquireMode::NoFallback);
186  }
187 
188  if (mode != ezResourceAcquireMode::NoFallbackAllowMissing)
189  {
190  EZ_REPORT_FAILURE("The resource '{0}' of type '{1}' is missing and no fallback is available", pResource->GetResourceID(),
191  ezGetStaticRTTI<ResourceType>()->GetTypeName());
192  }
193 
194  if (out_AcquireResult)
195  *out_AcquireResult = ezResourceAcquireResult::None;
196 
197  return nullptr;
198  }
199 
200  if (out_AcquireResult)
201  *out_AcquireResult = ezResourceAcquireResult::Final;
202 
203  pResource->m_iLockCount.Increment();
204  return pResource;
205 }
206 
207 template <typename ResourceType>
208 void ezResourceManager::EndAcquireResource(ResourceType* pResource)
209 {
210  EZ_ASSERT_DEV(pResource != nullptr, "Resource Pointer cannot be nullptr.");
211  EZ_ASSERT_DEV(pResource->m_iLockCount > 0, "The resource lock counter is incorrect: {0}", (ezInt32)pResource->m_iLockCount);
212 
213  pResource->m_iLockCount.Decrement();
214 }
215 
216 
217 template <typename ResourceType>
219 {
220  ResourceType* pResource = BeginAcquireResource(hResource, ezResourceAcquireMode::PointerOnly);
221  pResource->m_Flags.Remove(ezResourceFlags::PreventFileReload);
222 
223  ReloadResource(pResource, true);
224 
225  EndAcquireResource(pResource);
226 }
227 
228 template <typename ResourceType>
230 {
231  ResourceType* pResource = BeginAcquireResource(hResource, ezResourceAcquireMode::PointerOnly);
232 
233  bool res = ReloadResource(pResource, bForce);
234 
235  EndAcquireResource(pResource);
236 
237  return res;
238 }
239 
240 template <typename ResourceType>
242 {
243  return ReloadResourcesOfType(ezGetStaticRTTI<ResourceType>(), bForce);
244 }
245 
246 template <typename ResourceType>
248 {
249  EZ_LOCK(s_ResourceMutex);
250 
251  s_ResourceTypeLoader[ezGetStaticRTTI<ResourceType>()->GetTypeName()] = creator;
252 }
253 
255 {
256  EZ_LOCK(s_ResourceMutex);
257 
258  s_pDefaultResourceLoader = pDefaultLoader;
259 }
260 
261 template <typename ResourceType>
263 {
264  EZ_ASSERT_DEV(s_bExportMode, "Export mode needs to be enabled");
265 
266  return LoadResource<ResourceType>(szResourceID);
267 }
268 
static bool ReloadResource(const ezTypedResourceHandle< ResourceType > &hResource, bool bForce)
Reloads only the one specific resource. If bForce is true, it is updated, even if there is no indicat...
Definition: ResourceManager_inl.h:229
#define EZ_ASSERT_DEBUG(bCondition, szErrorMsg,...)
Macro to raise an error, if a condition is not met.
Definition: Assert.h:88
Once this flag is set, no reloading from file is done, until the flag is manually removed...
Definition: Declarations.h:65
static ezTypedResourceHandle< ResourceType > CreateResource(const char *szResourceID, DescriptorType &&descriptor, const char *szResourceDescription=nullptr)
Creates a resource from a descriptor.
Definition: ResourceManager_inl.h:54
#define EZ_REPORT_FAILURE(szErrorMsg,...)
Macro to report a failure when that code is reached. This will ALWAYS be executed, even in release builds, therefore might crash the application (or trigger a debug break).
Definition: Assert.h:52
static ezTypedResourceHandle< ResourceType > GetResourceHandleForExport(const char *szResourceID)
Creates a resource handle for the given resource ID. This method can only be used if export mode is e...
Definition: ResourceManager_inl.h:262
This enumerable class holds information about reflected types. Each instance represents one type that...
Definition: RTTI.h:30
static void RestoreResource(const ezTypedResourceHandle< ResourceType > &hResource)
Removes the &#39;PreventFileReload&#39; flag and forces a reload on the resource.
Definition: ResourceManager_inl.h:218
bool TryGetValue(const CompatibleKeyType &key, ValueType &out_value) const
Returns if an entry with the given key was found and if found writes out the corresponding value to o...
Definition: HashTable_inl.h:402
#define EZ_ASSERT_DEV(bCondition, szErrorMsg,...)
Macro to raise an error, if a condition is not met.
Definition: Assert.h:116
static void SetDefaultResourceLoader(ezResourceTypeLoader *pDefaultLoader)
Sets the resource loader to use when no type specific resource loader is available.
Definition: ResourceManager_inl.h:254
static ezUInt32 ReloadResourcesOfType(bool bForce)
Goes through all resources of the given type and makes sure they are reloaded, if they have changed...
Definition: ResourceManager_inl.h:241
When this is set, the resource was created and not loaded from file.
Definition: Declarations.h:67
The base class for all resources.
Definition: Resource.h:9
A class to use together with ezHashedString for quick comparisons with temporary strings that need no...
Definition: HashedString.h:149
static ezTypedResourceHandle< ResourceType > GetExistingResource(const char *szResourceID)
Returns a handle to the resource with the given ID. If the resource does not exist, the handle is invalid.
Definition: ResourceManager_inl.h:37
EZ_ALWAYS_INLINE bool IsValid() const
Returns whether the handle stores a valid pointer to a resource.
Definition: ResourceHandle.h:174
static ResourceType * BeginAcquireResource(const ezTypedResourceHandle< ResourceType > &hResource, ezResourceAcquireMode mode, const ezTypedResourceHandle< ResourceType > &hLoadingFallback=ezTypedResourceHandle< ResourceType >(), ezResourcePriority Priority=ezResourcePriority::Unchanged, ezResourceAcquireResult *out_AcquireResult=nullptr)
Acquires a resource pointer from a handle. Prefer to use ezResourceLock, which wraps BeginAcquireReso...
Definition: ResourceManager_inl.h:88
Describes in which loading state a resource currently is, and how many different quality levels there...
Definition: Declarations.h:96
The central class for managing all types derived from ezResource.
Definition: ResourceManager.h:11
static void EndAcquireResource(ResourceType *pResource)
Needs to be called in concert with BeginAcquireResource() after accessing a resource has been finishe...
Definition: ResourceManager_inl.h:208
Base class for all resource loaders.
Definition: ResourceTypeLoader.h:28
static void SetResourceTypeLoader(ezResourceTypeLoader *pCreator)
Sets the resource loader to use for the given resource type.
Definition: ResourceManager_inl.h:247
static ezTypedResourceHandle< ResourceType > LoadResource(const char *szResourceID)
Returns a handle to the requested resource. szResourceID must uniquely identify the resource...
Definition: ResourceManager_inl.h:12
The ezTypedResourceHandle controls access to an ezResource.
Definition: Declarations.h:14