From b7dc0dd0044a0d8fe1b4183b132960706c8ff0dc Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 22 Apr 2024 18:11:25 +0200 Subject: [PATCH] Fix crash when removing Anim Event visual script that is used in opened Animation timeline #2471 --- .../Editor/Content/Items/VisualScriptItem.cs | 16 ++++++++++ .../Timeline/Tracks/AnimationEventTrack.cs | 32 +++++++++++++++---- Source/Editor/Scripting/ScriptType.Custom.cs | 6 ++++ .../Editor/Scripting/ScriptType.Interfaces.cs | 6 ++++ Source/Editor/Scripting/ScriptType.cs | 18 ++++++++--- .../Editor/Surface/Archetypes/BehaviorTree.cs | 11 +++++++ 6 files changed, 78 insertions(+), 11 deletions(-) diff --git a/Source/Editor/Content/Items/VisualScriptItem.cs b/Source/Editor/Content/Items/VisualScriptItem.cs index 1d2e6a0bc..b99125f9b 100644 --- a/Source/Editor/Content/Items/VisualScriptItem.cs +++ b/Source/Editor/Content/Items/VisualScriptItem.cs @@ -249,6 +249,7 @@ namespace FlaxEditor.Content private ScriptMemberInfo[] _parameters; private ScriptMemberInfo[] _methods; private object[] _attributes; + private List> _disposing; /// /// Gets the Visual Script asset that contains this type. @@ -310,6 +311,13 @@ namespace FlaxEditor.Content internal void Dispose() { + if (_disposing != null) + { + foreach (var e in _disposing) + e(new ScriptType(this)); + _disposing.Clear(); + _disposing = null; + } if (_parameters != null) { OnAssetReloading(_asset); @@ -510,6 +518,14 @@ namespace FlaxEditor.Content } return _methods; } + + /// + public void TrackLifetime(Action disposing) + { + if (_disposing == null) + _disposing = new List>(); + _disposing.Add(disposing); + } } /// diff --git a/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs b/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs index ef0cef279..bf46e36ab 100644 --- a/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs @@ -99,6 +99,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks if (Type == ScriptType.Null) { Editor.LogError("Missing anim event type " + _instanceTypeName); + InitMissing(); return; } Instance = (AnimEvent)Type.CreateInstance(); @@ -125,20 +126,37 @@ namespace FlaxEditor.GUI.Timeline.Tracks _isRegisteredForScriptsReload = true; ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin; } + Type.TrackLifetime(OnTypeDisposing); + } + + private void OnTypeDisposing(ScriptType type) + { + if (Type == type && !IsDisposing) + { + // Turn into missing script + OnScriptsReloadBegin(); + ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd; + InitMissing(); + } + } + + private void InitMissing() + { + CanDelete = true; + CanSplit = false; + CanResize = false; + TooltipText = $"Missing Anim Event Type '{_instanceTypeName}'"; + BackgroundColor = Color.Red; + Type = ScriptType.Null; + Instance = null; } internal void InitMissing(string typeName, byte[] data) { - Type = ScriptType.Null; IsContinuous = false; - CanDelete = true; - CanSplit = false; - CanResize = false; - TooltipText = $"Missing Anim Event Type '{typeName}'"; - Instance = null; - BackgroundColor = Color.Red; _instanceTypeName = typeName; _instanceData = data; + InitMissing(); } internal void Load(BinaryReader stream) diff --git a/Source/Editor/Scripting/ScriptType.Custom.cs b/Source/Editor/Scripting/ScriptType.Custom.cs index 6da34f448..49bdd6013 100644 --- a/Source/Editor/Scripting/ScriptType.Custom.cs +++ b/Source/Editor/Scripting/ScriptType.Custom.cs @@ -144,5 +144,11 @@ namespace FlaxEditor.Scripting { return Utils.GetEmptyArray(); } + + /// + public void TrackLifetime(Action disposing) + { + ElementType.TrackLifetime(disposing); + } } } diff --git a/Source/Editor/Scripting/ScriptType.Interfaces.cs b/Source/Editor/Scripting/ScriptType.Interfaces.cs index 2aac4babc..01a4755ec 100644 --- a/Source/Editor/Scripting/ScriptType.Interfaces.cs +++ b/Source/Editor/Scripting/ScriptType.Interfaces.cs @@ -167,6 +167,12 @@ namespace FlaxEditor.Scripting /// A bitmask comprised of one or more that specify how the search is conducted.-or- Zero (), to return an empty array. /// An array of member objects representing all methods defined for the current type that match the specified binding constraints.-or- An empty array of type member, if no methods are defined for the current type, or if none of the defined methods match the binding constraints. ScriptMemberInfo[] GetMethods(BindingFlags bindingAttr); + + /// + /// Registers delegate to be invoked upon script type disposal (except hot-reload in Editor via ). For example, can happen when user deleted Visual Script asset. + /// + /// Event to call when script type gets disposed (eg. removed asset). + void TrackLifetime(Action disposing); } /// diff --git a/Source/Editor/Scripting/ScriptType.cs b/Source/Editor/Scripting/ScriptType.cs index 5a5a3ac93..848fda30e 100644 --- a/Source/Editor/Scripting/ScriptType.cs +++ b/Source/Editor/Scripting/ScriptType.cs @@ -1395,11 +1395,21 @@ namespace FlaxEditor.Scripting } /// - /// Basic check to see if a type could be casted to another type + /// Registers delegate to be invoked upon script type disposal (except hot-reload in Editor via ). For example, can happen when user deleted Visual Script asset. + /// + /// Event to call when script type gets disposed (eg. removed asset). + public void TrackLifetime(Action disposing) + { + if (_custom != null) + _custom.TrackLifetime(disposing); + } + + /// + /// Basic check to see if a type could be cast to another type /// /// Source type /// Target type - /// True if the type can be casted + /// True if the type can be cast. public static bool CanCast(ScriptType from, ScriptType to) { if (from == to) @@ -1412,10 +1422,10 @@ namespace FlaxEditor.Scripting } /// - /// Basic check to see if this type could be casted to another type + /// Basic check to see if this type could be cast to another type /// /// Target type - /// True if the type can be casted + /// True if the type can be cast. public bool CanCastTo(ScriptType to) { return CanCast(this, to); diff --git a/Source/Editor/Surface/Archetypes/BehaviorTree.cs b/Source/Editor/Surface/Archetypes/BehaviorTree.cs index 1fa4f8402..c4bb13c5e 100644 --- a/Source/Editor/Surface/Archetypes/BehaviorTree.cs +++ b/Source/Editor/Surface/Archetypes/BehaviorTree.cs @@ -104,6 +104,16 @@ namespace FlaxEditor.Surface.Archetypes } } + private void OnTypeDisposing(ScriptType type) + { + if (_type == type && !IsDisposing) + { + // Turn into missing script + _type = ScriptType.Null; + Instance = null; + } + } + public override void OnLoaded(SurfaceNodeActions action) { base.OnLoaded(action); @@ -113,6 +123,7 @@ namespace FlaxEditor.Surface.Archetypes _type = TypeUtils.GetType(typeName); if (_type != null) { + _type.TrackLifetime(OnTypeDisposing); TooltipText = Editor.Instance.CodeDocs.GetTooltip(_type); try {