Fix duplicating json assets to properly remap object IDs

#3441
This commit is contained in:
Wojtek Figat
2025-06-04 23:49:19 +02:00
parent 496856d12e
commit 8f49a492d8

View File

@@ -9,6 +9,10 @@
#include "Engine/Level/Types.h"
#include "Engine/Debug/Exceptions/JsonParseException.h"
#include "Engine/Profiler/ProfilerCPU.h"
#if USE_EDITOR
#include "Engine/Core/Collections/HashSet.h"
#include "Engine/Core/Collections/Dictionary.h"
#endif
#include <ThirdParty/rapidjson/document.h>
bool JsonStorageProxy::IsValidExtension(const StringView& extension)
@@ -56,27 +60,31 @@ bool JsonStorageProxy::GetAssetInfo(const StringView& path, Guid& resultId, Stri
#if USE_EDITOR
void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, const StringAnsi& srcId, const StringAnsi& dstId)
void FindObjectIds(const rapidjson_flax::Value& obj, const rapidjson_flax::Document& document, HashSet<Guid>& ids, const char* parentName = nullptr)
{
if (obj.IsObject())
{
for (rapidjson_flax::Value::MemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i)
for (rapidjson_flax::Value::ConstMemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i)
{
ChangeIds(i->value, document, srcId, dstId);
FindObjectIds(i->value, document, ids, i->name.GetString());
}
}
else if (obj.IsArray())
{
for (rapidjson::SizeType i = 0; i < obj.Size(); i++)
{
ChangeIds(obj[i], document, srcId, dstId);
FindObjectIds(obj[i], document, ids, parentName);
}
}
else if (obj.IsString())
else if (obj.IsString() && obj.GetStringLength() == 32)
{
if (StringUtils::Compare(srcId.Get(), obj.GetString()) == 0)
if (parentName && StringUtils::Compare(parentName, "ID") == 0)
{
obj.SetString(dstId.Get(), document.GetAllocator());
auto value = JsonTools::GetGuid(obj);
if (value.IsValid())
{
ids.Add(value);
}
}
}
}
@@ -91,9 +99,7 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
// Load file
Array<byte> fileData;
if (File::ReadAllBytes(path, fileData))
{
return false;
}
// Parse data
rapidjson_flax::Document document;
@@ -107,33 +113,35 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
return false;
}
// Try get asset metadata
// Get all IDs inside the file
HashSet<Guid> ids;
FindObjectIds(document, document, ids);
// Remap into a unique IDs
Dictionary<Guid, Guid> remap;
remap.EnsureCapacity(ids.Count());
for (const auto& id : ids)
remap.Add(id.Item, Guid::New());
// Remap asset ID using the provided value
auto idNode = document.FindMember("ID");
if (idNode == document.MemberEnd())
{
return true;
}
remap[JsonTools::GetGuid(idNode->value)] = newId;
// Change IDs
auto oldIdStr = idNode->value.GetString();
auto newIdStr = newId.ToString(Guid::FormatType::N).ToStringAnsi();
ChangeIds(document, document, oldIdStr, newIdStr);
// Change IDs of asset and objects inside asset
JsonTools::ChangeIds(document, remap);
// Save to file
rapidjson_flax::StringBuffer buffer;
PrettyJsonWriter writer(buffer);
document.Accept(writer.GetWriter());
if (File::WriteAllBytes(path, (byte*)buffer.GetString(), (int32)buffer.GetSize()))
{
return true;
}
return false;
#else
LOG(Warning, "Editing cooked content is invalid.");
return true;
#endif
}