// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Enums.h"
#include "Engine/Core/Delegate.h"
#include "Engine/Core/Types/String.h"
#include "Engine/Platform/CriticalSection.h"
#include "Engine/Scripting/ScriptingObject.h"
#include "Config.h"
#include "Types.h"
#define DECLARE_ASSET_HEADER(type) \
DECLARE_SCRIPTING_TYPE_NO_SPAWN(type); \
public: \
static const String TypeName; \
const String& GetTypeName() const override { return type::TypeName; } \
public: \
explicit type(const SpawnParams& params, const AssetInfo* info)
///
/// Asset objects base class.
///
API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API Asset : public ManagedScriptingObject
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Asset);
friend Content;
friend LoadAssetTask;
friend class ContentService;
public:
///
/// The asset loading result.
///
DECLARE_ENUM_7(LoadResult, Ok, Failed, MissingDataChunk, CannotLoadData, CannotLoadStorage, CannotLoadInitData, InvalidData);
protected:
volatile int64 _refCount;
ContentLoadTask* _loadingTask;
int8 _isLoaded : 1; // Indicates that asset is loaded
int8 _loadFailed : 1; // Indicates that last asset loading has failed
int8 _deleteFileOnUnload : 1; // Indicates that asset source file should be removed on asset unload
int8 _isVirtual : 1; // Indicates that asset is pure virtual (generated or temporary, has no storage so won't be saved)
public:
///
/// Initializes a new instance of the class.
///
/// The object initialization parameters.
/// The asset object information.
explicit Asset(const SpawnParams& params, const AssetInfo* info);
public:
typedef Delegate EventType;
///
/// Action called when asset gets loaded
///
EventType OnLoaded;
///
/// Action called when asset start reloading (e.g. after reimport). Always called from the main thread.
///
EventType OnReloading;
///
/// Action called when asset gets unloaded
///
EventType OnUnloaded;
///
/// General purpose mutex for an asset object. Should guard most of asset functionalities to be secure.
///
CriticalSection Locker;
public:
///
/// Gets asset's reference count. Asset will be automatically unloaded when this reaches zero.
///
API_PROPERTY() int32 GetReferencesCount() const;
///
/// Adds reference to that asset.
///
FORCE_INLINE void AddReference()
{
Platform::InterlockedIncrement(&_refCount);
}
///
/// Removes reference from that asset.
///
FORCE_INLINE void RemoveReference()
{
Platform::InterlockedDecrement(&_refCount);
}
public:
///
/// Gets the path to the asset storage file. In Editor it reflects the actual file, in cooked Game, it fakes the Editor path to be informative for developers.
///
API_PROPERTY() virtual const String& GetPath() const = 0;
///
/// Gets the asset type name.
///
virtual const String& GetTypeName() const = 0;
///
/// Returns true if asset is loaded, otherwise false.
///
API_PROPERTY() FORCE_INLINE bool IsLoaded() const
{
return _isLoaded != 0;
}
///
/// Returns true if last asset loading failed, otherwise false.
///
API_PROPERTY() bool LastLoadFailed() const;
///
/// Determines whether this asset is virtual (generated or temporary, has no storage so it won't be saved).
///
API_PROPERTY() FORCE_INLINE bool IsVirtual() const
{
return _isVirtual != 0;
}
#if USE_EDITOR
///
/// Determines whether this asset was marked to be deleted on unload.
///
API_PROPERTY() bool ShouldDeleteFileOnUnload() const;
#endif
///
/// Gets amount of CPU memory used by this resource (in bytes). It's a rough estimation. Memory may be fragmented, compressed or sub-allocated so the actual memory pressure from this resource may vary.
///
API_PROPERTY() virtual uint64 GetMemoryUsage() const;
public:
///
/// Reloads the asset.
///
API_FUNCTION() void Reload();
///
/// Stops the current thread execution and waits until asset will be loaded (loading will fail, success or be cancelled).
///
/// Custom timeout value in milliseconds.
/// True if cannot load that asset (failed or has been cancelled), otherwise false.
API_FUNCTION() bool WaitForLoaded(double timeoutInMilliseconds = 30000.0) const;
///
/// Initializes asset data as virtual asset.
///
virtual void InitAsVirtual();
///
/// Cancels any asynchronous content streaming by this asset (eg. mesh data streaming into GPU memory). Will release any locks for asset storage container.
///
virtual void CancelStreaming();
#if USE_EDITOR
///
/// Gets the asset references. Supported only in Editor.
///
///
/// For some asset types (e.g. scene or prefab) it may contain invalid asset ids due to not perfect gather method,
/// which is optimized to perform scan very quickly. Before using those ids perform simple validation via Content cache API.
/// The result collection contains only 1-level-deep references (only direct ones) and is invalid if asset is not loaded.
/// Also the output data may have duplicated asset ids or even invalid ids (Guid::Empty).
///
/// The output collection of the asset ids referenced by this asset.
virtual void GetReferences(Array& output) const;
///
/// Gets the asset references. Supported only in Editor.
///
///
/// For some asset types (e.g. scene or prefab) it may contain invalid asset ids due to not perfect gather method,
/// which is optimized to perform scan very quickly. Before using those ids perform simple validation via Content cache API.
/// The result collection contains only 1-level-deep references (only direct ones) and is invalid if asset is not loaded.
/// Also the output data may have duplicated asset ids or even invalid ids (Guid::Empty).
///
/// The collection of the asset ids referenced by this asset.
API_FUNCTION() Array GetReferences() const;
#endif
///
/// Deletes the managed object.
///
void DeleteManaged();
protected:
///
/// Creates the loading tasks sequence (allows to inject custom tasks to asset loading logic).
///
/// First task to call on start loading
virtual ContentLoadTask* createLoadingTask();
///
/// Starts the asset loading.
///
virtual void startLoading();
///
/// Releases the storage file/container handle to prevent issues when renaming or moving the asset.
///
virtual void releaseStorage();
///
/// Loads asset
///
/// Loading result
virtual LoadResult loadAsset() = 0;
///
/// Unloads asset data
///
/// True if asset is reloading data, otherwise false.
virtual void unload(bool isReloading) = 0;
protected:
virtual bool IsInternalType() const;
bool onLoad(LoadAssetTask* task);
void onLoaded();
void onLoaded_MainThread();
virtual void onUnload_MainThread();
#if USE_EDITOR
virtual void onRename(const StringView& newPath) = 0;
#endif
public:
// [ManagedScriptingObject]
String ToString() const override;
void OnDeleteObject() override;
bool CreateManaged() override;
void DestroyManaged() override;
void OnManagedInstanceDeleted() override;
void OnScriptingDispose() override;
void ChangeID(const Guid& newId) override;
};
// Don't include Content.h but just Load method
extern FLAXENGINE_API Asset* LoadAsset(const Guid& id, const ScriptingTypeHandle& type);