Add support for virtual Prefab assets created from code

This commit is contained in:
Wojtek Figat
2022-07-26 23:08:19 +02:00
parent adaaaa3e3f
commit cced83ca96
7 changed files with 68 additions and 5 deletions

View File

@@ -230,7 +230,8 @@ void Asset::OnDeleteObject()
Content::GetRegistry()->DeleteAsset(id, nullptr); Content::GetRegistry()->DeleteAsset(id, nullptr);
// Delete file // Delete file
Content::deleteFileSafety(path, id); if (!IsVirtual())
Content::deleteFileSafety(path, id);
} }
#endif #endif
} }
@@ -288,8 +289,13 @@ void Asset::OnScriptingDispose()
void Asset::ChangeID(const Guid& newId) void Asset::ChangeID(const Guid& newId)
{ {
// Don't allow to change asset ids // Only virtual asset can change ID
CRASH; if (!IsVirtual())
CRASH;
const Guid oldId = _id;
ManagedScriptingObject::ChangeID(newId);
Content::onAssetChangeId(this, oldId, newId);
} }
bool Asset::LastLoadFailed() const bool Asset::LastLoadFailed() const

View File

@@ -460,12 +460,16 @@ Asset* Content::LoadAsync(const StringView& path, const ScriptingTypeHandle& typ
Array<Asset*> Content::GetAssets() Array<Asset*> Content::GetAssets()
{ {
Array<Asset*> assets; Array<Asset*> assets;
AssetsLocker.Lock();
Assets.GetValues(assets); Assets.GetValues(assets);
AssetsLocker.Unlock();
return assets; return assets;
} }
const Dictionary<Guid, Asset*>& Content::GetAssetsRaw() const Dictionary<Guid, Asset*>& Content::GetAssetsRaw()
{ {
AssetsLocker.Lock();
AssetsLocker.Unlock();
return Assets; return Assets;
} }
@@ -862,6 +866,13 @@ void Content::onAssetUnload(Asset* asset)
LoadedAssetsToInvoke.Remove(asset); LoadedAssetsToInvoke.Remove(asset);
} }
void Content::onAssetChangeId(Asset* asset, const Guid& oldId, const Guid& newId)
{
ScopeLock locker(AssetsLocker);
Assets.Remove(oldId);
Assets.Add(newId, asset);
}
bool Content::IsAssetTypeIdInvalid(const ScriptingTypeHandle& type, const ScriptingTypeHandle& assetType) bool Content::IsAssetTypeIdInvalid(const ScriptingTypeHandle& type, const ScriptingTypeHandle& assetType)
{ {
// Skip if no restrictions for the type // Skip if no restrictions for the type

View File

@@ -358,6 +358,7 @@ private:
static void tryCallOnLoaded(Asset* asset); static void tryCallOnLoaded(Asset* asset);
static void onAssetLoaded(Asset* asset); static void onAssetLoaded(Asset* asset);
static void onAssetUnload(Asset* asset); static void onAssetUnload(Asset* asset);
static void onAssetChangeId(Asset* asset, const Guid& oldId, const Guid& newId);
static Asset* load(const Guid& id, const ScriptingTypeHandle& type, AssetInfo& assetInfo); static Asset* load(const Guid& id, const ScriptingTypeHandle& type, AssetInfo& assetInfo);
private: private:

View File

@@ -45,6 +45,29 @@ String JsonAssetBase::GetData() const
return String((const char*)buffer.GetString(), (int32)buffer.GetSize()); return String((const char*)buffer.GetString(), (int32)buffer.GetSize());
} }
bool JsonAssetBase::Init(const StringView& dataTypeName, const StringAnsiView& dataJson)
{
CHECK_RETURN(IsVirtual(), true);
unload(true);
DataTypeName = dataTypeName;
DataEngineBuild = FLAXENGINE_VERSION_BUILD;
// Parse json document
{
PROFILE_CPU_NAMED("Json.Parse");
Document.Parse(dataJson.Get(), dataJson.Length());
}
if (Document.HasParseError())
{
Log::JsonParseException(Document.GetParseError(), Document.GetErrorOffset());
return true;
}
Data = &Document;
// Load asset-specific data
return loadAsset() != LoadResult::Ok;
}
const String& JsonAssetBase::GetPath() const const String& JsonAssetBase::GetPath() const
{ {
#if USE_EDITOR #if USE_EDITOR
@@ -114,6 +137,9 @@ void JsonAssetBase::GetReferences(Array<Guid>& output) const
Asset::LoadResult JsonAssetBase::loadAsset() Asset::LoadResult JsonAssetBase::loadAsset()
{ {
if (IsVirtual())
return LoadResult::Ok;
// Load data (raw json file in editor, cooked asset in build game) // Load data (raw json file in editor, cooked asset in build game)
#if USE_EDITOR #if USE_EDITOR
BytesContainer data; BytesContainer data;

View File

@@ -50,6 +50,15 @@ public:
/// </summary> /// </summary>
API_PROPERTY() String GetData() const; API_PROPERTY() String GetData() const;
/// <summary>
/// Initializes the virtual Json asset with custom data.
/// </summary>
/// <remarks>Can be used only for virtual assets created at runtime.</remarks>
/// <param name="dataTypeName">The data type name from the header. Allows to recognize the data type.</param>
/// <param name="dataJson">The Json with serialized data.</param>
/// <returns>True if failed, otherwise false.</returns>
API_FUNCTION() bool Init(const StringView& dataTypeName, const StringAnsiView& dataJson);
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>
/// Parses Json string to find any object references inside it. It can produce list of references to assets and/or scene objects. Supported only in Editor. /// Parses Json string to find any object references inside it. It can produce list of references to assets and/or scene objects. Supported only in Editor.

View File

@@ -661,10 +661,16 @@ bool Prefab::ApplyAll(Actor* targetActor)
// Assign references to the prefabs // Assign references to the prefabs
allPrefabs.EnsureCapacity(Math::RoundUpToPowerOf2(Math::Max(30, nestedPrefabIds.Count()))); allPrefabs.EnsureCapacity(Math::RoundUpToPowerOf2(Math::Max(30, nestedPrefabIds.Count())));
const Dictionary<Guid, Asset*, HeapAllocation>& assetsRaw = Content::GetAssetsRaw();
for (auto& e : assetsRaw)
{
if (e.Value->GetTypeHandle() == Prefab::TypeInitializer)
nestedPrefabIds.AddUnique(e.Key);
}
for (int32 i = 0; i < nestedPrefabIds.Count(); i++) for (int32 i = 0; i < nestedPrefabIds.Count(); i++)
{ {
const auto nestedPrefab = Content::LoadAsync<Prefab>(nestedPrefabIds[i]); const auto nestedPrefab = Content::LoadAsync<Prefab>(nestedPrefabIds[i]);
if (nestedPrefab && nestedPrefab != this) if (nestedPrefab && nestedPrefab != this && (nestedPrefab->Flags & ObjectFlags::WasMarkedToDelete) == 0)
{ {
allPrefabs.Add(nestedPrefab); allPrefabs.Add(nestedPrefab);
} }
@@ -1079,6 +1085,10 @@ bool Prefab::UpdateInternal(const Array<SceneObject*>& defaultInstanceObjects, r
LOG(Info, "Updating prefab data"); LOG(Info, "Updating prefab data");
// Reload prefab data // Reload prefab data
if (IsVirtual())
{
return Init(TypeName, StringAnsiView(tmpBuffer.GetString(), (int32)tmpBuffer.GetSize()));
}
#if 1 // Set to 0 to use memory-only reload that does not modifies the source file - useful for testing and debugging prefabs apply #if 1 // Set to 0 to use memory-only reload that does not modifies the source file - useful for testing and debugging prefabs apply
#if COMPILE_WITH_ASSETS_IMPORTER #if COMPILE_WITH_ASSETS_IMPORTER
Locker.Unlock(); Locker.Unlock();

View File

@@ -11,7 +11,7 @@
#include "Engine/Scripting/Scripting.h" #include "Engine/Scripting/Scripting.h"
#endif #endif
REGISTER_JSON_ASSET(Prefab, "FlaxEngine.Prefab", false); REGISTER_JSON_ASSET(Prefab, "FlaxEngine.Prefab", true);
Prefab::Prefab(const SpawnParams& params, const AssetInfo* info) Prefab::Prefab(const SpawnParams& params, const AssetInfo* info)
: JsonAssetBase(params, info) : JsonAssetBase(params, info)