2#include "Engine/Logging/TracyMacros.hpp"
5#include <entt/entt.hpp>
10#include <unordered_map>
11#include <Engine/Ecs/RegistryManager.h>
49 template <
typename Key,
typename AssetClass>
52 template <
typename Key,
typename AssetClass>
64 template <
typename Key,
typename AssetClass>
103 template <
typename Key,
typename AssetClass>
122 readyPromise = std::make_shared<std::promise<Result>>();
178 template <
typename Key,
typename AssetClass>
196 const auto record =
record_.lock();
197 return record ? record->state :
UNLOADED;
213 [[nodiscard]] AssetClass*
get()
const
215 const auto record =
record_.lock();
216 return record && record->state ==
LOADED ? record->asset.get() :
nullptr;
237 const auto record =
record_.lock();
238 return record ? record->generation : 0;
247 static const std::string empty;
248 const auto record =
record_.lock();
249 return record ? record->lastError : empty;
258 const auto record =
record_.lock();
266 [[nodiscard]]
explicit operator bool()
const
274 explicit Ref(std::shared_ptr<RecordType> record) :
record_(
std::move(record)) {}
278 static std::shared_future<Result> future = []
280 std::promise<Result> promise;
282 result.
error =
"Asset record expired";
283 promise.set_value(std::move(result));
284 return promise.get_future().share();
303 explicit AssetBase(
bool initializeDefaultEntity =
false) :
357 template <
typename Key,
typename AssetClass>
380 template <
typename... Args>
388 void add(Key path, AssetClass* asset);
408 void resolve(
const Key& path, std::unique_ptr<AssetClass> asset);
413 void fail(
const Key& path, std::string error);
447 std::optional<AssetClass*>
getAsset(
const Key& path);
459 template<
typename Func>
461 for (
const auto& [key, record] :
records) {
462 if (record && record->asset !=
nullptr) {
463 func(key, record->asset.get());
470 [[nodiscard]] std::shared_ptr<RecordType>
getRecord(
const Key& path)
const;
471 void completeRecord(
const std::shared_ptr<RecordType>& record,
bool success, std::string error = {});
474 std::unordered_map<Key, std::shared_ptr<RecordType>>
records;
477 template<
typename Key,
typename AssetClass>
478 template<
typename... Args>
481 record->asset = std::make_unique<AssetClass>(std::forward<Args>(args)...);
482 ++record->generation;
483 record->resetFuture();
485 if (record->state ==
LOADED) {
490 template<
typename Key,
typename AssetClass>
492 TRACY_ZONE_SCOPED_NAMED(
"Added Asset to Asset Manager" );
493 assert(asset !=
nullptr);
495 record->asset.reset(asset);
496 ++record->generation;
497 record->resetFuture();
499 if (record->state ==
LOADED) {
504 template<
typename Key,
typename AssetClass>
509 template<
typename Key,
typename AssetClass>
514 template<
typename Key,
typename AssetClass>
521 ++record->generation;
522 record->resetFuture();
523 record->lastError.clear();
525 record->asset.reset();
529 record->state = state;
535 template<
typename Key,
typename AssetClass>
538 record->asset = std::move(asset);
540 record->lastError.clear();
544 template<
typename Key,
typename AssetClass>
547 record->asset.reset();
549 record->lastError = std::move(error);
553 template<
typename Key,
typename AssetClass>
557 record->asset.reset();
559 ++record->generation;
560 record->resetFuture();
561 record->lastError.clear();
564 template<
typename Key,
typename AssetClass>
567 return record && record->asset !=
nullptr;
570 template <
typename Key,
typename AssetClass>
576 template <
typename Key,
typename AssetClass>
581 return record->state;
584 template<
typename Key,
typename AssetClass>
586 TRACY_ZONE_SCOPED_NAMED(
"Retrieve Asset");
588 if (!record || record->asset ==
nullptr)
return std::nullopt;
590 return record->asset.get();
593 template <
typename Key,
typename AssetClass>
596 TRACY_ZONE_SCOPED_NAMED(
"Unloading data" );
597 for (
auto& [key, record] :
records)
599 TRACY_ZONE_SCOPED_NAMED(
"Deleting loaded data");
601 record->asset.reset();
603 ++record->generation;
604 record->resetFuture();
605 record->lastError.clear();
611 template<
typename Key,
typename AssetClass>
618 auto record = std::make_shared<RecordType>(path);
623 template<
typename Key,
typename AssetClass>
625 const auto it =
records.find(path);
626 return it !=
records.end() ? it->second :
nullptr;
629 template<
typename Key,
typename AssetClass>
631 if (!record || record->readyPromiseResolved || !record->readyPromise)
return;
635 result.
asset = success ? record->asset.get() :
nullptr;
637 result.
error = std::move(error);
640 record->readyPromise->set_value(std::move(result));
641 record->readyPromiseResolved =
true;
644 template<
typename Key,
typename AssetClass>
646 if (!record || record->asset ==
nullptr)
return;
647 if (record->state ==
FAILED)
return;
649 const LoadState payloadState = record->asset->getLoadingState();
650 if (payloadState != record->state) {
651 record->state = payloadState;
653 if (record->state ==
LOADED) {
void requestLoad()
If this asset is in the UNLOADED state it will get added to the assets to load.
entt::entity data
Entity containing the asset's component data.
entt::entity getEntity() const
Getter for data.
virtual ~AssetBase()
Releases base asset resources.
virtual void unload()
Base function for unloading the ecs data.
AssetBase(bool initializeDefaultEntity=false)
Creates a base asset and optionally allocates its default ECS entity.
virtual void updateLoadingState()
Updates loadingState from derived asset data.
CpuLoadingState loadingState
Current CPU loading state.
CpuLoadingState getLoadingState()
Gets the loading state of this asset.
entt::registry & mainRegistry
Registry that owns this asset's ECS data.
A manager which is used to look up existing assets and their loading state.
void declare(Key path, Args &&... args)
Adds an asset to the list in its unloaded state.
std::shared_ptr< RecordType > getOrCreateRecord(const Key &path)
Record< Key, AssetClass > RecordType
Internal record type stored by this manager.
LoadResult< Key, AssetClass > ResultType
Completion result type for async loads.
CpuLoadingState getAssetLoadingState(const Key &path)
Gets a loading state for an asset. If the asset is not yet declared it will return that it is UNLOADE...
std::optional< AssetClass * > getAsset(const Key &path)
Try's to get an asset. If the asset does not exist (can be checked with exists) it will return a std:...
void syncRecordStateFromPayload(const std::shared_ptr< RecordType > &record) const
void setAssetLoadingState(const Key &path, LoadState state)
Sets the record loading state without requiring a payload object.
void fail(const Key &path, std::string error)
Marks the record as failed and resolves the ready future with an error.
std::shared_ptr< RecordType > getRecord(const Key &path) const
bool isDeclared(Key path)
Checks if an asset has been declared. If it exists it is also declared.
void forEachAsset(Func &&func) const
Iterates over all assets and calls the provided callback for each.
void completeRecord(const std::shared_ptr< RecordType > &record, bool success, std::string error={})
bool exists(Key path)
Checks if an asset already exists. This means it is declared and there is content.
AssetManager()=default
Creates an empty asset manager.
virtual void clear()
Clears out all resources.
void add(Key path, AssetClass *asset)
Adds or overwrites a previously declared asset at a key.
RefType getRef(const Key &path) const
Gets a stable asset reference if a record exists, otherwise an expired ref.
virtual ~AssetManager()=default
Destroys the manager object.
Ref< Key, AssetClass > RefType
Stable reference type returned by this manager.
void resolve(const Key &path, std::unique_ptr< AssetClass > asset)
Stores a loaded payload and resolves the record's ready future.
std::unordered_map< Key, std::shared_ptr< RecordType > > records
void unloadAssetPayload(const Key &path)
Drops the loaded payload while preserving the stable record.
RefType getOrCreateRef(const Key &path)
Gets a stable asset reference, creating a record if necessary.
Non-owning handle to an asset record managed by AssetManager.
LoadState getState() const
Gets the current loading state.
Ref()=default
Creates an empty ref that points to no record.
std::shared_ptr< RecordType > sharedRecord() const
Gets a shared handle to the underlying record, keeping it (and its asset payload) alive as long as an...
Ref(std::shared_ptr< RecordType > record)
LoadResult< Asset::MeshPath, Animation > Result
const std::string & getError() const
Gets the last load error reported by the record.
std::shared_future< Result > readyFuture() const
Gets a future for completion of the current generation.
std::weak_ptr< RecordType > record_
static std::shared_future< Result > expiredFuture()
bool isLoaded() const
Checks whether the referenced asset has a loaded payload.
AssetClass * get() const
Gets the loaded payload.
Record< Asset::MeshPath, Animation > RecordType
uint64_t getGeneration() const
Gets the current record generation.
Classes which are related to asset loading are mostly stored in this namespace.
CpuLoadingState
State for assets in the asset loading process.
@ LOADED
All components of the asset have been loaded, and it is ready to be used.
@ REQUESTED_LOAD
An asset has been requested to load and is waiting for an asset pipeline to start working on it.
@ LOADING
While the asset is currently being processed in the asset pipeline.
@ UNLOADED
When the asset is not loaded yet but the frame is already existing for the heavy data to be loaded in...
@ FAILED
Asset loading finished unsuccessfully. Inspect the asset ref error for details.
CpuLoadingState LoadState
Alias used by the asset manager and refs.
Result returned when an asynchronous asset load reaches a terminal state.
AssetClass * asset
Loaded asset payload, or nullptr when loading failed or the record expired.
bool success
True when the payload finished loading successfully.
Ref< Key, AssetClass > ref
Stable reference to the record that produced this result.
std::string error
Failure message for unsuccessful loads.
uint64_t generation
Record generation that completed.
Internal storage for one asset entry managed by AssetManager.
std::string lastError
Last failure message reported for this record.
std::shared_future< Result > readyFuture
Shared future resolved when the current generation succeeds or fails.
Record(Key key)
Creates an unloaded record for an asset key.
void resetFuture()
Starts a new ready future for the current generation.
bool readyPromiseResolved
True after readyPromise has been resolved for the current generation.
uint64_t generation
Monotonic version incremented when the payload lifecycle restarts.
std::shared_ptr< std::promise< Result > > readyPromise
Promise used by AssetManager to complete readyFuture.
LoadState state
Current CPU loading state for the record.
LoadResult< Key, AssetClass > Result
Completion result type for this record.
Key key
Asset lookup key for this record.
std::unique_ptr< AssetClass > asset
Owned payload instance, or nullptr while no payload is available.