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