Add content deprecation upgrades support to prefabs and scenes when loading levels
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
#include "SceneObjectsFactory.h"
|
#include "SceneObjectsFactory.h"
|
||||||
#include "Scene/Scene.h"
|
#include "Scene/Scene.h"
|
||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Content/Deprecated.h"
|
||||||
#include "Engine/Core/Cache.h"
|
#include "Engine/Core/Cache.h"
|
||||||
#include "Engine/Core/Collections/CollectionPoolCache.h"
|
#include "Engine/Core/Collections/CollectionPoolCache.h"
|
||||||
#include "Engine/Core/ObjectsRemovalService.h"
|
#include "Engine/Core/ObjectsRemovalService.h"
|
||||||
@@ -827,7 +828,7 @@ bool Level::loadScene(JsonAsset* sceneAsset)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadScene(*sceneAsset->Data, sceneAsset->DataEngineBuild);
|
return loadScene(*sceneAsset->Data, sceneAsset->DataEngineBuild, nullptr, &sceneAsset->GetPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Level::loadScene(const BytesContainer& sceneData, Scene** outScene)
|
bool Level::loadScene(const BytesContainer& sceneData, Scene** outScene)
|
||||||
@@ -866,11 +867,14 @@ bool Level::loadScene(rapidjson_flax::Document& document, Scene** outScene)
|
|||||||
return loadScene(data->value, saveEngineBuild, outScene);
|
return loadScene(data->value, saveEngineBuild, outScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene)
|
bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene, const String* assetPath)
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Level.LoadScene");
|
PROFILE_CPU_NAMED("Level.LoadScene");
|
||||||
if (outScene)
|
if (outScene)
|
||||||
*outScene = nullptr;
|
*outScene = nullptr;
|
||||||
|
#if USE_EDITOR
|
||||||
|
ContentDeprecated::Clear();
|
||||||
|
#endif
|
||||||
LOG(Info, "Loading scene...");
|
LOG(Info, "Loading scene...");
|
||||||
Stopwatch stopwatch;
|
Stopwatch stopwatch;
|
||||||
_lastSceneLoadTime = DateTime::Now();
|
_lastSceneLoadTime = DateTime::Now();
|
||||||
@@ -1002,6 +1006,9 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
|
|||||||
if (context.Async)
|
if (context.Async)
|
||||||
{
|
{
|
||||||
ScenesLock.Unlock(); // Unlock scenes from Main Thread so Job Threads can use it to safely setup actors hierarchy (see Actor::Deserialize)
|
ScenesLock.Unlock(); // Unlock scenes from Main Thread so Job Threads can use it to safely setup actors hierarchy (see Actor::Deserialize)
|
||||||
|
#if USE_EDITOR
|
||||||
|
volatile int64 deprecated = 0;
|
||||||
|
#endif
|
||||||
JobSystem::Execute([&](int32 i)
|
JobSystem::Execute([&](int32 i)
|
||||||
{
|
{
|
||||||
i++; // Start from 1. at index [0] was scene
|
i++; // Start from 1. at index [0] was scene
|
||||||
@@ -1011,9 +1018,17 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
|
|||||||
auto& idMapping = Scripting::ObjectsLookupIdMapping.Get();
|
auto& idMapping = Scripting::ObjectsLookupIdMapping.Get();
|
||||||
idMapping = &context.GetModifier()->IdsMapping;
|
idMapping = &context.GetModifier()->IdsMapping;
|
||||||
SceneObjectsFactory::Deserialize(context, obj, data[i]);
|
SceneObjectsFactory::Deserialize(context, obj, data[i]);
|
||||||
|
#if USE_EDITOR
|
||||||
|
if (ContentDeprecated::Clear())
|
||||||
|
Platform::InterlockedIncrement(&deprecated);
|
||||||
|
#endif
|
||||||
idMapping = nullptr;
|
idMapping = nullptr;
|
||||||
}
|
}
|
||||||
}, dataCount - 1);
|
}, dataCount - 1);
|
||||||
|
#if USE_EDITOR
|
||||||
|
if (deprecated != 0)
|
||||||
|
ContentDeprecated::Mark();
|
||||||
|
#endif
|
||||||
ScenesLock.Lock();
|
ScenesLock.Lock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1103,6 +1118,28 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
|
|||||||
LOG(Info, "Scene loaded in {0}ms", stopwatch.GetMilliseconds());
|
LOG(Info, "Scene loaded in {0}ms", stopwatch.GetMilliseconds());
|
||||||
if (outScene)
|
if (outScene)
|
||||||
*outScene = scene;
|
*outScene = scene;
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Resave assets that use deprecated data format
|
||||||
|
for (auto& e : context.DeprecatedPrefabs)
|
||||||
|
{
|
||||||
|
AssetReference<Prefab> prefab = e.Item;
|
||||||
|
LOG(Info, "Resaving asset '{}' that uses deprecated data format", prefab->GetPath());
|
||||||
|
if (prefab->Resave())
|
||||||
|
{
|
||||||
|
LOG(Error, "Failed to resave asset '{}'", prefab->GetPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ContentDeprecated::Clear() && assetPath)
|
||||||
|
{
|
||||||
|
LOG(Info, "Resaving asset '{}' that uses deprecated data format", *assetPath);
|
||||||
|
if (saveScene(scene, *assetPath))
|
||||||
|
{
|
||||||
|
LOG(Error, "Failed to resave asset '{}'", *assetPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1125,6 +1162,7 @@ bool LevelImpl::saveScene(Scene* scene)
|
|||||||
|
|
||||||
bool LevelImpl::saveScene(Scene* scene, const String& path)
|
bool LevelImpl::saveScene(Scene* scene, const String& path)
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU_NAMED("Level.SaveScene");
|
||||||
ASSERT(scene && EnumHasNoneFlags(scene->Flags, ObjectFlags::WasMarkedToDelete));
|
ASSERT(scene && EnumHasNoneFlags(scene->Flags, ObjectFlags::WasMarkedToDelete));
|
||||||
auto sceneId = scene->GetID();
|
auto sceneId = scene->GetID();
|
||||||
|
|
||||||
|
|||||||
@@ -551,5 +551,5 @@ private:
|
|||||||
static bool loadScene(JsonAsset* sceneAsset);
|
static bool loadScene(JsonAsset* sceneAsset);
|
||||||
static bool loadScene(const BytesContainer& sceneData, Scene** outScene = nullptr);
|
static bool loadScene(const BytesContainer& sceneData, Scene** outScene = nullptr);
|
||||||
static bool loadScene(rapidjson_flax::Document& document, Scene** outScene = nullptr);
|
static bool loadScene(rapidjson_flax::Document& document, Scene** outScene = nullptr);
|
||||||
static bool loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene = nullptr);
|
static bool loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene = nullptr, const String* assetPath = nullptr);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -732,6 +732,50 @@ bool Prefab::ApplyAll(Actor* targetActor)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Prefab::Resave()
|
||||||
|
{
|
||||||
|
if (OnCheckSave())
|
||||||
|
return true;
|
||||||
|
PROFILE_CPU_NAMED("Prefab.Resave");
|
||||||
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
|
Dictionary<Guid, Guid> objectIds;
|
||||||
|
objectIds.EnsureCapacity(ObjectsIds.Count());
|
||||||
|
for (int32 i = 0; i < ObjectsIds.Count(); i++)
|
||||||
|
{
|
||||||
|
Guid id = ObjectsIds[i];
|
||||||
|
objectIds.Add(id, id);
|
||||||
|
}
|
||||||
|
PrefabManager::SpawnOptions options;
|
||||||
|
options.WithLink = false;
|
||||||
|
options.IDs = &objectIds;
|
||||||
|
auto instance = PrefabManager::SpawnPrefab(this, options);
|
||||||
|
if (instance == nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Serialize to json data
|
||||||
|
CollectionPoolCache<ActorsCache::SceneObjectsListType>::ScopeCache sceneObjects = ActorsCache::SceneObjectsListCache.Get();
|
||||||
|
SceneQuery::GetAllSerializableSceneObjects(instance, *sceneObjects.Value);
|
||||||
|
rapidjson_flax::StringBuffer dataBuffer;
|
||||||
|
{
|
||||||
|
PrettyJsonWriter writerObj(dataBuffer);
|
||||||
|
PrefabInstanceData::SerializeObjects(*sceneObjects.Value, writerObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove temporary objects
|
||||||
|
instance->DeleteObject();
|
||||||
|
instance = nullptr;
|
||||||
|
|
||||||
|
// Save to file
|
||||||
|
if (CreateJson::Create(GetPath(), dataBuffer, TypeName))
|
||||||
|
{
|
||||||
|
LOG(Warning, "Failed to serialize prefab data to the asset.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPrefab, PrefabInstancesData& prefabInstancesData)
|
bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPrefab, PrefabInstancesData& prefabInstancesData)
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Prefab.Apply");
|
PROFILE_CPU_NAMED("Prefab.Apply");
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class Actor;
|
|||||||
class SceneObject;
|
class SceneObject;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Json asset that stores the collection of scene objects including actors and scripts. In general it can serve as any grouping of scene objects (for example a level) or be used as a form of a template instantiated and reused throughout the scene.
|
/// Json asset that stores the collection of scene objects including actors and scripts. In general, it can serve as any grouping of scene objects (for example a level) or be used as a form of a template instantiated and reused throughout the scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="JsonAssetBase" />
|
/// <seealso cref="JsonAssetBase" />
|
||||||
API_CLASS(NoSpawn) class FLAXENGINE_API Prefab : public JsonAssetBase
|
API_CLASS(NoSpawn) class FLAXENGINE_API Prefab : public JsonAssetBase
|
||||||
@@ -74,11 +74,16 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the difference from the prefab object instance, saves the changes and synchronizes them with the active instances of the prefab asset.
|
/// Applies the difference from the prefab object instance, saves the changes and synchronizes them with the active instances of the prefab asset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>Applies all the changes from not only the given actor instance but all actors created within that prefab instance.</remarks>
|
||||||
/// Applies all the changes from not only the given actor instance but all actors created within that prefab instance.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="targetActor">The root actor of spawned prefab instance to use as modified changes sources.</param>
|
/// <param name="targetActor">The root actor of spawned prefab instance to use as modified changes sources.</param>
|
||||||
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool ApplyAll(Actor* targetActor);
|
bool ApplyAll(Actor* targetActor);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resaves the prefab asset to the file by serializing default instance in the latest format and defaults.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
|
API_FUNCTION() bool Resave();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
#include "Engine/Content/AssetInfo.h"
|
#include "Engine/Content/AssetInfo.h"
|
||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Content/Deprecated.h"
|
||||||
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
||||||
#include "Engine/Physics/Colliders/MeshCollider.h"
|
#include "Engine/Physics/Colliders/MeshCollider.h"
|
||||||
#include "Engine/Level/Actors/StaticModel.h"
|
#include "Engine/Level/Actors/StaticModel.h"
|
||||||
@@ -306,6 +307,7 @@ void Scene::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
|||||||
if (e != stream.MemberEnd())
|
if (e != stream.MemberEnd())
|
||||||
{
|
{
|
||||||
// Upgrade from old single hidden navmesh data into NavMesh actors on a scene
|
// Upgrade from old single hidden navmesh data into NavMesh actors on a scene
|
||||||
|
MARK_CONTENT_DEPRECATED();
|
||||||
AssetReference<RawDataAsset> dataAsset;
|
AssetReference<RawDataAsset> dataAsset;
|
||||||
Serialization::Deserialize(e->value, dataAsset, modifier);
|
Serialization::Deserialize(e->value, dataAsset, modifier);
|
||||||
const auto settings = NavigationSettings::Get();
|
const auto settings = NavigationSettings::Get();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
#include "Engine/Level/Scripts/MissingScript.h"
|
#include "Engine/Level/Scripts/MissingScript.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "Engine/Content/Deprecated.h"
|
||||||
#include "Engine/Level/Scripts/ModelPrefab.h"
|
#include "Engine/Level/Scripts/ModelPrefab.h"
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -199,6 +200,7 @@ SceneObject* SceneObjectsFactory::Spawn(Context& context, const ISerializable::D
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// [Deprecated: 18.07.2019 expires 18.07.2020]
|
// [Deprecated: 18.07.2019 expires 18.07.2020]
|
||||||
|
MARK_CONTENT_DEPRECATED();
|
||||||
const auto typeIdMember = stream.FindMember("TypeID");
|
const auto typeIdMember = stream.FindMember("TypeID");
|
||||||
if (typeIdMember == stream.MemberEnd())
|
if (typeIdMember == stream.MemberEnd())
|
||||||
{
|
{
|
||||||
@@ -286,7 +288,19 @@ void SceneObjectsFactory::Deserialize(Context& context, SceneObject* obj, ISeria
|
|||||||
// Deserialize prefab data (recursive prefab loading to support nested prefabs)
|
// Deserialize prefab data (recursive prefab loading to support nested prefabs)
|
||||||
const auto prevVersion = modifier->EngineBuild;
|
const auto prevVersion = modifier->EngineBuild;
|
||||||
modifier->EngineBuild = prefab->DataEngineBuild;
|
modifier->EngineBuild = prefab->DataEngineBuild;
|
||||||
|
#if USE_EDITOR
|
||||||
|
bool prevDeprecated = ContentDeprecated::Clear();
|
||||||
|
#endif
|
||||||
Deserialize(context, obj, *(ISerializable::DeserializeStream*)prefabData);
|
Deserialize(context, obj, *(ISerializable::DeserializeStream*)prefabData);
|
||||||
|
#if USE_EDITOR
|
||||||
|
if (ContentDeprecated::Clear(prevDeprecated))
|
||||||
|
{
|
||||||
|
// Prefab contains deprecated data format
|
||||||
|
context.Locker.Lock();
|
||||||
|
context.DeprecatedPrefabs.Add(prefab);
|
||||||
|
context.Locker.Unlock();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
modifier->EngineBuild = prevVersion;
|
modifier->EngineBuild = prevVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ public:
|
|||||||
Dictionary<Guid, int32> ObjectToInstance;
|
Dictionary<Guid, int32> ObjectToInstance;
|
||||||
CriticalSection Locker;
|
CriticalSection Locker;
|
||||||
ThreadLocal<ISerializeModifier*> Modifiers;
|
ThreadLocal<ISerializeModifier*> Modifiers;
|
||||||
|
#if USE_EDITOR
|
||||||
|
HashSet<Prefab*> DeprecatedPrefabs;
|
||||||
|
#endif
|
||||||
|
|
||||||
Context(ISerializeModifier* modifier);
|
Context(ISerializeModifier* modifier);
|
||||||
~Context();
|
~Context();
|
||||||
|
|||||||
Reference in New Issue
Block a user