@@ -1676,6 +1676,9 @@ namespace FlaxEditor
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetPrefabNestedObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_GetPrefabNestedObject(IntPtr prefabId, IntPtr prefabObjectId, IntPtr outPrefabId, IntPtr outPrefabObjectId);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||
|
||||
|
||||
@@ -509,6 +509,21 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_INTERNAL_CALL(void) EditorInternal_GetPrefabNestedObject(Guid* prefabId, Guid* prefabObjectId, Guid* outPrefabId, Guid* outPrefabObjectId)
|
||||
{
|
||||
*outPrefabId = Guid::Empty;
|
||||
*outPrefabObjectId = Guid::Empty;
|
||||
const auto prefab = Content::Load<Prefab>(*prefabId);
|
||||
if (!prefab)
|
||||
return;
|
||||
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(*prefabObjectId);
|
||||
if (!prefabObjectDataPtr)
|
||||
return;
|
||||
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
|
||||
JsonTools::GetGuidIfValid(*outPrefabId, prefabObjectData, "PrefabID");
|
||||
JsonTools::GetGuidIfValid(*outPrefabObjectId, prefabObjectData, "PrefabObjectID");
|
||||
}
|
||||
|
||||
DEFINE_INTERNAL_CALL(float) EditorInternal_GetAnimationTime(AnimatedModel* animatedModel)
|
||||
{
|
||||
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;
|
||||
|
||||
@@ -17,6 +17,30 @@ namespace FlaxEditor.Actions
|
||||
[Serializable]
|
||||
sealed class BreakPrefabLinkAction : IUndoAction
|
||||
{
|
||||
private struct Item
|
||||
{
|
||||
public Guid ID;
|
||||
public Guid PrefabID;
|
||||
public Guid PrefabObjectID;
|
||||
|
||||
public unsafe Item(SceneObject obj, List<Item> nestedPrefabLinks)
|
||||
{
|
||||
ID = obj.ID;
|
||||
PrefabID = obj.PrefabID;
|
||||
PrefabObjectID = obj.PrefabObjectID;
|
||||
if (nestedPrefabLinks != null)
|
||||
{
|
||||
// Check if this object comes from another nested prefab (to break link only from the top-level prefab)
|
||||
Item nested;
|
||||
nested.ID = ID;
|
||||
fixed (Item* i = &this)
|
||||
Editor.Internal_GetPrefabNestedObject(new IntPtr(&i->PrefabID), new IntPtr(&i->PrefabObjectID), new IntPtr(&nested.PrefabID), new IntPtr(&nested.PrefabObjectID));
|
||||
if (nested.PrefabID != Guid.Empty && nested.PrefabObjectID != Guid.Empty)
|
||||
nestedPrefabLinks.Add(nested);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize]
|
||||
private readonly bool _isBreak;
|
||||
|
||||
@@ -24,25 +48,18 @@ namespace FlaxEditor.Actions
|
||||
private Guid _actorId;
|
||||
|
||||
[Serialize]
|
||||
private Guid _prefabId;
|
||||
private List<Item> _items = new();
|
||||
|
||||
[Serialize]
|
||||
private Dictionary<Guid, Guid> _prefabObjectIds;
|
||||
|
||||
private BreakPrefabLinkAction(bool isBreak, Guid actorId, Guid prefabId)
|
||||
private BreakPrefabLinkAction(bool isBreak, Guid actorId)
|
||||
{
|
||||
_isBreak = isBreak;
|
||||
_actorId = actorId;
|
||||
_prefabId = prefabId;
|
||||
}
|
||||
|
||||
private BreakPrefabLinkAction(bool isBreak, Actor actor)
|
||||
{
|
||||
_isBreak = isBreak;
|
||||
_actorId = actor.ID;
|
||||
_prefabId = actor.PrefabID;
|
||||
|
||||
_prefabObjectIds = new Dictionary<Guid, Guid>(1024);
|
||||
CollectIds(actor);
|
||||
}
|
||||
|
||||
@@ -55,7 +72,7 @@ namespace FlaxEditor.Actions
|
||||
{
|
||||
if (actor == null)
|
||||
throw new ArgumentNullException(nameof(actor));
|
||||
return new BreakPrefabLinkAction(true, actor.ID, Guid.Empty);
|
||||
return new BreakPrefabLinkAction(true, actor.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,53 +113,45 @@ namespace FlaxEditor.Actions
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_prefabObjectIds.Clear();
|
||||
_items.Clear();
|
||||
}
|
||||
|
||||
private void DoLink()
|
||||
{
|
||||
if (_prefabObjectIds == null)
|
||||
throw new Exception("Cannot link prefab. Missing objects Ids mapping.");
|
||||
|
||||
var actor = Object.Find<Actor>(ref _actorId);
|
||||
if (actor == null)
|
||||
throw new Exception("Cannot link prefab. Missing actor.");
|
||||
|
||||
// Restore cached links
|
||||
foreach (var e in _prefabObjectIds)
|
||||
{
|
||||
var objId = e.Key;
|
||||
var prefabObjId = e.Value;
|
||||
|
||||
var obj = Object.Find<Object>(ref objId);
|
||||
if (obj is Actor)
|
||||
{
|
||||
Actor.Internal_LinkPrefab(Object.GetUnmanagedPtr(obj), ref _prefabId, ref prefabObjId);
|
||||
}
|
||||
else if (obj is Script)
|
||||
{
|
||||
Script.Internal_LinkPrefab(Object.GetUnmanagedPtr(obj), ref _prefabId, ref prefabObjId);
|
||||
}
|
||||
}
|
||||
|
||||
Editor.Instance.Scene.MarkSceneEdited(actor.Scene);
|
||||
Editor.Instance.Windows.PropertiesWin.Presenter.BuildLayout();
|
||||
Link(_items);
|
||||
Refresh(actor);
|
||||
}
|
||||
|
||||
private void CollectIds(Actor actor)
|
||||
private void Link(List<Item> items)
|
||||
{
|
||||
_prefabObjectIds.Add(actor.ID, actor.PrefabObjectID);
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
var obj = Object.Find<Object>(ref item.ID);
|
||||
if (obj != null)
|
||||
SceneObject.Internal_LinkPrefab(Object.GetUnmanagedPtr(obj), ref item.PrefabID, ref item.PrefabObjectID);
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectIds(Actor actor, List<Item> nestedPrefabLinks = null)
|
||||
{
|
||||
_items.Add(new Item(actor, nestedPrefabLinks));
|
||||
|
||||
for (int i = 0; i < actor.ChildrenCount; i++)
|
||||
{
|
||||
CollectIds(actor.GetChild(i));
|
||||
}
|
||||
CollectIds(actor.GetChild(i), nestedPrefabLinks);
|
||||
|
||||
for (int i = 0; i < actor.ScriptsCount; i++)
|
||||
{
|
||||
var script = actor.GetScript(i);
|
||||
_prefabObjectIds.Add(script.ID, script.PrefabObjectID);
|
||||
}
|
||||
_items.Add(new Item(actor.GetScript(i), nestedPrefabLinks));
|
||||
}
|
||||
|
||||
private void Refresh(Actor actor)
|
||||
{
|
||||
Editor.Instance.Scene.MarkSceneEdited(actor.Scene);
|
||||
Editor.Instance.Windows.PropertiesWin.Presenter.BuildLayout();
|
||||
}
|
||||
|
||||
private void DoBreak()
|
||||
@@ -153,18 +162,18 @@ namespace FlaxEditor.Actions
|
||||
if (!actor.HasPrefabLink)
|
||||
throw new Exception("Cannot break missing prefab link.");
|
||||
|
||||
if (_prefabObjectIds == null)
|
||||
_prefabObjectIds = new Dictionary<Guid, Guid>(1024);
|
||||
else
|
||||
_prefabObjectIds.Clear();
|
||||
CollectIds(actor);
|
||||
|
||||
_prefabId = actor.PrefabID;
|
||||
// Cache 'prev' state and extract any nested prefab instances to remain
|
||||
_items.Clear();
|
||||
var nestedPrefabLinks = new List<Item>();
|
||||
CollectIds(actor, nestedPrefabLinks);
|
||||
|
||||
// Break prefab linkage
|
||||
actor.BreakPrefabLink();
|
||||
|
||||
Editor.Instance.Scene.MarkSceneEdited(actor.Scene);
|
||||
Editor.Instance.Windows.PropertiesWin.Presenter.BuildLayout();
|
||||
// Restore prefab link for nested instances
|
||||
Link(nestedPrefabLinks);
|
||||
|
||||
Refresh(actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user