diff --git a/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs b/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs
index a6c4e6623..8c8c76561 100644
--- a/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs
@@ -1,6 +1,11 @@
-using FlaxEditor.CustomEditors.Editors;
+using FlaxEditor.Actions;
+using FlaxEditor.CustomEditors.Editors;
+using FlaxEditor.GUI;
+using FlaxEditor.GUI.ContextMenu;
+using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
+using System.Collections.Generic;
namespace FlaxEditor.CustomEditors.Dedicated;
@@ -10,6 +15,11 @@ namespace FlaxEditor.CustomEditors.Dedicated;
[CustomEditor(typeof(MissingScript)), DefaultEditor]
public class MissingScriptEditor : GenericEditor
{
+ DropPanel _dropPanel;
+ Button _replaceScriptButton;
+ CheckBox _shouldReplaceAllCheckbox;
+ CustomEditor _propertiesEditor;
+
///
public override void Initialize(LayoutElementsContainer layout)
{
@@ -18,9 +28,157 @@ public class MissingScriptEditor : GenericEditor
base.Initialize(layout);
return;
}
+ _dropPanel = dropPanel;
+ _dropPanel.HeaderTextColor = Color.OrangeRed;
- dropPanel.HeaderTextColor = Color.OrangeRed;
+ Panel replaceScriptPanel = new Panel
+ {
+ Parent = _dropPanel,
+ Height = 64,
+ };
+
+ _replaceScriptButton = new Button
+ {
+ Text = "Replace Script",
+ AnchorPreset = AnchorPresets.TopCenter,
+ Width = 240,
+ Height = 24,
+ X = -120,
+ Y = 0,
+ Parent = replaceScriptPanel,
+ };
+ _replaceScriptButton.Clicked += OnReplaceScriptButtonClicked;
+
+ Label replaceAllLabel = new Label
+ {
+ Text = "Replace All of Same Type",
+ AnchorPreset = AnchorPresets.BottomCenter,
+ Y = -34,
+ Parent = replaceScriptPanel,
+ };
+ replaceAllLabel.X -= FlaxEngine.GUI.Style.Current.FontSmall.MeasureText(replaceAllLabel.Text).X;
+
+ _shouldReplaceAllCheckbox = new CheckBox
+ {
+ TooltipText = "Wether or not to apply this script change to all scripts missing the same type.",
+ AnchorPreset = AnchorPresets.BottomCenter,
+ Y = -34,
+ Parent = replaceScriptPanel,
+ };
+
+ float centerDifference = (_shouldReplaceAllCheckbox.Right - replaceAllLabel.Left) / 2;
+ replaceAllLabel.X += centerDifference;
+ _shouldReplaceAllCheckbox.X += centerDifference;
base.Initialize(layout);
}
+
+ private List FindActorsWithMatchingMissingScript()
+ {
+ List missingScripts = new List();
+
+ foreach (Actor actor in Level.GetActors())
+ {
+ for (int scriptIndex = 0; scriptIndex < actor.ScriptsCount; scriptIndex++)
+ {
+ Script actorScript = actor.Scripts[scriptIndex];
+ if (actorScript is not MissingScript missingActorScript)
+ {
+ continue;
+ }
+
+ MissingScript currentMissing = Values[0] as MissingScript;
+ if (missingActorScript.MissingTypeName != currentMissing.MissingTypeName)
+ {
+ continue;
+ }
+
+ // Matching MissingScript.
+ missingScripts.Add(missingActorScript);
+ }
+ }
+
+ return missingScripts;
+ }
+
+ private void RunReplacementMulticast(List actions)
+ {
+ if (actions.Count == 0)
+ {
+ Editor.LogWarning("Failed to replace scripts!");
+ return;
+ }
+
+ var multiAction = new MultiUndoAction(actions);
+ multiAction.Do();
+ var presenter = ParentEditor.Presenter;
+ if (presenter != null)
+ {
+ presenter.Undo.AddAction(multiAction);
+ presenter.Control.Focus();
+ }
+ }
+
+ private void ReplaceScript(ScriptType script, bool replaceAllInScene)
+ {
+ var actions = new List(4);
+
+ List missingScripts = new List();
+ if (!replaceAllInScene)
+ {
+ missingScripts.Add(Values[0] as MissingScript);
+ } else
+ {
+ missingScripts = FindActorsWithMatchingMissingScript();
+ }
+
+ foreach (MissingScript missingScript in missingScripts)
+ {
+ AddRemoveScript addReplacementScriptAction = AddRemoveScript.Add(missingScript.Actor, script);
+ actions.Add(addReplacementScriptAction);
+ }
+ RunReplacementMulticast(actions);
+
+ for (int actionIdx = 0; actionIdx < actions.Count; actionIdx++)
+ {
+ AddRemoveScript addRemoveScriptAction = (AddRemoveScript) actions[actionIdx];
+ int orderInParent = addRemoveScriptAction.GetOrderInParent();
+
+ Script newScript = missingScripts[actionIdx].Actor.Scripts[orderInParent];
+ missingScripts[actionIdx].ReferenceScript = newScript;
+ }
+ actions.Clear();
+
+ foreach (MissingScript missingScript in missingScripts)
+ {
+ actions.Add(AddRemoveScript.Remove(missingScript));
+ }
+ RunReplacementMulticast(actions);
+ }
+
+ private void OnReplaceScriptButtonClicked()
+ {
+ var scripts = Editor.Instance.CodeEditing.Scripts.Get();
+ if (scripts.Count == 0)
+ {
+ // No scripts
+ var cm1 = new ContextMenu();
+ cm1.AddButton("No scripts in project");
+ cm1.Show(_dropPanel, _replaceScriptButton.BottomLeft);
+ return;
+ }
+
+ // Show context menu with list of scripts to add
+ var cm = new ItemsListContextMenu(180);
+ for (int i = 0; i < scripts.Count; i++)
+ {
+ cm.AddItem(new TypeSearchPopup.TypeItemView(scripts[i]));
+ }
+ // Get the parent (actor properties editor) of the parent (Scripts Editor) of our editor.
+ _propertiesEditor = ParentEditor.ParentEditor;
+
+ cm.ItemClicked += item => ReplaceScript((ScriptType)item.Tag, _shouldReplaceAllCheckbox.Checked);
+ cm.SortItems();
+ cm.Show(_dropPanel, _replaceScriptButton.BottomLeft - new Float2((cm.Width - _replaceScriptButton.Width) / 2, 0));
+ }
}
diff --git a/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs b/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs
index a5710494c..86afd4c0b 100644
--- a/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs
+++ b/Source/Editor/Undo/Actions/AddRemoveScriptAction.cs
@@ -75,6 +75,11 @@ namespace FlaxEditor.Actions
_enabled = true;
}
+ public int GetOrderInParent()
+ {
+ return _orderInParent;
+ }
+
///
/// Creates a new added script undo action.
///
@@ -184,6 +189,7 @@ namespace FlaxEditor.Actions
script.Parent = parentActor;
if (_orderInParent != -1)
script.OrderInParent = _orderInParent;
+ _orderInParent = script.OrderInParent; // Ensure _orderInParent is correct for script that want to use it.
if (_prefabObjectId != Guid.Empty)
SceneObject.Internal_LinkPrefab(Object.GetUnmanagedPtr(script), ref _prefabId, ref _prefabObjectId);
Editor.Instance.Scene.MarkSceneEdited(parentActor.Scene);