// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #pragma once #if USE_EDITOR #include "IAssetUpgrader.h" #include "Engine/Content/Storage/AssetHeader.h" #include "Engine/Core/Log.h" /// /// Binary asset upgrading context structure. /// struct FLAXENGINE_API AssetMigrationContext { /// /// The input data. /// AssetInitData Input; /// /// The output data. /// AssetInitData Output; public: /// /// Allocates the chunk in the output data so upgrader can write to it. /// /// The index of the chunk. /// True if cannot allocate it. bool AllocateChunk(int32 index) { // Check index if (index < 0 || index >= ASSET_FILE_DATA_CHUNKS) { LOG(Warning, "Invalid asset chunk index {0}.", index); return true; } // Check if chunk has been already allocated if (Output.Header.Chunks[index] != nullptr) { LOG(Warning, "Asset chunk {0} has been already allocated.", index); return true; } // Create new chunk const auto chunk = New(); Output.Header.Chunks[index] = chunk; if (chunk == nullptr) { OUT_OF_MEMORY; } return false; } }; typedef bool (*UpgradeHandler)(AssetMigrationContext& context); /// /// Binary Assets Upgrader base class /// /// class FLAXENGINE_API BinaryAssetUpgrader : public IAssetUpgrader { public: struct Upgrader { uint32 CurrentVersion; uint32 TargetVersion; UpgradeHandler Handler; }; private: Upgrader const* _upgraders; int32 _upgradersCount; public: /// /// Upgrades the specified asset data serialized version. /// /// The serialized version. /// The context. /// True if cannot upgrade or upgrade failed, otherwise false bool Upgrade(uint32 serializedVersion, AssetMigrationContext& context) const { // Find upgrader for (int32 i = 0; i < _upgradersCount; i++) { auto& upgrader = _upgraders[i]; if (upgrader.CurrentVersion == serializedVersion) { // Set target version and preserve metadata context.Output.SerializedVersion = upgrader.TargetVersion; #if USE_EDITOR context.Output.Metadata = context.Input.Metadata; context.Output.Dependencies = context.Input.Dependencies; #endif // Upgrade LOG(Info, "Converting \'{0}\' from version {1} to {2}...", context.Input.Header.ToString(), context.Input.SerializedVersion, context.Output.SerializedVersion); return upgrader.Handler(context); } } return true; } public: /// /// Copies all the chunks from the input data to the output container. /// /// The context. /// True if failed, otherwise false. static bool CopyChunks(AssetMigrationContext& context) { for (int32 chunkIndex = 0; chunkIndex < ASSET_FILE_DATA_CHUNKS; chunkIndex++) { const auto srcChunk = context.Input.Header.Chunks[chunkIndex]; if (srcChunk != nullptr && srcChunk->IsLoaded()) { if (context.AllocateChunk(chunkIndex)) return true; context.Output.Header.Chunks[chunkIndex]->Data.Copy(srcChunk->Data); } } return false; } /// /// Copies single chunk from the input data to the output container. /// /// The context. /// The chunk index. /// True if failed, otherwise false. static bool CopyChunk(AssetMigrationContext& context, int32 index) { return CopyChunk(context, index, index); } /// /// Copies single chunk from the input data to the output container. /// /// The context. /// The source chunk index. /// The destination chunk index. /// True if failed, otherwise false. static bool CopyChunk(AssetMigrationContext& context, int32 srcIndex, int32 dstIndex) { // Check index if (srcIndex < 0 || srcIndex >= ASSET_FILE_DATA_CHUNKS) { LOG(Warning, "Invalid asset chunk index {0}.", srcIndex); return true; } // Check if loaded and valid const auto srcChunk = context.Input.Header.Chunks[srcIndex]; if (srcChunk != nullptr && srcChunk->IsLoaded()) { // Allocate memory if (context.AllocateChunk(dstIndex)) return true; // Copy data context.Output.Header.Chunks[dstIndex]->Data.Copy(srcChunk->Data); } return false; } protected: BinaryAssetUpgrader() { _upgraders = nullptr; _upgradersCount = 0; } void setup(Upgrader const* upgraders, int32 upgradersCount) { _upgraders = upgraders; _upgradersCount = upgradersCount; } public: // [IAssetUpgrader] bool ShouldUpgrade(uint32 serializedVersion) const override { // Find upgrader for (int32 i = 0; i < _upgradersCount; i++) { if (_upgraders[i].CurrentVersion == serializedVersion) return true; } return false; } }; #endif