From 8a7ceef2881a99e28f220317587ac2bf3c262199 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 20 Jan 2025 23:46:49 +0100 Subject: [PATCH] Add content deprecation system that auto-saves assets in Editor that use old data format --- Flax.sln.DotSettings | 1 + Source/Engine/AI/BehaviorTree.cpp | 29 +-- Source/Engine/AI/BehaviorTree.h | 5 +- .../SceneAnimations/SceneAnimation.cpp | 187 ++++++++++++++++-- .../SceneAnimations/SceneAnimation.h | 7 +- Source/Engine/Content/Asset.cpp | 73 +++++++ Source/Engine/Content/Asset.h | 10 +- Source/Engine/Content/Assets/Animation.cpp | 21 +- Source/Engine/Content/Assets/Animation.h | 10 +- .../Engine/Content/Assets/AnimationGraph.cpp | 28 +-- Source/Engine/Content/Assets/AnimationGraph.h | 5 +- .../Content/Assets/AnimationGraphFunction.cpp | 37 ++-- .../Content/Assets/AnimationGraphFunction.h | 8 +- Source/Engine/Content/Assets/Material.cpp | 59 ++++-- Source/Engine/Content/Assets/Material.h | 4 +- .../Content/Assets/MaterialFunction.cpp | 33 ++-- .../Engine/Content/Assets/MaterialFunction.h | 13 +- .../Content/Assets/MaterialInstance.cpp | 12 +- .../Engine/Content/Assets/MaterialInstance.h | 13 +- Source/Engine/Content/Assets/Model.cpp | 4 +- Source/Engine/Content/Assets/Model.h | 4 +- Source/Engine/Content/Assets/ModelBase.cpp | 20 +- Source/Engine/Content/Assets/ModelBase.h | 5 +- Source/Engine/Content/Assets/RawDataAsset.cpp | 12 +- Source/Engine/Content/Assets/RawDataAsset.h | 15 +- Source/Engine/Content/Assets/SkeletonMask.cpp | 12 +- Source/Engine/Content/Assets/SkeletonMask.h | 12 +- Source/Engine/Content/Assets/SkinnedModel.cpp | 2 +- Source/Engine/Content/Assets/SkinnedModel.h | 2 +- Source/Engine/Content/Assets/Texture.cpp | 19 +- Source/Engine/Content/Assets/Texture.h | 18 +- Source/Engine/Content/Assets/VisualScript.cpp | 33 ++-- Source/Engine/Content/Assets/VisualScript.h | 7 +- Source/Engine/Content/BinaryAsset.cpp | 17 +- Source/Engine/Content/BinaryAsset.h | 6 +- Source/Engine/Content/Content.cpp | 5 - Source/Engine/Content/Deprecated.h | 26 +++ Source/Engine/Content/JsonAsset.cpp | 78 ++++++-- Source/Engine/Content/JsonAsset.h | 10 +- Source/Engine/Core/Types/Variant.cpp | 2 + Source/Engine/Engine/GameplayGlobals.cpp | 12 +- Source/Engine/Engine/GameplayGlobals.h | 14 +- Source/Engine/Foliage/Foliage.cpp | 2 + .../Graphics/Materials/MaterialParams.cpp | 5 + .../Shaders/Cache/ShaderAssetBase.cpp | 8 +- .../Graphics/Shaders/Cache/ShaderAssetBase.h | 14 +- .../Graphics/Shaders/Cache/ShaderStorage.h | 2 +- Source/Engine/Level/Actor.cpp | 7 + Source/Engine/Level/Actors/AnimatedModel.cpp | 7 + .../Engine/Level/Actors/EnvironmentProbe.cpp | 2 + Source/Engine/Level/Actors/SplineModel.cpp | 7 + Source/Engine/Level/Actors/StaticModel.cpp | 8 + Source/Engine/Navigation/Navigation.cpp | 5 +- Source/Engine/Particles/ParticleEffect.cpp | 2 + Source/Engine/Particles/ParticleEmitter.cpp | 50 +++-- Source/Engine/Particles/ParticleEmitter.h | 26 +-- .../Particles/ParticleEmitterFunction.cpp | 35 ++-- .../Particles/ParticleEmitterFunction.h | 17 +- Source/Engine/Particles/ParticleSystem.cpp | 30 +-- Source/Engine/Particles/ParticleSystem.h | 7 +- .../Engine/Physics/Actors/WheeledVehicle.cpp | 9 +- Source/Engine/Render2D/FontAsset.cpp | 12 +- Source/Engine/Render2D/FontAsset.h | 12 +- Source/Engine/Serialization/JsonTools.cpp | 2 + Source/Engine/Terrain/Terrain.cpp | 10 +- Source/Engine/UI/TextRender.cpp | 7 + Source/Engine/Visject/Graph.h | 2 + 67 files changed, 751 insertions(+), 427 deletions(-) create mode 100644 Source/Engine/Content/Deprecated.h diff --git a/Flax.sln.DotSettings b/Flax.sln.DotSettings index 8ff4f1621..86647d380 100644 --- a/Flax.sln.DotSettings +++ b/Flax.sln.DotSettings @@ -237,6 +237,7 @@ True True True + True DisabledByUser True Blue diff --git a/Source/Engine/AI/BehaviorTree.cpp b/Source/Engine/AI/BehaviorTree.cpp index 8cbb9f608..69fd0f854 100644 --- a/Source/Engine/AI/BehaviorTree.cpp +++ b/Source/Engine/AI/BehaviorTree.cpp @@ -13,6 +13,7 @@ #include "FlaxEngine.Gen.h" #if USE_EDITOR #include "Engine/Level/Level.h" +#include "Engine/Serialization/MemoryWriteStream.h" #endif REGISTER_BINARY_ASSET(BehaviorTree, "FlaxEngine.BehaviorTree", false); @@ -164,7 +165,7 @@ BehaviorTreeNode* BehaviorTree::GetNodeInstance(uint32 id) return nullptr; } -BytesContainer BehaviorTree::LoadSurface() +BytesContainer BehaviorTree::LoadSurface() const { if (WaitForLoaded()) return BytesContainer(); @@ -182,19 +183,10 @@ BytesContainer BehaviorTree::LoadSurface() #if USE_EDITOR -bool BehaviorTree::SaveSurface(const BytesContainer& data) +bool BehaviorTree::SaveSurface(const BytesContainer& data) const { - // Wait for asset to be loaded or don't if last load failed - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Set Visject Surface data @@ -250,6 +242,19 @@ void BehaviorTree::GetReferences(Array& assets, Array& files) cons } } +bool BehaviorTree::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + MemoryWriteStream stream; + if (Graph.Save(&stream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(stream)); + return SaveSurface(data); +} + #endif void BehaviorTree::OnScriptingDispose() diff --git a/Source/Engine/AI/BehaviorTree.h b/Source/Engine/AI/BehaviorTree.h index 1463cd9a5..3b3265232 100644 --- a/Source/Engine/AI/BehaviorTree.h +++ b/Source/Engine/AI/BehaviorTree.h @@ -77,7 +77,7 @@ public: /// Tries to load surface graph from the asset. /// /// The surface data or empty if failed to load it. - API_FUNCTION() BytesContainer LoadSurface(); + API_FUNCTION() BytesContainer LoadSurface() const; #if USE_EDITOR /// @@ -85,7 +85,7 @@ public: /// /// Stream with graph data. /// True if cannot save it, otherwise false. - API_FUNCTION() bool SaveSurface(const BytesContainer& data); + API_FUNCTION() bool SaveSurface(const BytesContainer& data) const; #endif private: @@ -99,6 +99,7 @@ public: void OnScriptingDispose() override; #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp b/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp index afe4446bc..6896f242a 100644 --- a/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp +++ b/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp @@ -5,6 +5,7 @@ #include "Engine/Content/Factories/BinaryAssetFactory.h" #include "Engine/Content/Assets/MaterialBase.h" #include "Engine/Content/Content.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Serialization/MemoryReadStream.h" #include "Engine/Audio/AudioClip.h" #include "Engine/Graphics/PostProcessSettings.h" @@ -35,19 +36,166 @@ const BytesContainer& SceneAnimation::LoadTimeline() #if USE_EDITOR -bool SceneAnimation::SaveTimeline(const BytesContainer& data) +void SceneAnimation::SaveData(MemoryWriteStream& stream) const { - // Wait for asset to be loaded or don't if last load failed (eg. by shader source compilation error) - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); - return true; - } + // Save properties + stream.Write(4); + stream.Write(FramesPerSecond); + stream.Write(DurationFrames); + // Save tracks + stream.Write(Tracks.Count()); + for (const auto& track : Tracks) + { + stream.Write((byte)track.Type); + stream.Write((byte)track.Flag); + stream.Write((int32)track.ParentIndex); + stream.Write((int32)track.ChildrenCount); + stream.Write(track.Name, -13); + stream.Write(track.Color); + switch (track.Type) + { + case Track::Types::Folder: + break; + case Track::Types::PostProcessMaterial: + { + auto trackData = stream.Move(); + trackData->AssetID = track.Asset.GetID(); + const auto trackRuntime = track.GetRuntimeData(); + stream.Write((int32)trackRuntime->Count); + stream.WriteBytes(trackRuntime->Media, sizeof(Media) * trackRuntime->Count); + break; + } + case Track::Types::NestedSceneAnimation: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + trackData->AssetID = track.Asset.GetID(); + break; + } + case Track::Types::ScreenFade: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + const auto trackRuntime = track.GetRuntimeData(); + stream.WriteBytes(trackRuntime->GradientStops, sizeof(ScreenFadeTrack::GradientStop) * trackData->GradientStopsCount); + break; + } + case Track::Types::Audio: + { + auto trackData = stream.Move(); + trackData->AssetID = track.Asset.GetID(); + const auto trackRuntime = track.GetRuntimeData(); + stream.Write((int32)trackRuntime->Count); + stream.WriteBytes(trackRuntime->Media, sizeof(AudioTrack::Media) * trackRuntime->Count); + break; + } + case Track::Types::AudioVolume: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + const auto trackRuntime = track.GetRuntimeData(); + stream.WriteBytes(trackRuntime->Keyframes, sizeof(BezierCurveKeyframe) * trackRuntime->KeyframesCount); + break; + } + case Track::Types::Actor: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + break; + } + case Track::Types::Script: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + break; + } + case Track::Types::KeyframesProperty: + case Track::Types::ObjectReferenceProperty: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + const auto trackRuntime = track.GetRuntimeData(); + stream.WriteBytes(trackRuntime->PropertyName, trackData->PropertyNameLength + 1); + stream.WriteBytes(trackRuntime->PropertyTypeName, trackData->PropertyTypeNameLength + 1); + stream.WriteBytes(trackRuntime->Keyframes, trackRuntime->KeyframesSize); + break; + } + case Track::Types::CurveProperty: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + const auto trackRuntime = track.GetRuntimeData(); + stream.WriteBytes(trackRuntime->PropertyName, trackData->PropertyNameLength + 1); + stream.WriteBytes(trackRuntime->PropertyTypeName, trackData->PropertyTypeNameLength + 1); + const int32 keyframesDataSize = trackData->KeyframesCount * (sizeof(float) + trackData->ValueSize * 3); + stream.WriteBytes(trackRuntime->Keyframes, keyframesDataSize); + break; + } + case Track::Types::StringProperty: + { + const auto trackData = stream.Move(); + *trackData = *track.GetData(); + const auto trackRuntime = track.GetRuntimeData(); + stream.WriteBytes(trackRuntime->PropertyName, trackData->PropertyNameLength + 1); + stream.WriteBytes(trackRuntime->PropertyTypeName, trackData->PropertyTypeNameLength + 1); + const auto keyframesTimes = (float*)((byte*)trackRuntime + sizeof(StringPropertyTrack::Runtime)); + const auto keyframesLengths = (int32*)((byte*)keyframesTimes + sizeof(float) * trackRuntime->KeyframesCount); + const auto keyframesValues = (Char**)((byte*)keyframesLengths + sizeof(int32) * trackRuntime->KeyframesCount); + for (int32 j = 0; j < trackRuntime->KeyframesCount; j++) + { + stream.Write((float)keyframesTimes[j]); + stream.Write((int32)keyframesLengths[j]); + stream.WriteBytes(keyframesValues[j], keyframesLengths[j] * sizeof(Char)); + } + break; + } + case Track::Types::StructProperty: + case Track::Types::ObjectProperty: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + const auto trackRuntime = track.GetRuntimeData(); + stream.WriteBytes(trackRuntime->PropertyName, trackData->PropertyNameLength + 1); + stream.WriteBytes(trackRuntime->PropertyTypeName, trackData->PropertyTypeNameLength + 1); + break; + } + case Track::Types::Event: + { + const auto trackRuntime = track.GetRuntimeData(); + int32 tmp = StringUtils::Length(trackRuntime->EventName); + stream.Write((int32)trackRuntime->EventParamsCount); + stream.Write((int32)trackRuntime->EventsCount); + stream.Write((int32)tmp); + stream.WriteBytes(trackRuntime->EventName, tmp + 1); + for (int j = 0; j < trackRuntime->EventParamsCount; j++) + { + stream.Write((int32)trackRuntime->EventParamSizes[j]); + stream.Write((int32)tmp); + stream.WriteBytes(trackRuntime->EventParamTypes[j], tmp + 1); + } + stream.WriteBytes(trackRuntime->DataBegin, trackRuntime->EventsCount * (sizeof(float) + trackRuntime->EventParamsSize)); + break; + } + case Track::Types::CameraCut: + { + auto trackData = stream.Move(); + *trackData = *track.GetData(); + const auto trackRuntime = track.GetRuntimeData(); + stream.Write((int32)trackRuntime->Count); + stream.WriteBytes(trackRuntime->Media, sizeof(Media) * trackRuntime->Count); + break; + } + default: + break; + } + } +} + +bool SceneAnimation::SaveTimeline(const BytesContainer& data) const +{ + if (OnCheckSave()) + return true; ScopeLock lock(Locker); // Release all chunks @@ -71,10 +219,6 @@ bool SceneAnimation::SaveTimeline(const BytesContainer& data) return false; } -#endif - -#if USE_EDITOR - void SceneAnimation::GetReferences(Array& assets, Array& files) const { // Base @@ -88,6 +232,18 @@ void SceneAnimation::GetReferences(Array& assets, Array& files) co } } +bool SceneAnimation::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + MemoryWriteStream stream; + SaveData(stream); + BytesContainer data; + data.Link(ToSpan(stream)); + return SaveTimeline(data); +} + #endif Asset::LoadResult SceneAnimation::load() @@ -117,6 +273,7 @@ Asset::LoadResult SceneAnimation::load() { case 2: // [Deprecated in 2020 expires on 03.09.2023] case 3: // [Deprecated on 03.09.2021 expires on 03.09.2023] + MARK_CONTENT_DEPRECATED(); case 4: { stream.Read(FramesPerSecond); diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimation.h b/Source/Engine/Animations/SceneAnimations/SceneAnimation.h index 9232589b5..af2dec366 100644 --- a/Source/Engine/Animations/SceneAnimations/SceneAnimation.h +++ b/Source/Engine/Animations/SceneAnimations/SceneAnimation.h @@ -415,6 +415,10 @@ private: BytesContainer _data; MemoryWriteStream _runtimeData; +#if USE_EDITOR + void SaveData(MemoryWriteStream& stream) const; +#endif + public: /// /// The frames amount per second of the timeline animation. @@ -457,7 +461,7 @@ public: /// It cannot be used by virtual assets. /// The timeline data container. /// true failed to save data; otherwise, false. - API_FUNCTION() bool SaveTimeline(const BytesContainer& data); + API_FUNCTION() bool SaveTimeline(const BytesContainer& data) const; #endif @@ -465,6 +469,7 @@ public: // [BinaryAsset] #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp index 961ea7ed2..0a8672e69 100644 --- a/Source/Engine/Content/Asset.cpp +++ b/Source/Engine/Content/Asset.cpp @@ -2,6 +2,7 @@ #include "Asset.h" #include "Content.h" +#include "Deprecated.h" #include "SoftAssetReference.h" #include "Cache/AssetsCache.h" #include "Loading/Tasks/LoadAssetTask.h" @@ -10,6 +11,26 @@ #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Scripting/ManagedCLR/MCore.h" #include "Engine/Threading/MainThreadTask.h" +#include "Engine/Threading/ThreadLocal.h" + +#if USE_EDITOR + +ThreadLocal ContentDeprecatedFlags; + +void ContentDeprecated::Mark() +{ + ContentDeprecatedFlags.Set(true); +} + +bool ContentDeprecated::Clear(bool newValue) +{ + auto& flag = ContentDeprecatedFlags.Get(); + bool result = flag; + flag = newValue; + return result; +} + +#endif AssetReferenceBase::~AssetReferenceBase() { @@ -340,6 +361,7 @@ void Asset::Reload() // Virtual assets are memory-only so reloading them makes no sense if (IsVirtual()) return; + PROFILE_CPU_NAMED("Asset.Reload"); // It's better to call it from the main thread if (IsInMainThread()) @@ -476,6 +498,12 @@ Array Asset::GetReferences() const return result; } +bool Asset::Save(const StringView& path) +{ + LOG(Warning, "Asset type '{}' does not support saving.", GetTypeName()); + return true; +} + #endif void Asset::DeleteManaged() @@ -524,12 +552,21 @@ bool Asset::onLoad(LoadAssetTask* task) // Load asset LoadResult result; +#if USE_EDITOR + auto& deprecatedFlag = ContentDeprecatedFlags.Get(); + bool prevDeprecated = deprecatedFlag; + deprecatedFlag = false; +#endif { PROFILE_CPU_ASSET(this); result = loadAsset(); } const bool isLoaded = result == LoadResult::Ok; const bool failed = !isLoaded; +#if USE_EDITOR + const bool isDeprecated = deprecatedFlag; + deprecatedFlag = prevDeprecated; +#endif Platform::AtomicStore(&_loadState, (int64)(isLoaded ? LoadState::Loaded : LoadState::LoadFailed)); if (failed) { @@ -550,6 +587,19 @@ bool Asset::onLoad(LoadAssetTask* task) // This allows to reduce mutexes and locks (max one frame delay isn't hurting but provides more safety) Content::onAssetLoaded(this); } + +#if USE_EDITOR + // Auto-save deprecated assets to get rid of data in an old format + if (isDeprecated && isLoaded) + { + PROFILE_CPU_NAMED("Asset.Save"); + LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString()); + if (Save()) + { + LOG(Error, "Failed to resave asset '{}'", ToString()); + } + } +#endif return failed; } @@ -595,3 +645,26 @@ void Asset::onUnload_MainThread() loadingTask->Cancel(); } } + +#if USE_EDITOR + +bool Asset::OnCheckSave(const StringView& path) const +{ + if (LastLoadFailed()) + { + LOG(Warning, "Saving asset that failed to load."); + } + if (WaitForLoaded()) + { + LOG(Error, "Asset loading failed. Cannot save it."); + return true; + } + if (IsVirtual() && path.IsEmpty()) + { + LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); + return true; + } + return false; +} + +#endif diff --git a/Source/Engine/Content/Asset.h b/Source/Engine/Content/Asset.h index de79a640b..a82c1ce23 100644 --- a/Source/Engine/Content/Asset.h +++ b/Source/Engine/Content/Asset.h @@ -75,7 +75,7 @@ public: EventType OnUnloaded; /// - /// General purpose mutex for an asset object. Should guard most of asset functionalities to be secure. + /// General purpose mutex for an asset object. Should guard most of the asset functionalities to be secure. /// CriticalSection Locker; @@ -209,6 +209,13 @@ public: /// /// The collection of the asset ids referenced by this asset. API_FUNCTION() Array GetReferences() const; + + /// + /// Saves this asset to the file. Supported only in Editor. + /// + /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. + /// True when cannot save data, otherwise false. + API_FUNCTION(Sealed) virtual bool Save(const StringView& path = StringView::Empty); #endif /// @@ -253,6 +260,7 @@ protected: virtual void onLoaded_MainThread(); virtual void onUnload_MainThread(); #if USE_EDITOR + bool OnCheckSave(const StringView& path = StringView::Empty) const; virtual void onRename(const StringView& newPath) = 0; #endif diff --git a/Source/Engine/Content/Assets/Animation.cpp b/Source/Engine/Content/Assets/Animation.cpp index 88c13277a..473aef700 100644 --- a/Source/Engine/Content/Assets/Animation.cpp +++ b/Source/Engine/Content/Assets/Animation.cpp @@ -226,16 +226,8 @@ void Animation::LoadTimeline(BytesContainer& result) const bool Animation::SaveTimeline(BytesContainer& data) { - // Wait for asset to be loaded or don't if last load failed (eg. by shader source compilation error) - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } ScopeLock lock(Locker); MemoryReadStream stream(data.Get(), data.Length()); @@ -401,17 +393,8 @@ bool Animation::SaveTimeline(BytesContainer& data) bool Animation::Save(const StringView& path) { - // Wait for asset to be loaded or don't if last load failed (eg. by shader source compilation error) - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - ScopeLock lock(Locker); // Serialize animation data to the stream diff --git a/Source/Engine/Content/Assets/Animation.h b/Source/Engine/Content/Assets/Animation.h index 68e1f9c5e..02888420d 100644 --- a/Source/Engine/Content/Assets/Animation.h +++ b/Source/Engine/Content/Assets/Animation.h @@ -138,17 +138,10 @@ public: /// /// Saves the serialized timeline data to the asset as animation. /// - /// The cannot be used by virtual assets. + /// This cannot be used by virtual assets. /// The timeline data container. /// true failed to save data; otherwise, false. API_FUNCTION() bool SaveTimeline(BytesContainer& data); - - /// - /// Saves the animation data to the asset. Supported only in Editor. - /// - /// The cannot be used by virtual assets. - /// true failed to save data; otherwise, false. - bool Save(const StringView& path = StringView::Empty); #endif private: @@ -161,6 +154,7 @@ public: // [BinaryAsset] #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif uint64 GetMemoryUsage() const override; void OnScriptingDispose() override; diff --git a/Source/Engine/Content/Assets/AnimationGraph.cpp b/Source/Engine/Content/Assets/AnimationGraph.cpp index 8a8570435..ecd1e71af 100644 --- a/Source/Engine/Content/Assets/AnimationGraph.cpp +++ b/Source/Engine/Content/Assets/AnimationGraph.cpp @@ -127,7 +127,7 @@ bool AnimationGraph::InitAsAnimation(SkinnedModel* baseModel, Animation* anim, b return Graph.Load(&readStream, USE_EDITOR); } -BytesContainer AnimationGraph::LoadSurface() +BytesContainer AnimationGraph::LoadSurface() const { if (!IsVirtual() && WaitForLoaded()) return BytesContainer(); @@ -160,19 +160,10 @@ BytesContainer AnimationGraph::LoadSurface() #if USE_EDITOR -bool AnimationGraph::SaveSurface(BytesContainer& data) +bool AnimationGraph::SaveSurface(const BytesContainer& data) { - // Wait for asset to be loaded or don't if last load failed - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); if (IsVirtual()) @@ -228,4 +219,17 @@ void AnimationGraph::GetReferences(Array& assets, Array& files) co Graph.GetReferences(assets); } +bool AnimationGraph::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + MemoryWriteStream writeStream; + if (Graph.Save(&writeStream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(writeStream)); + return SaveSurface(data); +} + #endif diff --git a/Source/Engine/Content/Assets/AnimationGraph.h b/Source/Engine/Content/Assets/AnimationGraph.h index 77468e448..00379d32e 100644 --- a/Source/Engine/Content/Assets/AnimationGraph.h +++ b/Source/Engine/Content/Assets/AnimationGraph.h @@ -45,7 +45,7 @@ public: /// Tries to load surface graph from the asset. /// /// The surface data or empty if failed to load it. - API_FUNCTION() BytesContainer LoadSurface(); + API_FUNCTION() BytesContainer LoadSurface() const; #if USE_EDITOR @@ -54,7 +54,7 @@ public: /// /// Stream with graph data. /// True if cannot save it, otherwise false. - API_FUNCTION() bool SaveSurface(BytesContainer& data); + API_FUNCTION() bool SaveSurface(const BytesContainer& data); private: void FindDependencies(AnimGraphBase* graph); @@ -65,6 +65,7 @@ public: // [BinaryAsset] #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Content/Assets/AnimationGraphFunction.cpp b/Source/Engine/Content/Assets/AnimationGraphFunction.cpp index 383ecc938..ab857976e 100644 --- a/Source/Engine/Content/Assets/AnimationGraphFunction.cpp +++ b/Source/Engine/Content/Assets/AnimationGraphFunction.cpp @@ -4,6 +4,9 @@ #include "Engine/Core/Log.h" #include "Engine/Core/Types/DataContainer.h" #include "Engine/Serialization/MemoryReadStream.h" +#if USE_EDITOR +#include "Engine/Serialization/MemoryWriteStream.h" +#endif #include "Engine/Content/Factories/BinaryAssetFactory.h" #include "Engine/Threading/Threading.h" @@ -84,19 +87,10 @@ void AnimationGraphFunction::GetSignature(Array> } } -bool AnimationGraphFunction::SaveSurface(const BytesContainer& data) +bool AnimationGraphFunction::SaveSurface(const BytesContainer& data) const { - // Wait for asset to be loaded or don't if last load failed - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Set Visject Surface data @@ -185,3 +179,24 @@ void AnimationGraphFunction::ProcessGraphForSignature(AnimGraphBase* graph, bool } } } + +#if USE_EDITOR + +bool AnimationGraphFunction::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + AnimGraph graph(const_cast(this), true); + MemoryReadStream readStream(GraphData.Get(), GraphData.Length()); + if (graph.Load(&readStream, true)) + return true; + MemoryWriteStream writeStream; + if (graph.Save(&writeStream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(writeStream)); + return SaveSurface(data); +} + +#endif diff --git a/Source/Engine/Content/Assets/AnimationGraphFunction.h b/Source/Engine/Content/Assets/AnimationGraphFunction.h index 42956bc84..0d456bce6 100644 --- a/Source/Engine/Content/Assets/AnimationGraphFunction.h +++ b/Source/Engine/Content/Assets/AnimationGraphFunction.h @@ -53,13 +53,19 @@ public: /// /// The surface graph data. /// True if cannot save it, otherwise false. - API_FUNCTION() bool SaveSurface(const BytesContainer& data); + API_FUNCTION() bool SaveSurface(const BytesContainer& data) const; #endif private: void ProcessGraphForSignature(AnimGraphBase* graph, bool canUseOutputs); +public: + // [BinaryAsset] +#if USE_EDITOR + bool Save(const StringView& path = StringView::Empty) override; +#endif + protected: // [BinaryAsset] LoadResult load() override; diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp index 9b0f537af..f7d800034 100644 --- a/Source/Engine/Content/Assets/Material.cpp +++ b/Source/Engine/Content/Assets/Material.cpp @@ -191,12 +191,13 @@ Asset::LoadResult Material::load() auto lock = Storage->Lock(); // Prepare + const String name = ToString(); MaterialGenerator generator; generator.Error.Bind(&OnGeneratorError); if (_shaderHeader.Material.GraphVersion != MATERIAL_GRAPH_VERSION) - LOG(Info, "Converting material \'{0}\', from version {1} to {2}...", ToString(), _shaderHeader.Material.GraphVersion, MATERIAL_GRAPH_VERSION); + LOG(Info, "Converting material \'{0}\', from version {1} to {2}...", name, _shaderHeader.Material.GraphVersion, MATERIAL_GRAPH_VERSION); else - LOG(Info, "Updating material \'{0}\'...", ToString()); + LOG(Info, "Updating material \'{0}\'...", name); // Load or create material surface MaterialLayer* layer; @@ -205,7 +206,7 @@ Asset::LoadResult Material::load() // Load graph if (LoadChunks(GET_CHUNK_FLAG(SHADER_FILE_CHUNK_VISJECT_SURFACE))) { - LOG(Warning, "Cannot load \'{0}\' data from chunk {1}.", ToString(), SHADER_FILE_CHUNK_VISJECT_SURFACE); + LOG(Warning, "Cannot load \'{0}\' data from chunk {1}.", name, SHADER_FILE_CHUNK_VISJECT_SURFACE); return LoadResult::Failed; } @@ -214,7 +215,19 @@ Asset::LoadResult Material::load() MemoryReadStream stream(surfaceChunk->Get(), surfaceChunk->Size()); // Load layer - layer = MaterialLayer::Load(GetID(), &stream, _shaderHeader.Material.Info, ToString()); + layer = MaterialLayer::Load(GetID(), &stream, _shaderHeader.Material.Info, name); + if (ContentDeprecated::Clear()) + { + // If encountered any deprecated data when loading graph then serialize it + MaterialGraph graph; + MemoryWriteStream writeStream(1024); + stream.SetPosition(0); + if (!graph.Load(&stream, true) && !graph.Save(&writeStream, true)) + { + surfaceChunk->Data.Copy(ToSpan(writeStream)); + ContentDeprecated::Clear(); + } + } } else { @@ -245,7 +258,7 @@ Asset::LoadResult Material::load() MaterialInfo info = _shaderHeader.Material.Info; if (generator.Generate(source, info, materialParamsChunk->Data)) { - LOG(Error, "Cannot generate material source code for \'{0}\'. Please see log for more info.", ToString()); + LOG(Error, "Cannot generate material source code for \'{0}\'. Please see log for more info.", name); return LoadResult::Failed; } @@ -282,9 +295,9 @@ Asset::LoadResult Material::load() // Save to file #if USE_EDITOR - if (Save()) + if (SaveShaderAsset()) { - LOG(Error, "Cannot save \'{0}\'", ToString()); + LOG(Error, "Cannot save \'{0}\'", name); return LoadResult::Failed; } #endif @@ -505,6 +518,25 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options) #endif } +bool Material::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + BytesContainer existingData = LoadSurface(true); + if (existingData.IsInvalid()) + return true; + MaterialGraph graph; + MemoryWriteStream writeStream(existingData.Length()); + MemoryReadStream readStream(existingData); + if (graph.Load(&readStream, true) || graph.Save(&writeStream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(writeStream)); + auto materialInfo = _shaderHeader.Material.Info; + return SaveSurface(data, materialInfo); +} + #endif BytesContainer Material::LoadSurface(bool createDefaultIfMissing) @@ -555,17 +587,8 @@ BytesContainer Material::LoadSurface(bool createDefaultIfMissing) bool Material::SaveSurface(const BytesContainer& data, const MaterialInfo& info) { - // Wait for asset to be loaded or don't if last load failed (eg. by shader source compilation error) - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Release all chunks @@ -582,7 +605,7 @@ bool Material::SaveSurface(const BytesContainer& data, const MaterialInfo& info) ASSERT(visjectSurfaceChunk != nullptr); visjectSurfaceChunk->Data.Copy(data); - if (Save()) + if (SaveShaderAsset()) { LOG(Error, "Cannot save \'{0}\'", ToString()); return true; diff --git a/Source/Engine/Content/Assets/Material.h b/Source/Engine/Content/Assets/Material.h index e8f398e3d..8c8871115 100644 --- a/Source/Engine/Content/Assets/Material.h +++ b/Source/Engine/Content/Assets/Material.h @@ -13,6 +13,7 @@ class MaterialShader; API_CLASS(NoSpawn) class FLAXENGINE_API Material : public ShaderAssetTypeBase { DECLARE_BINARY_ASSET_HEADER(Material, ShadersSerializedVersion); + private: MaterialShader* _materialShader = nullptr; @@ -25,7 +26,6 @@ public: API_FUNCTION() BytesContainer LoadSurface(bool createDefaultIfMissing); #if USE_EDITOR - /// /// Updates the material surface (save new one, discard cached data, reload asset). /// @@ -33,7 +33,6 @@ public: /// The material info structure. /// True if cannot save it, otherwise false. API_FUNCTION() bool SaveSurface(const BytesContainer& data, const MaterialInfo& info); - #endif public: @@ -52,6 +51,7 @@ public: // [ShaderAssetBase] #if USE_EDITOR void InitCompilationOptions(ShaderCompilationOptions& options) override; + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Content/Assets/MaterialFunction.cpp b/Source/Engine/Content/Assets/MaterialFunction.cpp index af73e2070..5b06180ea 100644 --- a/Source/Engine/Content/Assets/MaterialFunction.cpp +++ b/Source/Engine/Content/Assets/MaterialFunction.cpp @@ -6,6 +6,7 @@ #include "Engine/Core/Log.h" #include "Engine/Core/Types/DataContainer.h" #include "Engine/Serialization/MemoryReadStream.h" +#include "Engine/Serialization/MemoryWriteStream.h" #endif #include "Engine/Content/Factories/BinaryAssetFactory.h" @@ -24,7 +25,7 @@ Asset::LoadResult MaterialFunction::load() if (!surfaceChunk || !surfaceChunk->IsLoaded()) return LoadResult::MissingDataChunk; MemoryReadStream stream(surfaceChunk->Get(), surfaceChunk->Size()); - if (Graph.Load(&stream, false)) + if (Graph.Load(&stream, USE_EDITOR)) return LoadResult::Failed; // Cache input and output nodes @@ -89,7 +90,7 @@ BytesContainer MaterialFunction::LoadSurface() return result; } -bool MaterialFunction::LoadSurface(MaterialGraph& graph) +bool MaterialFunction::LoadSurface(MaterialGraph& graph, bool loadMeta) { if (WaitForLoaded()) return true; @@ -100,7 +101,7 @@ bool MaterialFunction::LoadSurface(MaterialGraph& graph) { const auto surfaceChunk = GetChunk(0); MemoryReadStream stream(surfaceChunk->Get(), surfaceChunk->Size()); - return graph.Load(&stream, false); + return graph.Load(&stream, loadMeta); } } return true; @@ -128,19 +129,10 @@ void MaterialFunction::GetSignature(Array>& type #if USE_EDITOR -bool MaterialFunction::SaveSurface(BytesContainer& data) +bool MaterialFunction::SaveSurface(const BytesContainer& data) const { - // Wait for asset to be loaded or don't if last load failed - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Set Visject Surface data @@ -160,4 +152,17 @@ bool MaterialFunction::SaveSurface(BytesContainer& data) return false; } +bool MaterialFunction::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + MemoryWriteStream writeStream; + if (Graph.Save(&writeStream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(writeStream)); + return SaveSurface(data); +} + #endif diff --git a/Source/Engine/Content/Assets/MaterialFunction.h b/Source/Engine/Content/Assets/MaterialFunction.h index 824d956fd..bb175bc63 100644 --- a/Source/Engine/Content/Assets/MaterialFunction.h +++ b/Source/Engine/Content/Assets/MaterialFunction.h @@ -11,9 +11,9 @@ API_CLASS(NoSpawn) class FLAXENGINE_API MaterialFunction : public BinaryAsset { DECLARE_BINARY_ASSET_HEADER(MaterialFunction, 1); + public: #if COMPILE_WITH_MATERIAL_GRAPH - /// /// The loaded material function graph. /// @@ -39,8 +39,9 @@ public: /// Tries to load surface graph from the asset. /// /// The graph to load. + /// True if load metadata. /// True if failed, otherwise false. - bool LoadSurface(MaterialGraph& graph); + bool LoadSurface(MaterialGraph& graph, bool loadMeta = false); // Gets the function signature for Visject Surface editor. API_FUNCTION() void GetSignature(API_PARAM(Out) Array>& types, API_PARAM(Out) Array>& names); @@ -48,14 +49,18 @@ public: #endif #if USE_EDITOR - /// /// Updates the material graph surface (save new one, discards cached data, reloads asset). /// /// The surface graph data. /// True if cannot save it, otherwise false. - API_FUNCTION() bool SaveSurface(BytesContainer& data); + API_FUNCTION() bool SaveSurface(const BytesContainer& data) const; +#endif +public: + // [BinaryAsset] +#if USE_EDITOR + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp index 28bbf8a8c..8e8e58d3a 100644 --- a/Source/Engine/Content/Assets/MaterialInstance.cpp +++ b/Source/Engine/Content/Assets/MaterialInstance.cpp @@ -310,18 +310,8 @@ void MaterialInstance::ResetParameters() bool MaterialInstance::Save(const StringView& path) { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } - ScopeLock lock(Locker); // Save instance data diff --git a/Source/Engine/Content/Assets/MaterialInstance.h b/Source/Engine/Content/Assets/MaterialInstance.h index 9d87cdf5b..89cb534da 100644 --- a/Source/Engine/Content/Assets/MaterialInstance.h +++ b/Source/Engine/Content/Assets/MaterialInstance.h @@ -33,18 +33,6 @@ public: /// API_FUNCTION() void ResetParameters(); -#if USE_EDITOR - - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// If you use saving with the GPU mesh data then the call has to be provided from the thread other than the main game thread. - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if cannot save data, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty); - -#endif - private: void OnBaseSet(); void OnBaseUnset(); @@ -56,6 +44,7 @@ public: bool IsMaterialInstance() const override; #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif // [IMaterial] diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp index 915066fc2..c622dac06 100644 --- a/Source/Engine/Content/Assets/Model.cpp +++ b/Source/Engine/Content/Assets/Model.cpp @@ -400,7 +400,7 @@ bool Model::LoadHeader(ReadStream& stream, byte& headerVersion) #if USE_EDITOR -bool Model::SaveHeader(WriteStream& stream) +bool Model::SaveHeader(WriteStream& stream) const { if (ModelBase::SaveHeader(stream)) return true; @@ -457,7 +457,7 @@ bool Model::SaveHeader(WriteStream& stream, const ModelData& modelData) return false; } -bool Model::Save(bool withMeshDataFromGpu, Function& getChunk) +bool Model::Save(bool withMeshDataFromGpu, Function& getChunk) const { if (ModelBase::Save(withMeshDataFromGpu, getChunk)) return true; diff --git a/Source/Engine/Content/Assets/Model.h b/Source/Engine/Content/Assets/Model.h index aedc23dbf..e7c585af2 100644 --- a/Source/Engine/Content/Assets/Model.h +++ b/Source/Engine/Content/Assets/Model.h @@ -271,9 +271,9 @@ private: bool LoadHeader(ReadStream& stream, byte& headerVersion); #if USE_EDITOR friend class ImportModel; - bool SaveHeader(WriteStream& stream) override; + bool SaveHeader(WriteStream& stream) const override; static bool SaveHeader(WriteStream& stream, const ModelData& modelData); - bool Save(bool withMeshDataFromGpu, Function& getChunk) override; + bool Save(bool withMeshDataFromGpu, Function& getChunk) const override; #endif public: diff --git a/Source/Engine/Content/Assets/ModelBase.cpp b/Source/Engine/Content/Assets/ModelBase.cpp index b194d9861..40971bae0 100644 --- a/Source/Engine/Content/Assets/ModelBase.cpp +++ b/Source/Engine/Content/Assets/ModelBase.cpp @@ -218,16 +218,8 @@ void ModelBase::GetLODData(int32 lodIndex, BytesContainer& data) const bool ModelBase::Save(bool withMeshDataFromGpu, const StringView& path) { // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } if (withMeshDataFromGpu && IsInMainThread()) { LOG(Error, "To save model with GPU mesh buffers it needs to be called from the other thread (not the main thread)."); @@ -238,7 +230,6 @@ bool ModelBase::Save(bool withMeshDataFromGpu, const StringView& path) LOG(Error, "To save virtual model asset you need to specify 'withMeshDataFromGpu' (it has no other storage container to get data)."); return true; } - ScopeLock lock(Locker); // Use a temporary chunks for data storage for virtual assets @@ -399,7 +390,7 @@ bool ModelBase::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase* m #if USE_EDITOR -bool ModelBase::SaveHeader(WriteStream& stream) +bool ModelBase::SaveHeader(WriteStream& stream) const { // Basic info static_assert(MODEL_HEADER_VERSION == 2, "Update code"); @@ -852,7 +843,7 @@ bool ModelBase::SaveMesh(WriteStream& stream, const MeshBase* mesh) const return false; } -bool ModelBase::Save(bool withMeshDataFromGpu, Function& getChunk) +bool ModelBase::Save(bool withMeshDataFromGpu, Function& getChunk) const { return false; } @@ -876,6 +867,11 @@ void ModelBase::GetReferences(Array& assets, Array& files) const assets.Add(slot.Material.GetID()); } +bool ModelBase::Save(const StringView& path) +{ + return Save(false, path); +} + #endif int32 ModelBase::GetCurrentResidency() const diff --git a/Source/Engine/Content/Assets/ModelBase.h b/Source/Engine/Content/Assets/ModelBase.h index 56e07911d..4044f0a2f 100644 --- a/Source/Engine/Content/Assets/ModelBase.h +++ b/Source/Engine/Content/Assets/ModelBase.h @@ -331,12 +331,12 @@ protected: virtual bool LoadMesh(class MemoryReadStream& stream, byte meshVersion, MeshBase* mesh, MeshData* dataIfReadOnly = nullptr); bool LoadHeader(ReadStream& stream, byte& headerVersion); #if USE_EDITOR - virtual bool SaveHeader(WriteStream& stream); + virtual bool SaveHeader(WriteStream& stream) const; static bool SaveHeader(WriteStream& stream, const class ModelData& modelData); bool SaveLOD(WriteStream& stream, int32 lodIndex) const; static bool SaveLOD(WriteStream& stream, const ModelData& modelData, int32 lodIndex, bool(saveMesh)(WriteStream& stream, const ModelData& modelData, int32 lodIndex, int32 meshIndex) = nullptr); virtual bool SaveMesh(WriteStream& stream, const MeshBase* mesh) const; - virtual bool Save(bool withMeshDataFromGpu, Function& getChunk); + virtual bool Save(bool withMeshDataFromGpu, Function& getChunk) const; #endif public: @@ -344,6 +344,7 @@ public: void CancelStreaming() override; #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif // [StreamableResource] diff --git a/Source/Engine/Content/Assets/RawDataAsset.cpp b/Source/Engine/Content/Assets/RawDataAsset.cpp index f567abb1f..5c39683da 100644 --- a/Source/Engine/Content/Assets/RawDataAsset.cpp +++ b/Source/Engine/Content/Assets/RawDataAsset.cpp @@ -18,18 +18,8 @@ RawDataAsset::RawDataAsset(const SpawnParams& params, const AssetInfo* info) bool RawDataAsset::Save(const StringView& path) { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } - ScopeLock lock(Locker); bool result; diff --git a/Source/Engine/Content/Assets/RawDataAsset.h b/Source/Engine/Content/Assets/RawDataAsset.h index 9da6e258c..813e0ab9e 100644 --- a/Source/Engine/Content/Assets/RawDataAsset.h +++ b/Source/Engine/Content/Assets/RawDataAsset.h @@ -16,20 +16,11 @@ public: /// API_FIELD() Array Data; -public: -#if USE_EDITOR - - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if failed, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty); - -#endif - public: // [BinaryAsset] +#if USE_EDITOR + bool Save(const StringView& path = StringView::Empty) override; +#endif uint64 GetMemoryUsage() const override; protected: diff --git a/Source/Engine/Content/Assets/SkeletonMask.cpp b/Source/Engine/Content/Assets/SkeletonMask.cpp index 48fd71678..aaeb01434 100644 --- a/Source/Engine/Content/Assets/SkeletonMask.cpp +++ b/Source/Engine/Content/Assets/SkeletonMask.cpp @@ -66,18 +66,8 @@ const BitArray<>& SkeletonMask::GetNodesMask() bool SkeletonMask::Save(const StringView& path) { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } - ScopeLock lock(Locker); // Write data diff --git a/Source/Engine/Content/Assets/SkeletonMask.h b/Source/Engine/Content/Assets/SkeletonMask.h index f14975b37..2a136fa03 100644 --- a/Source/Engine/Content/Assets/SkeletonMask.h +++ b/Source/Engine/Content/Assets/SkeletonMask.h @@ -51,17 +51,6 @@ public: /// The constant reference to the skeleton nodes mask. API_PROPERTY() const BitArray<>& GetNodesMask(); -#if USE_EDITOR - - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if cannot save data, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty); - -#endif - private: void OnSkeletonUnload(); @@ -73,6 +62,7 @@ public: BinaryAsset::GetReferences(assets, files); assets.Add(Skeleton.GetID()); } + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Content/Assets/SkinnedModel.cpp b/Source/Engine/Content/Assets/SkinnedModel.cpp index c614dc2c0..1713c157f 100644 --- a/Source/Engine/Content/Assets/SkinnedModel.cpp +++ b/Source/Engine/Content/Assets/SkinnedModel.cpp @@ -661,7 +661,7 @@ bool SkinnedModel::LoadHeader(ReadStream& stream, byte& headerVersion) #if USE_EDITOR -bool SkinnedModel::SaveHeader(WriteStream& stream) +bool SkinnedModel::SaveHeader(WriteStream& stream) const { if (ModelBase::SaveHeader(stream)) return true; diff --git a/Source/Engine/Content/Assets/SkinnedModel.h b/Source/Engine/Content/Assets/SkinnedModel.h index c90cb5362..03917d732 100644 --- a/Source/Engine/Content/Assets/SkinnedModel.h +++ b/Source/Engine/Content/Assets/SkinnedModel.h @@ -299,7 +299,7 @@ private: bool LoadHeader(ReadStream& stream, byte& headerVersion); #if USE_EDITOR friend class ImportModel; - bool SaveHeader(WriteStream& stream) override; + bool SaveHeader(WriteStream& stream) const override; static bool SaveHeader(WriteStream& stream, const ModelData& modelData); bool SaveMesh(WriteStream& stream, const MeshBase* mesh) const override; static bool SaveMesh(WriteStream& stream, const ModelData& modelData, int32 lodIndex, int32 meshIndex); diff --git a/Source/Engine/Content/Assets/Texture.cpp b/Source/Engine/Content/Assets/Texture.cpp index 7a77ea130..e0c2f386a 100644 --- a/Source/Engine/Content/Assets/Texture.cpp +++ b/Source/Engine/Content/Assets/Texture.cpp @@ -29,24 +29,19 @@ bool Texture::IsNormalMap() const #if USE_EDITOR +bool Texture::Save(const StringView& path) +{ + return Save(path, nullptr); +} + bool Texture::Save(const StringView& path, const InitData* customData) { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } - ScopeLock lock(Locker); AssetInitData data; - const auto texture = StreamingTexture(); + const class StreamingTexture* texture = StreamingTexture(); // Use a temporary chunks for data storage for virtual assets FlaxChunk* tmpChunks[ASSET_FILE_DATA_CHUNKS]; diff --git a/Source/Engine/Content/Assets/Texture.h b/Source/Engine/Content/Assets/Texture.h index 9e9596ce5..47f0c6528 100644 --- a/Source/Engine/Content/Assets/Texture.h +++ b/Source/Engine/Content/Assets/Texture.h @@ -23,17 +23,6 @@ API_CLASS(NoSpawn) class FLAXENGINE_API Texture : public TextureBase public: #if USE_EDITOR - - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if cannot save data, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty) - { - return Save(path, nullptr); - } - /// /// Saves this asset to the file. Supported only in Editor. /// @@ -41,7 +30,6 @@ public: /// The custom texture data container. Can be used to override the data stored in the asset. Use null to ignore this argument. /// True if cannot save data, otherwise false. bool Save(const StringView& path, const InitData* customData); - #endif /// @@ -60,4 +48,10 @@ public: /// True if generate mipmaps for the imported texture. /// The loaded texture (virtual asset) or null if fails. API_FUNCTION() static Texture* FromFile(const StringView& path, bool generateMips = false); + +public: + // [TextureBase] +#if USE_EDITOR + bool Save(const StringView& path = StringView::Empty) override; +#endif }; diff --git a/Source/Engine/Content/Assets/VisualScript.cpp b/Source/Engine/Content/Assets/VisualScript.cpp index c8b0fbf7e..f5ff9ca58 100644 --- a/Source/Engine/Content/Assets/VisualScript.cpp +++ b/Source/Engine/Content/Assets/VisualScript.cpp @@ -2,6 +2,7 @@ #include "VisualScript.h" #include "Engine/Core/Log.h" +#include "Engine/Core/Types/Span.h" #include "Engine/Core/Types/DataContainer.h" #include "Engine/Content/Content.h" #include "Engine/Content/Factories/BinaryAssetFactory.h" @@ -1303,6 +1304,23 @@ VisualScript::VisualScript(const SpawnParams& params, const AssetInfo* info) { } +#if USE_EDITOR + +bool VisualScript::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + MemoryWriteStream writeStream; + if (Graph.Save(&writeStream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(writeStream)); + return SaveSurface(data, Meta); +} + +#endif + Asset::LoadResult VisualScript::load() { // Build Visual Script typename that is based on asset id @@ -2184,7 +2202,7 @@ const VisualScript::Field* VisualScript::FindField(const StringAnsiView& name) c return nullptr; } -BytesContainer VisualScript::LoadSurface() +BytesContainer VisualScript::LoadSurface() const { if (WaitForLoaded()) return BytesContainer(); @@ -2202,19 +2220,10 @@ BytesContainer VisualScript::LoadSurface() #if USE_EDITOR -bool VisualScript::SaveSurface(const BytesContainer& data, const Metadata& meta) +bool VisualScript::SaveSurface(const BytesContainer& data, const Metadata& meta) const { - // Wait for asset to be loaded or don't if last load failed - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Release all chunks diff --git a/Source/Engine/Content/Assets/VisualScript.h b/Source/Engine/Content/Assets/VisualScript.h index a69429db0..9e9de1007 100644 --- a/Source/Engine/Content/Assets/VisualScript.h +++ b/Source/Engine/Content/Assets/VisualScript.h @@ -246,7 +246,7 @@ public: /// Tries to load surface graph from the asset. /// /// The surface data or empty if failed to load it. - API_FUNCTION() BytesContainer LoadSurface(); + API_FUNCTION() BytesContainer LoadSurface() const; #if USE_EDITOR @@ -256,7 +256,7 @@ public: /// Stream with graph data. /// Script metadata. /// True if cannot save it, otherwise false. - API_FUNCTION() bool SaveSurface(const BytesContainer& data, API_PARAM(Ref) const Metadata& meta); + API_FUNCTION() bool SaveSurface(const BytesContainer& data, API_PARAM(Ref) const Metadata& meta) const; // Returns the amount of methods in the script. API_FUNCTION() int32 GetMethodsCount() const @@ -286,6 +286,7 @@ public: BinaryAsset::GetReferences(assets, files); Graph.GetReferences(assets); } + bool Save(const StringView& path = StringView::Empty) override; #endif protected: @@ -406,7 +407,6 @@ public: static Variant Invoke(VisualScript::Method* method, ScriptingObject* instance, Span parameters = Span()); #if VISUAL_SCRIPT_DEBUGGING - // Custom event that is called every time the Visual Script signal flows over the graph (including the data connections). Can be used to read nad visualize the Visual Script execution logic. static Action DebugFlow; @@ -420,6 +420,5 @@ public: /// The output value. Valid only if method returned true. /// True if could fetch the value, otherwise false. static bool Evaluate(VisualScript* script, ScriptingObject* instance, uint32 nodeId, uint32 boxId, Variant& result); - #endif }; diff --git a/Source/Engine/Content/BinaryAsset.cpp b/Source/Engine/Content/BinaryAsset.cpp index 228a93f29..6af0bd22f 100644 --- a/Source/Engine/Content/BinaryAsset.cpp +++ b/Source/Engine/Content/BinaryAsset.cpp @@ -189,7 +189,7 @@ bool BinaryAsset::HasDependenciesModified() const #endif -FlaxChunk* BinaryAsset::GetOrCreateChunk(int32 index) +FlaxChunk* BinaryAsset::GetOrCreateChunk(int32 index) const { if (IsVirtual()) // Virtual assets don't own storage container return nullptr; @@ -205,7 +205,7 @@ FlaxChunk* BinaryAsset::GetOrCreateChunk(int32 index) // Allocate ASSERT(Storage); - _header.Chunks[index] = chunk = Storage->AllocateChunk(); + const_cast(this)->_header.Chunks[index] = chunk = Storage->AllocateChunk(); if (chunk) chunk->RegisterUsage(); @@ -263,10 +263,9 @@ void BinaryAsset::GetChunkData(int32 index, BytesContainer& data) const data.Link(chunk->Data); } -bool BinaryAsset::LoadChunk(int32 chunkIndex) +bool BinaryAsset::LoadChunk(int32 chunkIndex) const { ASSERT(Storage); - const auto chunk = _header.Chunks[chunkIndex]; if (chunk != nullptr && chunk->IsMissing() @@ -275,19 +274,14 @@ bool BinaryAsset::LoadChunk(int32 chunkIndex) if (Storage->LoadAssetChunk(chunk)) return true; } - return false; } -bool BinaryAsset::LoadChunks(AssetChunksFlag chunks) +bool BinaryAsset::LoadChunks(AssetChunksFlag chunks) const { - ASSERT(Storage); - - // Check if skip loading if (chunks == 0) return false; - - // Load all missing marked chunks + ASSERT(Storage); for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++) { auto chunk = _header.Chunks[i]; @@ -300,7 +294,6 @@ bool BinaryAsset::LoadChunks(AssetChunksFlag chunks) return true; } } - return false; } diff --git a/Source/Engine/Content/BinaryAsset.h b/Source/Engine/Content/BinaryAsset.h index b3c4c8e02..6290a4800 100644 --- a/Source/Engine/Content/BinaryAsset.h +++ b/Source/Engine/Content/BinaryAsset.h @@ -166,7 +166,7 @@ public: /// /// The chunk index. /// Flax Chunk object (may be null if asset storage doesn't allow to add new chunks). - FlaxChunk* GetOrCreateChunk(int32 index); + FlaxChunk* GetOrCreateChunk(int32 index) const; /// /// Determines whether the specified chunk exists. @@ -238,14 +238,14 @@ public: /// /// The chunk index to load. /// True if failed, otherwise false. - bool LoadChunk(int32 chunkIndex); + bool LoadChunk(int32 chunkIndex) const; /// /// Loads the chunks (synchronous, blocks current thread). /// /// The chunks to load (packed in a flag). /// True if failed, otherwise false. - bool LoadChunks(AssetChunksFlag chunks); + bool LoadChunks(AssetChunksFlag chunks) const; #if USE_EDITOR /// diff --git a/Source/Engine/Content/Content.cpp b/Source/Engine/Content/Content.cpp index 08a3a5f3f..ad1126ec6 100644 --- a/Source/Engine/Content/Content.cpp +++ b/Source/Engine/Content/Content.cpp @@ -1156,19 +1156,14 @@ void Content::tryCallOnLoaded(Asset* asset) void Content::onAssetLoaded(Asset* asset) { // This is called by the asset on loading end - ASSERT(asset && asset->IsLoaded()); - ScopeLock locker(LoadedAssetsToInvokeLocker); - LoadedAssetsToInvoke.Add(asset); } void Content::onAssetUnload(Asset* asset) { // This is called by the asset on unloading - ScopeLock locker(AssetsLocker); - Assets.Remove(asset->GetID()); UnloadQueue.Remove(asset); LoadedAssetsToInvoke.Remove(asset); diff --git a/Source/Engine/Content/Deprecated.h b/Source/Engine/Content/Deprecated.h new file mode 100644 index 000000000..92cd3aa44 --- /dev/null +++ b/Source/Engine/Content/Deprecated.h @@ -0,0 +1,26 @@ +// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Core/Core.h" + +#if USE_EDITOR + +// Utility for marking content as deprecated when loading it in Editor. Used to auto-upgrade (by resaving) data during development in editor or during game cooking. +class FLAXENGINE_API ContentDeprecated +{ +public: + // Marks content as deprecated (for the current thread). + static void Mark(); + // Reads and clears deprecation flag (for the current thread). + static bool Clear(bool newValue = false); +}; + +// Marks content as deprecated (for the current thread). +#define MARK_CONTENT_DEPRECATED() ContentDeprecated::Mark() + +#else + +#define MARK_CONTENT_DEPRECATED() + +#endif diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp index 7f3a2db32..0cf2e17ea 100644 --- a/Source/Engine/Content/JsonAsset.cpp +++ b/Source/Engine/Content/JsonAsset.cpp @@ -161,25 +161,19 @@ void JsonAssetBase::GetReferences(const StringAnsiView& json, Array& asset FindIds(document, assets, files); } -bool JsonAssetBase::Save(const StringView& path) const +bool JsonAssetBase::Save(const StringView& path) { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } + PROFILE_CPU(); ScopeLock lock(Locker); // Serialize to json to the buffer rapidjson_flax::StringBuffer buffer; PrettyJsonWriter writerObj(buffer); + _isResaving = true; Save(writerObj); + _isResaving = false; // Save json to file if (File::WriteAllBytes(path.HasChars() ? path : StringView(GetPath()), (byte*)buffer.GetString(), (int32)buffer.GetSize())) @@ -193,12 +187,8 @@ bool JsonAssetBase::Save(const StringView& path) const bool JsonAssetBase::Save(JsonWriter& writer) const { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } ScopeLock lock(Locker); writer.StartObject(); @@ -348,6 +338,61 @@ uint64 JsonAsset::GetMemoryUsage() const return result; } +void JsonAsset::OnGetData(rapidjson_flax::StringBuffer& buffer) const +{ + if (Instance && InstanceType && _isResaving) + { + // Serialize instance object that was loaded (from potentially deprecated data, serialize method is always up to date) + const ScriptingType& type = InstanceType.GetType(); + PrettyJsonWriter writer(buffer); + bool got = false; + switch (type.Type) + { + case ScriptingTypes::Class: + case ScriptingTypes::Structure: + { + const ScriptingType::InterfaceImplementation* interface = type.GetInterface(ISerializable::TypeInitializer); + writer.StartObject(); + ((ISerializable*)((byte*)Instance + interface->VTableOffset))->Serialize(writer, nullptr); + got = true; + break; + } + case ScriptingTypes::Script: + { + writer.StartObject(); + ToInterface((ScriptingObject*)Instance)->Serialize(writer, nullptr); + got = true; + break; + } + } + if (got) + { + writer.EndObject(); + + // Parse json document (CreateInstance uses it to spawn object) + auto* self = const_cast(this); + { + PROFILE_CPU_NAMED("Json.Parse"); + self->Document.Parse(buffer.GetString(), buffer.GetSize()); + } + if (self->Document.HasParseError()) + { + self->Data = nullptr; + Log::JsonParseException(Document.GetParseError(), Document.GetErrorOffset()); + } + else + { + self->Data = &self->Document; + self->DataEngineBuild = FLAXENGINE_VERSION_BUILD; + } + + return; + } + } + + JsonAssetBase::OnGetData(buffer); +} + Asset::LoadResult JsonAsset::loadAsset() { const auto result = JsonAssetBase::loadAsset(); @@ -387,6 +432,7 @@ void JsonAsset::onLoaded_MainThread() JsonAssetBase::onLoaded_MainThread(); // Special case for Settings assets to flush them after edited and saved in Editor + // TODO: add interface for custom JsonAsset interaction of the instance class (eg. OnJsonLoaded, or similar to C# like OnDeserialized from Newtonsoft.Json) const StringAsANSI<> dataTypeNameAnsi(DataTypeName.Get(), DataTypeName.Length()); const auto typeHandle = Scripting::FindScriptingType(StringAnsiView(dataTypeNameAnsi.Get(), DataTypeName.Length())); if (Instance && typeHandle && typeHandle.IsSubclassOf(SettingsBase::TypeInitializer) && _isAfterReload) diff --git a/Source/Engine/Content/JsonAsset.h b/Source/Engine/Content/JsonAsset.h index b974f3087..607ede7bc 100644 --- a/Source/Engine/Content/JsonAsset.h +++ b/Source/Engine/Content/JsonAsset.h @@ -16,6 +16,7 @@ API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API JsonAssetBase : public Asset protected: String _path; bool _isVirtualDocument = false; + bool _isResaving = false; protected: /// @@ -73,13 +74,6 @@ public: /// The output list of object IDs references by the asset (appended, not cleared). API_FUNCTION() static void GetReferences(const StringAnsiView& json, API_PARAM(Out) Array& assets); - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if cannot save data, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty) const; - /// /// Saves this asset to the Json Writer buffer (both ID, Typename header and Data contents). Supported only in Editor. /// @@ -98,6 +92,7 @@ public: uint64 GetMemoryUsage() const override; #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif protected: @@ -149,6 +144,7 @@ public: protected: // [JsonAssetBase] + void OnGetData(rapidjson_flax::StringBuffer& buffer) const override; LoadResult loadAsset() override; void unload(bool isReloading) override; void onLoaded_MainThread() override; diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index a9d1fb5a4..d5c21edec 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -888,10 +888,12 @@ Variant::Variant(const Span& v) } PRAGMA_DISABLE_DEPRECATION_WARNINGS +#include "Engine/Content/Deprecated.h" Variant::Variant(const CommonValue& value) : Variant() { // [Deprecated on 31.07.2020, expires on 31.07.2022] + MARK_CONTENT_DEPRECATED(); switch (value.Type) { case CommonType::Bool: diff --git a/Source/Engine/Engine/GameplayGlobals.cpp b/Source/Engine/Engine/GameplayGlobals.cpp index d6b9548d7..def352dd0 100644 --- a/Source/Engine/Engine/GameplayGlobals.cpp +++ b/Source/Engine/Engine/GameplayGlobals.cpp @@ -154,18 +154,8 @@ void GameplayGlobals::ResetValues() bool GameplayGlobals::Save(const StringView& path) { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } - ScopeLock lock(Locker); // Save to bytes diff --git a/Source/Engine/Engine/GameplayGlobals.h b/Source/Engine/Engine/GameplayGlobals.h index 4f09ba4c8..768840a55 100644 --- a/Source/Engine/Engine/GameplayGlobals.h +++ b/Source/Engine/Engine/GameplayGlobals.h @@ -80,20 +80,12 @@ public: /// API_FUNCTION() void ResetValues(); -#if USE_EDITOR - - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if cannot save data, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty); - -#endif - public: // [BinaryAsset] void InitAsVirtual() override; +#if USE_EDITOR + bool Save(const StringView& path = StringView::Empty) override; +#endif protected: // [BinaryAsset] diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 427e2260b..d3c8af9e2 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -7,6 +7,7 @@ #include "Engine/Core/Random.h" #include "Engine/Engine/Engine.h" #include "Engine/Graphics/RenderTask.h" +#include "Engine/Content/Deprecated.h" #if !FOLIAGE_USE_SINGLE_QUAD_TREE #include "Engine/Threading/JobSystem.h" #if FOLIAGE_USE_DRAW_CALLS_BATCHING @@ -1374,6 +1375,7 @@ void Foliage::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie if (modifier->EngineBuild <= 6189) { // [Deprecated on 30.11.2019, expires on 30.11.2021] + MARK_CONTENT_DEPRECATED(); InstanceEncoded1 enc; for (int32 i = 0; i < foliageInstancesCount; i++) { diff --git a/Source/Engine/Graphics/Materials/MaterialParams.cpp b/Source/Engine/Graphics/Materials/MaterialParams.cpp index 78337dcf0..61b765056 100644 --- a/Source/Engine/Graphics/Materials/MaterialParams.cpp +++ b/Source/Engine/Graphics/Materials/MaterialParams.cpp @@ -5,6 +5,7 @@ #include "Engine/Core/Math/Vector4.h" #include "Engine/Core/Math/Matrix.h" #include "Engine/Content/Content.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Engine/GameplayGlobals.h" #include "Engine/Serialization/MemoryWriteStream.h" @@ -652,6 +653,8 @@ bool MaterialParams::Load(ReadStream* stream) { case 1: // [Deprecated on 15.11.2019, expires on 15.11.2021] { + MARK_CONTENT_DEPRECATED(); + // Size of the collection uint16 paramsCount; stream->ReadUint16(¶msCount); @@ -727,6 +730,8 @@ bool MaterialParams::Load(ReadStream* stream) break; case 2: // [Deprecated on 15.11.2019, expires on 15.11.2021] { + MARK_CONTENT_DEPRECATED(); + // Size of the collection uint16 paramsCount; stream->ReadUint16(¶msCount); diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp index 8fd1131d1..ecb727c11 100644 --- a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp +++ b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp @@ -8,6 +8,7 @@ #include "Engine/Graphics/Shaders/GPUShader.h" #if COMPILE_WITH_SHADER_COMPILER #include "Engine/Engine/CommandLine.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Serialization/MemoryReadStream.h" #endif #include "Engine/ShadowsOfMordor/AtlasChartsPacker.h" @@ -98,8 +99,11 @@ bool ShaderAssetBase::initBase(AssetInitData& initData) #if USE_EDITOR -bool ShaderAssetBase::Save() +bool ShaderAssetBase::SaveShaderAsset() const { + // Asset is being saved so no longer need to resave deprecated data in it + ContentDeprecated::Clear(); + auto parent = GetShaderAsset(); AssetInitData data; data.SerializedVersion = ShaderStorage::Header::Version; @@ -296,7 +300,7 @@ bool ShaderAssetBase::LoadShaderCache(ShaderCacheResult& result) #if USE_EDITOR // Save chunks to the asset file - if (Save()) + if (SaveShaderAsset()) { LOG(Warning, "Cannot save '{0}'.", parent->ToString()); return true; diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h index d0ebc0c8d..e2a860abe 100644 --- a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h +++ b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h @@ -30,15 +30,13 @@ public: static int32 GetCacheChunkIndex(ShaderProfile profile); #if USE_EDITOR - /// - /// Prepare shader compilation options + /// Prepare shader compilation options. /// - /// Options + /// The output options. virtual void InitCompilationOptions(struct ShaderCompilationOptions& options) { } - #endif protected: @@ -50,13 +48,11 @@ protected: virtual BinaryAsset* GetShaderAsset() const = 0; #if USE_EDITOR - /// /// Saves this shader asset to the storage container. /// /// True if failed, otherwise false. - bool Save(); - + bool SaveShaderAsset() const; #endif /// @@ -70,12 +66,10 @@ protected: DataContainer Data; #if COMPILE_WITH_SHADER_COMPILER - /// /// The list of files included by the shader source (used by the given cache on the runtime graphics platform shader profile). Paths are absolute and unique. /// Array Includes; - #endif }; @@ -87,7 +81,6 @@ protected: bool LoadShaderCache(ShaderCacheResult& result); #if COMPILE_WITH_SHADER_COMPILER - /// /// Registers shader asset for the automated reloads on source includes changes. /// @@ -100,7 +93,6 @@ protected: /// /// The asset. void UnregisterForShaderReloads(Asset* asset); - #endif }; diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderStorage.h b/Source/Engine/Graphics/Shaders/Cache/ShaderStorage.h index b4660c8d1..59bcd0999 100644 --- a/Source/Engine/Graphics/Shaders/Cache/ShaderStorage.h +++ b/Source/Engine/Graphics/Shaders/Cache/ShaderStorage.h @@ -75,7 +75,7 @@ public: }; /// /// File header, version 19 -/// [Deprecated on 13.07.2022, expires on 13.07.2024] + /// [Deprecated on 13.07.2022, expires on 13.07.2024] /// struct Header19 { diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 2a594bdde..9fe0f4b9d 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -12,6 +12,7 @@ #include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Threading/Threading.h" #include "Engine/Content/Content.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Core/Cache.h" #include "Engine/Core/Collections/CollectionPoolCache.h" #include "Engine/Debug/Exceptions/JsonParseException.h" @@ -1074,12 +1075,18 @@ void Actor::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) // StaticFlags update - added StaticFlags::Navigation // [Deprecated on 17.05.2020, expires on 17.05.2021] if (modifier->EngineBuild < 6178 && (int32)_staticFlags == (1 + 2 + 4)) + { + MARK_CONTENT_DEPRECATED(); _staticFlags |= StaticFlags::Navigation; + } // StaticFlags update - added StaticFlags::Shadow // [Deprecated on 17.05.2020, expires on 17.05.2021] if (modifier->EngineBuild < 6601 && (int32)_staticFlags == (1 + 2 + 4 + 8)) + { + MARK_CONTENT_DEPRECATED(); _staticFlags |= StaticFlags::Shadow; + } const auto tag = stream.FindMember("Tag"); if (tag != stream.MemberEnd()) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 373339e2d..07cea3d15 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -11,6 +11,7 @@ #include "Engine/Core/Math/Matrix3x3.h" #include "Editor/Editor.h" #endif +#include "Engine/Content/Deprecated.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/RenderTask.h" @@ -1153,10 +1154,16 @@ void AnimatedModel::Deserialize(DeserializeStream& stream, ISerializeModifier* m // [Deprecated on 07.02.2022, expires on 07.02.2024] if (modifier->EngineBuild <= 6330) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSDF; + } // [Deprecated on 27.04.2022, expires on 27.04.2024] if (modifier->EngineBuild <= 6331) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSurfaceAtlas; + } } const Span AnimatedModel::GetMaterialSlots() const diff --git a/Source/Engine/Level/Actors/EnvironmentProbe.cpp b/Source/Engine/Level/Actors/EnvironmentProbe.cpp index 8d7155dee..305f9d8ec 100644 --- a/Source/Engine/Level/Actors/EnvironmentProbe.cpp +++ b/Source/Engine/Level/Actors/EnvironmentProbe.cpp @@ -11,6 +11,7 @@ #include "Engine/Renderer/ProbesRenderer.h" #include "Engine/Renderer/ReflectionsPass.h" #include "Engine/Content/Content.h" +#include "Engine/Content/Deprecated.h" #include "Engine/ContentExporters/AssetExporters.h" #include "Engine/ContentImporters/AssetsImportingManager.h" #include "Engine/Graphics/RenderTools.h" @@ -255,6 +256,7 @@ void EnvironmentProbe::Deserialize(DeserializeStream& stream, ISerializeModifier // [Deprecated on 18.07.2022, expires on 18.07.2022] if (modifier->EngineBuild <= 6332) { + MARK_CONTENT_DEPRECATED(); const auto member = stream.FindMember("AutoUpdate"); if (member != stream.MemberEnd() && member->value.IsBool() && member->value.GetBool()) UpdateMode = ProbeUpdateMode::WhenMoved; diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp index 71b618384..a41b22c92 100644 --- a/Source/Engine/Level/Actors/SplineModel.cpp +++ b/Source/Engine/Level/Actors/SplineModel.cpp @@ -6,6 +6,7 @@ #include "Engine/Core/Math/Matrix3x4.h" #include "Engine/Engine/Engine.h" #include "Engine/Serialization/Serialization.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Graphics/GPUBufferDescription.h" #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUBuffer.h" @@ -514,10 +515,16 @@ void SplineModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod // [Deprecated on 07.02.2022, expires on 07.02.2024] if (modifier->EngineBuild <= 6330) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSDF; + } // [Deprecated on 27.04.2022, expires on 27.04.2024] if (modifier->EngineBuild <= 6331) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSurfaceAtlas; + } } void SplineModel::OnActiveInTreeChanged() diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 054345785..06f776661 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -2,6 +2,7 @@ #include "StaticModel.h" #include "Engine/Engine/Engine.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Graphics/GPUBuffer.h" #include "Engine/Graphics/GPUBufferDescription.h" #include "Engine/Graphics/GPUContext.h" @@ -534,15 +535,22 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod const auto member = stream.FindMember("HiddenShadow"); if (member != stream.MemberEnd() && member->value.IsBool() && member->value.GetBool()) { + MARK_CONTENT_DEPRECATED(); DrawModes = DrawPass::Depth; } } // [Deprecated on 07.02.2022, expires on 07.02.2024] if (modifier->EngineBuild <= 6330) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSDF; + } // [Deprecated on 27.04.2022, expires on 27.04.2024] if (modifier->EngineBuild <= 6331) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSurfaceAtlas; + } { const auto member = stream.FindMember("RenderPasses"); diff --git a/Source/Engine/Navigation/Navigation.cpp b/Source/Engine/Navigation/Navigation.cpp index a30367391..5d7bb7889 100644 --- a/Source/Engine/Navigation/Navigation.cpp +++ b/Source/Engine/Navigation/Navigation.cpp @@ -4,6 +4,7 @@ #include "NavigationSettings.h" #include "NavMeshRuntime.h" #include "NavMeshBuilder.h" +#include "NavMesh.h" #include "Engine/Core/Config/GameSettings.h" #include "Engine/Content/Content.h" #include "Engine/Content/JsonAsset.h" @@ -14,8 +15,7 @@ #include "Engine/Level/Level.h" #include "Engine/Level/Scene/Scene.h" #endif -#include "NavMesh.h" - +#include "Engine/Content/Deprecated.h" #include "Engine/Engine/EngineService.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Serialization/Serialization.h" @@ -255,6 +255,7 @@ void NavigationSettings::Deserialize(DeserializeStream& stream, ISerializeModifi else { // [Deprecated on 12.01.2021, expires on 12.01.2022] + MARK_CONTENT_DEPRECATED(); float WalkableRadius = 34.0f; float WalkableHeight = 144.0f; float WalkableMaxClimb = 35.0f; diff --git a/Source/Engine/Particles/ParticleEffect.cpp b/Source/Engine/Particles/ParticleEffect.cpp index 9a89a0154..bb8769b46 100644 --- a/Source/Engine/Particles/ParticleEffect.cpp +++ b/Source/Engine/Particles/ParticleEffect.cpp @@ -3,6 +3,7 @@ #include "ParticleEffect.h" #include "Particles.h" #include "Engine/Core/Types/CommonValue.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Serialization/JsonTools.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Level/Scene/SceneRendering.h" @@ -664,6 +665,7 @@ void ParticleEffect::Deserialize(DeserializeStream& stream, ISerializeModifier* if (modifier->EngineBuild < 6197) { PRAGMA_DISABLE_DEPRECATION_WARNINGS + MARK_CONTENT_DEPRECATED(); const auto& overrides = overridesMember->value; ASSERT(overrides.IsArray()); _parametersOverrides.EnsureCapacity(_parametersOverrides.Count() + overrides.Size()); diff --git a/Source/Engine/Particles/ParticleEmitter.cpp b/Source/Engine/Particles/ParticleEmitter.cpp index 8e9533474..a23a30fac 100644 --- a/Source/Engine/Particles/ParticleEmitter.cpp +++ b/Source/Engine/Particles/ParticleEmitter.cpp @@ -154,6 +154,16 @@ Asset::LoadResult ParticleEmitter::load() LOG(Warning, "Cannot load Particle Emitter GPU graph '{0}'.", GetPath()); return LoadResult::CannotLoadData; } + if (ContentDeprecated::Clear()) + { + // If encountered any deprecated data when loading graph then serialize it + MemoryWriteStream writeStream(1024); + if (!Graph.Save(&writeStream, true)) + { + surfaceChunk->Data.Copy(ToSpan(writeStream)); + ContentDeprecated::Clear(); + } + } generator.AddGraph(graph); // Get chunk with material parameters @@ -199,7 +209,7 @@ Asset::LoadResult ParticleEmitter::load() // Save to file #if USE_EDITOR - if (Save()) + if (SaveShaderAsset()) { LOG(Error, "Cannot save \'{0}\'", ToString()); return LoadResult::Failed; @@ -318,10 +328,6 @@ void ParticleEmitter::OnDependencyModified(BinaryAsset* asset) Reload(); } -#endif - -#if USE_EDITOR - void ParticleEmitter::InitCompilationOptions(ShaderCompilationOptions& options) { // Base @@ -377,19 +383,10 @@ BytesContainer ParticleEmitter::LoadSurface(bool createDefaultIfMissing) #if USE_EDITOR -bool ParticleEmitter::SaveSurface(BytesContainer& data) +bool ParticleEmitter::SaveSurface(const BytesContainer& data) { - // Wait for asset to be loaded or don't if last load failed (eg. by shader source compilation error) - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Release all chunks @@ -406,7 +403,7 @@ bool ParticleEmitter::SaveSurface(BytesContainer& data) ASSERT(visjectSurfaceChunk != nullptr); visjectSurfaceChunk->Data.Copy(data); - if (Save()) + if (SaveShaderAsset()) { LOG(Error, "Cannot save \'{0}\'", ToString()); return true; @@ -420,4 +417,23 @@ bool ParticleEmitter::SaveSurface(BytesContainer& data) return false; } +void ParticleEmitter::GetReferences(Array& assets, Array& files) const +{ + BinaryAsset::GetReferences(assets, files); + Graph.GetReferences(assets); +} + +bool ParticleEmitter::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + MemoryWriteStream writeStream; + if (Graph.Save(&writeStream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(writeStream)); + return SaveSurface(data); +} + #endif diff --git a/Source/Engine/Particles/ParticleEmitter.h b/Source/Engine/Particles/ParticleEmitter.h index d07ffc108..321a0235b 100644 --- a/Source/Engine/Particles/ParticleEmitter.h +++ b/Source/Engine/Particles/ParticleEmitter.h @@ -20,6 +20,7 @@ class ParticleEmitterInstance; API_CLASS(NoSpawn) class FLAXENGINE_API ParticleEmitter : public ShaderAssetTypeBase { DECLARE_BINARY_ASSET_HEADER(ParticleEmitter, ShadersSerializedVersion); + public: /// /// The loaded particle graph. @@ -84,14 +85,12 @@ public: API_FUNCTION() BytesContainer LoadSurface(bool createDefaultIfMissing); #if USE_EDITOR - /// /// Updates surface (saves new one, discard cached data, reloads asset). /// /// The surface graph data. /// True if cannot save it, otherwise false. - API_FUNCTION() bool SaveSurface(BytesContainer& data); - + API_FUNCTION() bool SaveSurface(const BytesContainer& data); #endif public: @@ -100,7 +99,7 @@ public: /// /// The spawn position. /// The effect playback duration (in seconds). - /// If set to true effect be be auto-destroyed after duration. + /// If set to true effect will be auto-destroyed after duration. /// The spawned effect. API_FUNCTION() ParticleEffect* Spawn(const Vector3& position, float duration = MAX_float, bool autoDestroy = false) { @@ -113,7 +112,7 @@ public: /// The spawn position. /// The spawn rotation. /// The effect playback duration (in seconds). - /// If set to true effect be be auto-destroyed after duration. + /// If set to true effect will be auto-destroyed after duration. /// The spawned effect. API_FUNCTION() ParticleEffect* Spawn(const Vector3& position, const Quaternion& rotation, float duration = MAX_float, bool autoDestroy = false) { @@ -125,7 +124,7 @@ public: /// /// The spawn transform. /// The effect playback duration (in seconds). - /// If set to true effect be be auto-destroyed after duration. + /// If set to true effect will be auto-destroyed after duration. /// The spawned effect. API_FUNCTION() ParticleEffect* Spawn(const Transform& transform, float duration = MAX_float, bool autoDestroy = false) { @@ -138,7 +137,7 @@ public: /// The parent actor (can be null to link it to the first loaded scene). /// The spawn position. /// The effect playback duration (in seconds). - /// If set to true effect be be auto-destroyed after duration. + /// If set to true effect will be auto-destroyed after duration. /// The spawned effect. API_FUNCTION() ParticleEffect* Spawn(Actor* parent, const Vector3& position, float duration = MAX_float, bool autoDestroy = false) { @@ -152,7 +151,7 @@ public: /// The spawn position. /// The spawn rotation. /// The effect playback duration (in seconds). - /// If set to true effect be be auto-destroyed after duration. + /// If set to true effect will be auto-destroyed after duration. /// The spawned effect. API_FUNCTION() ParticleEffect* Spawn(Actor* parent, const Vector3& position, const Quaternion& rotation, float duration = MAX_float, bool autoDestroy = false) { @@ -165,18 +164,15 @@ public: /// The parent actor (can be null to link it to the first loaded scene). /// The spawn transform. /// The effect playback duration (in seconds). - /// If set to true effect be be auto-destroyed after duration. + /// If set to true effect will be auto-destroyed after duration. /// The spawned effect. API_FUNCTION() ParticleEffect* Spawn(Actor* parent, const Transform& transform, float duration = MAX_float, bool autoDestroy = false); public: // [BinaryAsset] #if USE_EDITOR - void GetReferences(Array& assets, Array& files) const override - { - BinaryAsset::GetReferences(assets, files); - Graph.GetReferences(assets); - } + void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif protected: @@ -186,8 +182,6 @@ protected: AssetChunksFlag getChunksToPreload() const override; #if USE_EDITOR void OnDependencyModified(BinaryAsset* asset) override; -#endif -#if USE_EDITOR void InitCompilationOptions(ShaderCompilationOptions& options) override; #endif }; diff --git a/Source/Engine/Particles/ParticleEmitterFunction.cpp b/Source/Engine/Particles/ParticleEmitterFunction.cpp index eae85e351..50f120d83 100644 --- a/Source/Engine/Particles/ParticleEmitterFunction.cpp +++ b/Source/Engine/Particles/ParticleEmitterFunction.cpp @@ -6,6 +6,7 @@ #include "Engine/Threading/Threading.h" #if USE_EDITOR #include "Engine/Core/Types/DataContainer.h" +#include "Engine/Serialization/MemoryWriteStream.h" #endif #include "Engine/Content/Factories/BinaryAssetFactory.h" @@ -44,7 +45,7 @@ Asset::LoadResult ParticleEmitterFunction::load() if (!surfaceChunk || !surfaceChunk->IsLoaded()) return LoadResult::MissingDataChunk; MemoryReadStream stream(surfaceChunk->Get(), surfaceChunk->Size()); - if (Graph.Load(&stream, false)) + if (Graph.Load(&stream, USE_EDITOR)) return LoadResult::Failed; for (int32 i = 0; i < Graph.Nodes.Count(); i++) { @@ -103,7 +104,7 @@ AssetChunksFlag ParticleEmitterFunction::getChunksToPreload() const return GET_CHUNK_FLAG(0); } -bool ParticleEmitterFunction::LoadSurface(ParticleEmitterGraphCPU& graph) +bool ParticleEmitterFunction::LoadSurface(ParticleEmitterGraphCPU& graph, bool loadMeta) { if (WaitForLoaded()) return true; @@ -114,7 +115,7 @@ bool ParticleEmitterFunction::LoadSurface(ParticleEmitterGraphCPU& graph) { const auto surfaceChunk = GetChunk(0); MemoryReadStream stream(surfaceChunk->Get(), surfaceChunk->Size()); - return graph.Load(&stream, false); + return graph.Load(&stream, loadMeta); } } return true; @@ -141,7 +142,7 @@ BytesContainer ParticleEmitterFunction::LoadSurface() #if COMPILE_WITH_PARTICLE_GPU_GRAPH -bool ParticleEmitterFunction::LoadSurface(ParticleEmitterGraphGPU& graph) +bool ParticleEmitterFunction::LoadSurface(ParticleEmitterGraphGPU& graph) const { if (WaitForLoaded()) return true; @@ -178,19 +179,10 @@ void ParticleEmitterFunction::GetSignature(Array } } -bool ParticleEmitterFunction::SaveSurface(BytesContainer& data) +bool ParticleEmitterFunction::SaveSurface(const BytesContainer& data) const { - // Wait for asset to be loaded or don't if last load failed - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Set Visject Surface data @@ -210,4 +202,17 @@ bool ParticleEmitterFunction::SaveSurface(BytesContainer& data) return false; } +bool ParticleEmitterFunction::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + MemoryWriteStream writeStream; + if (Graph.Save(&writeStream, true)) + return true; + BytesContainer data; + data.Link(ToSpan(writeStream)); + return SaveSurface(data); +} + #endif diff --git a/Source/Engine/Particles/ParticleEmitterFunction.h b/Source/Engine/Particles/ParticleEmitterFunction.h index 5938ff6e6..8d7499884 100644 --- a/Source/Engine/Particles/ParticleEmitterFunction.h +++ b/Source/Engine/Particles/ParticleEmitterFunction.h @@ -31,23 +31,21 @@ public: Array> Outputs; #if COMPILE_WITH_PARTICLE_GPU_GRAPH - /// /// The loaded GPU particle function graph. /// ParticleEmitterGraphGPU GraphGPU; - #endif /// /// Tries to load surface graph from the asset. /// /// The graph to load. + /// True if load metadata. /// True if failed, otherwise false. - bool LoadSurface(ParticleEmitterGraphCPU& graph); + bool LoadSurface(ParticleEmitterGraphCPU& graph, bool loadMeta = false); #if USE_EDITOR - /// /// Tries to load surface graph from the asset. /// @@ -55,14 +53,12 @@ public: API_FUNCTION() BytesContainer LoadSurface(); #if COMPILE_WITH_PARTICLE_GPU_GRAPH - /// /// Tries to load surface graph from the asset. /// /// The graph to load. /// True if failed, otherwise false. - bool LoadSurface(ParticleEmitterGraphGPU& graph); - + bool LoadSurface(ParticleEmitterGraphGPU& graph) const; #endif // Gets the function signature for Visject Surface editor. @@ -73,8 +69,13 @@ public: /// /// The surface graph data. /// True if cannot save it, otherwise false. - API_FUNCTION() bool SaveSurface(BytesContainer& data); + API_FUNCTION() bool SaveSurface(const BytesContainer& data) const; +#endif +public: + // [BinaryAsset] +#if USE_EDITOR + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Particles/ParticleSystem.cpp b/Source/Engine/Particles/ParticleSystem.cpp index e70e5769d..fba1561b0 100644 --- a/Source/Engine/Particles/ParticleSystem.cpp +++ b/Source/Engine/Particles/ParticleSystem.cpp @@ -4,6 +4,7 @@ #include "ParticleEffect.h" #include "Engine/Core/Types/CommonValue.h" #include "Engine/Level/Level.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Content/Factories/BinaryAssetFactory.h" #include "Engine/Serialization/MemoryReadStream.h" #include "Engine/Serialization/MemoryWriteStream.h" @@ -46,7 +47,7 @@ void ParticleSystem::Init(ParticleEmitter* emitter, float duration, float fps) } } -BytesContainer ParticleSystem::LoadTimeline() +BytesContainer ParticleSystem::LoadTimeline() const { BytesContainer result; ScopeLock lock(Locker); @@ -108,25 +109,16 @@ BytesContainer ParticleSystem::LoadTimeline() } // Set output data - result.Copy(stream.GetHandle(), stream.GetPosition()); + result.Copy(ToSpan(stream)); return result; } #if USE_EDITOR -bool ParticleSystem::SaveTimeline(BytesContainer& data) +bool ParticleSystem::SaveTimeline(const BytesContainer& data) const { - // Wait for asset to be loaded or don't if last load failed (eg. by shader source compilation error) - if (LastLoadFailed()) - { - LOG(Warning, "Saving asset that failed to load."); - } - else if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave()) return true; - } - ScopeLock lock(Locker); // Release all chunks @@ -197,6 +189,15 @@ void ParticleSystem::GetReferences(Array& assets, Array& files) co } } +bool ParticleSystem::Save(const StringView& path) +{ + if (OnCheckSave(path)) + return true; + ScopeLock lock(Locker); + BytesContainer data = LoadTimeline(); + return SaveTimeline(data); +} + #endif Asset::LoadResult ParticleSystem::load() @@ -225,6 +226,7 @@ Asset::LoadResult ParticleSystem::load() case 1: { // [Deprecated on 23.07.2019, expires on 27.04.2021] + MARK_CONTENT_DEPRECATED(); // Load properties stream.ReadFloat(&FramesPerSecond); @@ -299,6 +301,7 @@ Asset::LoadResult ParticleSystem::load() case 2: { // [Deprecated on 31.07.2020, expires on 31.07.2022] + MARK_CONTENT_DEPRECATED(); // Load properties stream.ReadFloat(&FramesPerSecond); @@ -372,6 +375,7 @@ Asset::LoadResult ParticleSystem::load() } PRAGMA_ENABLE_DEPRECATION_WARNINGS case 3: // [Deprecated on 03.09.2021 expires on 03.09.2023] + MARK_CONTENT_DEPRECATED(); case 4: { // Load properties diff --git a/Source/Engine/Particles/ParticleSystem.h b/Source/Engine/Particles/ParticleSystem.h index cd472b49f..98b81bd47 100644 --- a/Source/Engine/Particles/ParticleSystem.h +++ b/Source/Engine/Particles/ParticleSystem.h @@ -156,17 +156,15 @@ public: /// Loads the serialized timeline data. /// /// The output surface data, or empty if failed to load. - API_FUNCTION() BytesContainer LoadTimeline(); + API_FUNCTION() BytesContainer LoadTimeline() const; #if USE_EDITOR - /// /// Saves the serialized timeline data to the asset. /// /// The timeline data container. /// true failed to save data; otherwise, false. - API_FUNCTION() bool SaveTimeline(BytesContainer& data); - + API_FUNCTION() bool SaveTimeline(const BytesContainer& data) const; #endif public: @@ -243,6 +241,7 @@ public: void InitAsVirtual() override; #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; + bool Save(const StringView& path = StringView::Empty) override; #endif protected: diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index 010add151..01b088040 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -1,10 +1,11 @@ // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #include "WheeledVehicle.h" -#include "Engine/Physics/Physics.h" #include "Engine/Level/Scene/Scene.h" +#include "Engine/Physics/Physics.h" #include "Engine/Physics/PhysicsBackend.h" #include "Engine/Physics/PhysicsScene.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Serialization/Serialization.h" #if USE_EDITOR #include "Engine/Level/Scene/SceneRendering.h" @@ -476,7 +477,11 @@ void WheeledVehicle::Deserialize(DeserializeStream& stream, ISerializeModifier* DESERIALIZE_MEMBER(AntiRollBars, _antiRollBars); // [Deprecated on 13.06.2023, expires on 13.06.2025] - _fixInvalidForwardDir |= modifier->EngineBuild < 6341; + if (modifier->EngineBuild < 6341) + { + MARK_CONTENT_DEPRECATED(); + _fixInvalidForwardDir = true; + } } void WheeledVehicle::OnColliderChanged(Collider* c) diff --git a/Source/Engine/Render2D/FontAsset.cpp b/Source/Engine/Render2D/FontAsset.cpp index 3161c65ef..0dd3df37c 100644 --- a/Source/Engine/Render2D/FontAsset.cpp +++ b/Source/Engine/Render2D/FontAsset.cpp @@ -167,18 +167,8 @@ bool FontAsset::Init(const BytesContainer& fontFile) bool FontAsset::Save(const StringView& path) { - // Validate state - if (WaitForLoaded()) - { - LOG(Error, "Asset loading failed. Cannot save it."); + if (OnCheckSave(path)) return true; - } - if (IsVirtual() && path.IsEmpty()) - { - LOG(Error, "To save virtual asset asset you need to specify the target asset path location."); - return true; - } - ScopeLock lock(Locker); AssetInitData data; diff --git a/Source/Engine/Render2D/FontAsset.h b/Source/Engine/Render2D/FontAsset.h index 02b085db5..d5df16c4f 100644 --- a/Source/Engine/Render2D/FontAsset.h +++ b/Source/Engine/Render2D/FontAsset.h @@ -166,15 +166,6 @@ public: /// True if cannot init, otherwise false. API_FUNCTION() bool Init(const BytesContainer& fontFile); -#if USE_EDITOR - /// - /// Saves this asset to the file. Supported only in Editor. - /// - /// The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset. - /// True if cannot save data, otherwise false. - API_FUNCTION() bool Save(const StringView& path = StringView::Empty); -#endif - /// /// Check if the font contains the glyph of a char. /// @@ -190,6 +181,9 @@ public: public: // [BinaryAsset] uint64 GetMemoryUsage() const override; +#if USE_EDITOR + bool Save(const StringView& path = StringView::Empty) override; +#endif protected: // [BinaryAsset] diff --git a/Source/Engine/Serialization/JsonTools.cpp b/Source/Engine/Serialization/JsonTools.cpp index 7d6faf4ff..76b6a5572 100644 --- a/Source/Engine/Serialization/JsonTools.cpp +++ b/Source/Engine/Serialization/JsonTools.cpp @@ -285,9 +285,11 @@ DateTime JsonTools::GetDateTime(const Value& value) } PRAGMA_DISABLE_DEPRECATION_WARNINGS +#include "Engine/Content/Deprecated.h" CommonValue JsonTools::GetCommonValue(const Value& value) { // [Deprecated on 31.07.2020, expires on 31.07.2022] + MARK_CONTENT_DEPRECATED(); CommonValue result; const auto typeMember = value.FindMember("Type"); const auto valueMember = value.FindMember("Value"); diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index 204a78359..6e6d43d06 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -7,13 +7,14 @@ #include "Engine/Level/Scene/SceneRendering.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Physics/Physics.h" +#include "Engine/Physics/PhysicsScene.h" #include "Engine/Physics/PhysicalMaterial.h" #include "Engine/Physics/PhysicsBackend.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/Textures/GPUTexture.h" #include "Engine/Level/Scene/Scene.h" -#include "Engine/Physics/PhysicsScene.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Renderer/GlobalSignDistanceFieldPass.h" #include "Engine/Renderer/GI/GlobalSurfaceAtlasPass.h" @@ -810,16 +811,23 @@ void Terrain::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie // [Deprecated on 07.02.2022, expires on 07.02.2024] if (modifier->EngineBuild <= 6330) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSDF; + } // [Deprecated on 27.04.2022, expires on 27.04.2024] if (modifier->EngineBuild <= 6331) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSurfaceAtlas; + } // [Deprecated on 15.02.2024, expires on 15.02.2026] JsonAssetReference PhysicalMaterial; DESERIALIZE(PhysicalMaterial); if (PhysicalMaterial) { + MARK_CONTENT_DEPRECATED(); for (auto& e : _physicalMaterials) e = PhysicalMaterial; } diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index 8ff691204..a1ccbda59 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -16,6 +16,7 @@ #include "Engine/Serialization/Serialization.h" #include "Engine/Content/Assets/MaterialInstance.h" #include "Engine/Content/Content.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Core/Types/Variant.h" #include "Engine/Graphics/RenderTools.h" #include "Engine/Graphics/Shaders/GPUVertexLayout.h" @@ -482,10 +483,16 @@ void TextRender::Deserialize(DeserializeStream& stream, ISerializeModifier* modi // [Deprecated on 07.02.2022, expires on 07.02.2024] if (modifier->EngineBuild <= 6330) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSDF; + } // [Deprecated on 27.04.2022, expires on 27.04.2024] if (modifier->EngineBuild <= 6331) + { + MARK_CONTENT_DEPRECATED(); DrawModes |= DrawPass::GlobalSurfaceAtlas; + } _isDirty = true; } diff --git a/Source/Engine/Visject/Graph.h b/Source/Engine/Visject/Graph.h index 62fcfec0a..13cbbf28c 100644 --- a/Source/Engine/Visject/Graph.h +++ b/Source/Engine/Visject/Graph.h @@ -7,6 +7,7 @@ #include "VisjectMeta.h" #include "GraphNode.h" #include "GraphParameter.h" +#include "Engine/Content/Deprecated.h" #include "Engine/Serialization/ReadStream.h" #include "Engine/Serialization/WriteStream.h" @@ -183,6 +184,7 @@ public: if (version < 7000) { // [Deprecated on 31.07.2020, expires on 31.07.2022] + MARK_CONTENT_DEPRECATED(); // Time saved int64 timeSaved;