// 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);