Add Actor.Clone for actors duplication at runtime (including scripts and children)

#2012
This commit is contained in:
Wojtek Figat
2025-01-31 10:21:05 +01:00
parent b1392be3a1
commit 42fc62eb68
2 changed files with 42 additions and 2 deletions

View File

@@ -3,6 +3,7 @@
#include "Actor.h"
#include "ActorsCache.h"
#include "Level.h"
#include "SceneQuery.h"
#include "SceneObjectsFactory.h"
#include "Scene/Scene.h"
#include "Prefabs/Prefab.h"
@@ -1880,8 +1881,7 @@ String Actor::ToJson()
CompactJsonWriter writer(buffer);
writer.SceneObject(this);
String result;
const char* c = buffer.GetString();
result.SetUTF8(c, (int32)buffer.GetSize());
result.SetUTF8(buffer.GetString(), (int32)buffer.GetSize());
return result;
}
@@ -1909,6 +1909,41 @@ void Actor::FromJson(const StringAnsiView& json)
OnTransformChanged();
}
Actor* Actor::Clone()
{
// Collect actors to clone
auto actors = ActorsCache::ActorsListCache.Get();
actors->Add(this);
SceneQuery::GetAllActors(this, *actors);
// Serialize objects
MemoryWriteStream stream;
if (ToBytes(*actors, stream))
return nullptr;
// Remap object ids into a new ones
auto modifier = Cache::ISerializeModifier.Get();
for (int32 i = 0; i < actors->Count(); i++)
{
auto actor = actors->At(i);
if (!actor)
continue;
modifier->IdsMapping.Add(actor->GetID(), Guid::New());
for (int32 j = 0; j < actor->Scripts.Count(); j++)
{
const auto script = actor->Scripts[j];
if (script)
modifier->IdsMapping.Add(script->GetID(), Guid::New());
}
}
// Deserialize objects
Array<Actor*> output;
if (FromBytes(ToSpan(stream.GetHandle(), (int32)stream.GetPosition()), output, modifier.Value) || output.IsEmpty())
return nullptr;
return output[0];
}
void Actor::SetPhysicsScene(PhysicsScene* scene)
{
CHECK(scene);

View File

@@ -982,6 +982,11 @@ public:
/// <param name="json">The serialized actor data (state).</param>
API_FUNCTION() void FromJson(const StringAnsiView& json);
/// <summary>
/// Clones actor including all scripts and any child actors (whole scene tree). Objects are duplicated via serialization (any transient/non-saved state is ignored).
/// </summary>
API_FUNCTION() Actor* Clone();
public:
/// <summary>
/// Called when actor gets added to game systems. Occurs on BeginPlay event or when actor gets activated in hierarchy. Use this event to register object to other game system (eg. audio).