337 lines
11 KiB
C++
337 lines
11 KiB
C++
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Asset.h"
|
|
#include "Engine/Core/Types/Pair.h"
|
|
#include "Storage/FlaxStorageReference.h"
|
|
|
|
// Helper define
|
|
#define DECLARE_BINARY_ASSET_HEADER(type, serializedVersion) \
|
|
DECLARE_ASSET_HEADER(type); \
|
|
static const uint32 SerializedVersion = serializedVersion; \
|
|
uint32 GetSerializedVersion() const override { return SerializedVersion; }
|
|
|
|
#define REGISTER_BINARY_ASSET_ABSTRACT(type, typeName) \
|
|
const String type::TypeName = TEXT(typeName)
|
|
|
|
/// <summary>
|
|
/// Base class for all binary assets.
|
|
/// </summary>
|
|
/// <seealso cref="Asset" />
|
|
API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API BinaryAsset : public Asset
|
|
{
|
|
DECLARE_ASSET_HEADER(BinaryAsset);
|
|
protected:
|
|
|
|
AssetHeader _header;
|
|
FlaxStorageReference _storageRef; // Allow asset to have missing storage reference but only before asset is loaded or if it's virtual
|
|
bool _isSaving;
|
|
Array<BinaryAsset*> _dependantAssets;
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// Finalizes an instance of the <see cref="BinaryAsset"/> class.
|
|
/// </summary>
|
|
~BinaryAsset();
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// The asset storage container.
|
|
/// </summary>
|
|
FlaxStorage* Storage;
|
|
|
|
#if USE_EDITOR
|
|
|
|
/// <summary>
|
|
/// The asset metadata information. Stored in a Json format.
|
|
/// </summary>
|
|
BytesContainer Metadata;
|
|
|
|
/// <summary>
|
|
/// Asset dependencies list used by the asset for tracking (eg. material functions used by material asset). The pair of asset ID and cached file edit time (for tracking modification).
|
|
/// </summary>
|
|
Array<Pair<Guid, DateTime>> Dependencies;
|
|
|
|
#endif
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// Gets the asset serialized version.
|
|
/// </summary>
|
|
/// <returns>Version number.</returns>
|
|
virtual uint32 GetSerializedVersion() const = 0;
|
|
|
|
/// <summary>
|
|
/// Initializes the specified asset with asset header and storage only. Asset should be initialized later using will AssetInitData.
|
|
/// </summary>
|
|
/// <param name="storage">The storage container.</param>
|
|
/// <param name="header">The asset header.</param>
|
|
bool Init(const FlaxStorageReference& storage, AssetHeader& header);
|
|
|
|
/// <summary>
|
|
/// Initializes the specified asset.
|
|
/// </summary>
|
|
/// <param name="initData">The initialize data.</param>
|
|
/// <returns>True if cannot init, otherwise false</returns>
|
|
bool Init(AssetInitData& initData);
|
|
|
|
/// <summary>
|
|
/// Initializes the specified asset (as virtual).
|
|
/// </summary>
|
|
/// <param name="initData">The initialize data.</param>
|
|
/// <returns>True if cannot init, otherwise false</returns>
|
|
bool InitVirtual(AssetInitData& initData);
|
|
|
|
public:
|
|
|
|
#if USE_EDITOR
|
|
|
|
#if COMPILE_WITH_ASSETS_IMPORTER
|
|
|
|
/// <summary>
|
|
/// Reimports asset from the source file.
|
|
/// </summary>
|
|
API_FUNCTION() void Reimport() const;
|
|
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Returns imported file metadata.
|
|
/// </summary>
|
|
/// <param name="path">The import path.</param>
|
|
/// <param name="username">The import username.</param>
|
|
void GetImportMetadata(String& path, String& username) const;
|
|
|
|
/// <summary>
|
|
/// Gets the imported file path from the asset metadata (can be empty if not available).
|
|
/// </summary>
|
|
/// <returns>The imported source file path.</returns>
|
|
API_PROPERTY() String GetImportPath() const
|
|
{
|
|
String path, username;
|
|
GetImportMetadata(path, username);
|
|
return path;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the asset dependencies list and unregisters from tracking their changes.
|
|
/// </summary>
|
|
void ClearDependencies();
|
|
|
|
/// <summary>
|
|
/// Adds the dependency to the given asset.
|
|
/// </summary>
|
|
/// <param name="asset">The asset to depend on.</param>
|
|
void AddDependency(BinaryAsset* asset);
|
|
|
|
/// <summary>
|
|
/// Determines whether any of the dependency assets was modified after last modification time of this asset (last file write time check).
|
|
/// </summary>
|
|
/// <returns><c>true</c> if one or more dependencies were modified; otherwise, <c>false</c>.</returns>
|
|
bool HasDependenciesModified() const;
|
|
|
|
protected:
|
|
|
|
/// <summary>
|
|
/// Called when one of the asset dependencies gets modified (it was saved or reloaded or reimported).
|
|
/// </summary>
|
|
/// <param name="asset">The modified asset that this asset depends on.</param>
|
|
virtual void OnDependencyModified(BinaryAsset* asset)
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
protected:
|
|
|
|
/// <summary>
|
|
/// Initializes the specified asset.
|
|
/// </summary>
|
|
/// <param name="initData">The initialize data.</param>
|
|
/// <returns>True if cannot init, otherwise false</returns>
|
|
virtual bool init(AssetInitData& initData)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets packed chunks indices to preload before asset loading action
|
|
/// </summary>
|
|
/// <returns>Chunks to load flags</returns>
|
|
virtual AssetChunksFlag getChunksToPreload() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// Gets the asset chunk.
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <returns>Flax Chunk object or null if is missing</returns>
|
|
FlaxChunk* GetChunk(int32 index) const
|
|
{
|
|
ASSERT(index >= 0 && index < ASSET_FILE_DATA_CHUNKS);
|
|
auto chunk = _header.Chunks[index];
|
|
if (chunk)
|
|
chunk->RegisterUsage();
|
|
return chunk;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or creates the asset chunk.
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <returns>Flax Chunk object (may be null if asset storage doesn't allow to add new chunks).</returns>
|
|
FlaxChunk* GetOrCreateChunk(int32 index);
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified chunk exists.
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <returns>True if the specified chunk exists, otherwise false.</returns>
|
|
bool HasChunk(int32 index) const
|
|
{
|
|
ASSERT(index >= 0 && index < ASSET_FILE_DATA_CHUNKS);
|
|
return _header.Chunks[index] != nullptr;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the chunk size (in bytes).
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <returns>Chunk size (in bytes)</returns>
|
|
uint32 GetChunkSize(int32 index) const
|
|
{
|
|
ASSERT(index >= 0 && index < ASSET_FILE_DATA_CHUNKS);
|
|
return _header.Chunks[index] != nullptr ? _header.Chunks[index]->LocationInFile.Size : 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified chunk exists and is loaded.
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <returns>True if the specified chunk exists and is loaded, otherwise false.</returns>
|
|
bool HasChunkLoaded(int32 index) const
|
|
{
|
|
ASSERT(index >= 0 && index < ASSET_FILE_DATA_CHUNKS);
|
|
return _header.Chunks[index] != nullptr && _header.Chunks[index]->IsLoaded();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the chunk data (creates new chunk if is missing).
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <param name="data">The chunk data to set.</param>
|
|
void SetChunk(int32 index, const Span<byte>& data);
|
|
|
|
/// <summary>
|
|
/// Releases all the chunks data.
|
|
/// </summary>
|
|
void ReleaseChunks() const;
|
|
|
|
/// <summary>
|
|
/// Releases the chunk data (if loaded).
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
void ReleaseChunk(int32 index) const;
|
|
|
|
/// <summary>
|
|
/// Requests the chunk data asynchronously (creates task that will gather chunk data or null if already here).
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <returns>Task that will gather chunk data or null if already here.</returns>
|
|
ContentLoadTask* RequestChunkDataAsync(int32 index);
|
|
|
|
/// <summary>
|
|
/// Gets chunk data. May fail if not data requested. See RequestChunkDataAsync.
|
|
/// </summary>
|
|
/// <param name="index">The chunk index.</param>
|
|
/// <param name="data">Result data (linked chunk data, not copied).</param>
|
|
void GetChunkData(int32 index, BytesContainer& data) const;
|
|
|
|
/// <summary>
|
|
/// Loads the chunk (synchronous, blocks current thread).
|
|
/// </summary>
|
|
/// <param name="chunkIndex">The chunk index to load.</param>
|
|
/// <returns>True if failed, otherwise false.</returns>
|
|
bool LoadChunk(int32 chunkIndex);
|
|
|
|
/// <summary>
|
|
/// Loads the chunks (synchronous, blocks current thread).
|
|
/// </summary>
|
|
/// <param name="chunks">The chunks to load (packed in a flag).</param>
|
|
/// <returns>True if failed, otherwise false.</returns>
|
|
bool LoadChunks(AssetChunksFlag chunks);
|
|
|
|
#if USE_EDITOR
|
|
|
|
/// <summary>
|
|
/// Saves this asset to the storage container.
|
|
/// </summary>
|
|
/// <param name="data">Asset data.</param>
|
|
/// <param name="silentMode">In silent mode don't reload opened storage container that is using target file.</param>
|
|
/// <returns>True if failed, otherwise false.</returns>
|
|
FORCE_INLINE bool SaveAsset(AssetInitData& data, bool silentMode = false)
|
|
{
|
|
return SaveAsset(GetPath(), data, silentMode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves this asset to the file.
|
|
/// </summary>
|
|
/// <param name="data">Asset data.</param>
|
|
/// <param name="path">Asset path (will be used to override the asset or create a new one).</param>
|
|
/// <param name="silentMode">In silent mode don't reload opened storage container that is using target file.</param>
|
|
/// <returns>True if failed, otherwise false.</returns>
|
|
bool SaveAsset(const StringView& path, AssetInitData& data, bool silentMode = false);
|
|
|
|
/// <summary>
|
|
/// Saves asset data to the storage container. Asset unique ID is handled by auto.
|
|
/// </summary>
|
|
/// <param name="path">Asset path (will be used to override the asset or create a new one).</param>
|
|
/// <param name="data">Asset data.</param>
|
|
/// <param name="silentMode">In silent mode don't reload opened storage container that is using target file.</param>
|
|
/// <returns>True if failed, otherwise false.</returns>
|
|
static bool SaveToAsset(const StringView& path, AssetInitData& data, bool silentMode = false);
|
|
|
|
#endif
|
|
|
|
protected:
|
|
|
|
/// <summary>
|
|
/// Load data from the chunks
|
|
/// </summary>
|
|
/// <returns>Loading result</returns>
|
|
virtual LoadResult load() = 0;
|
|
|
|
private:
|
|
|
|
#if USE_EDITOR
|
|
void OnStorageReloaded(FlaxStorage* storage, bool failed);
|
|
#endif
|
|
|
|
public:
|
|
|
|
// [Asset]
|
|
#if USE_EDITOR
|
|
void OnDeleteObject() override;
|
|
#endif
|
|
const String& GetPath() const final override;
|
|
|
|
protected:
|
|
|
|
// [Asset]
|
|
ContentLoadTask* createLoadingTask() override;
|
|
LoadResult loadAsset() override;
|
|
void releaseStorage() final override;
|
|
#if USE_EDITOR
|
|
void onRename(const StringView& newPath) override;
|
|
#endif
|
|
};
|