Browse Source

Inspector :warning: when C# props might be out of date

Paul Joannon 1 year ago
parent
commit
0818d015db

+ 5 - 3
editor/plugins/script_text_editor.cpp

@@ -788,9 +788,7 @@ static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_curr
 }
 
 void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_for_script) {
-	if (!bool(EDITOR_GET("text_editor/external/use_external_editor"))) {
-		return;
-	}
+	bool use_external_editor = bool(EDITOR_GET("text_editor/external/use_external_editor"));
 
 	ERR_FAIL_NULL(get_tree());
 
@@ -804,6 +802,10 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo
 	for (const Ref<Script> &E : scripts) {
 		Ref<Script> scr = E;
 
+		if (!use_external_editor && !scr->get_language()->overrides_external_editor()) {
+			continue; // We're not using an external editor for this script.
+		}
+
 		if (p_for_script.is_valid() && p_for_script != scr) {
 			continue;
 		}

+ 11 - 0
modules/mono/csharp_script.cpp

@@ -2246,6 +2246,17 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
 			} else {
 				p_instance_to_update->update(propnames, values);
 			}
+		} else if (placeholders.size()) {
+			uint64_t script_modified_time = FileAccess::get_modified_time(get_path());
+			uint64_t last_valid_build_time = GDMono::get_singleton()->get_project_assembly_modified_time();
+			if (script_modified_time > last_valid_build_time) {
+				for (PlaceHolderScriptInstance *instance : placeholders) {
+					Object *owner = instance->get_owner();
+					if (owner->get_script_instance() == instance) {
+						owner->notify_property_list_changed();
+					}
+				}
+			}
 		}
 	}
 #endif

+ 38 - 0
modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs

@@ -9,6 +9,7 @@ using System.Linq;
 using GodotTools.Build;
 using GodotTools.Ides;
 using GodotTools.Ides.Rider;
+using GodotTools.Inspector;
 using GodotTools.Internals;
 using GodotTools.ProjectEditor;
 using JetBrains.Annotations;
@@ -45,6 +46,7 @@ namespace GodotTools
 
         // TODO Use WeakReference once we have proper serialization.
         private WeakRef _exportPluginWeak;
+        private WeakRef _inspectorPluginWeak;
 
         public GodotIdeManager GodotIdeManager { get; private set; }
 
@@ -52,6 +54,8 @@ namespace GodotTools
 
         public bool SkipBuildBeforePlaying { get; set; } = false;
 
+        public DateTime LastValidBuildDateTime { get; private set; }
+
         [UsedImplicitly]
         private bool CreateProjectSolutionIfNeeded()
         {
@@ -437,6 +441,21 @@ namespace GodotTools
             }
         }
 
+        private void UpdateLastValidBuildDateTime()
+        {
+            var dllName = $"{GodotSharpDirs.ProjectAssemblyName}.dll";
+            var path = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, "Debug", dllName);
+            LastValidBuildDateTime = File.GetLastWriteTime(path);
+        }
+
+        private void BuildFinished(BuildResult buildResult)
+        {
+            if (buildResult == BuildResult.Success)
+            {
+                UpdateLastValidBuildDateTime();
+            }
+        }
+
         private void BuildStateChanged()
         {
             if (_bottomPanelBtn != null)
@@ -447,6 +466,8 @@ namespace GodotTools
         {
             base._EnablePlugin();
 
+            UpdateLastValidBuildDateTime();
+
             ProjectSettings.SettingsChanged += GodotSharpDirs.DetermineProjectLocation;
 
             if (Instance != null)
@@ -615,6 +636,12 @@ namespace GodotTools
             AddExportPlugin(exportPlugin);
             _exportPluginWeak = WeakRef(exportPlugin);
 
+            // Inspector plugin
+            var inspectorPlugin = new InspectorPlugin();
+            AddInspectorPlugin(inspectorPlugin);
+            _inspectorPluginWeak = WeakRef(inspectorPlugin);
+            BuildManager.BuildFinished += BuildFinished;
+
             BuildManager.Initialize();
             RiderPathManager.Initialize();
 
@@ -627,6 +654,10 @@ namespace GodotTools
             base._DisablePlugin();
 
             _editorSettings.SettingsChanged -= OnSettingsChanged;
+
+            // Custom signals aren't automatically disconnected currently.
+            MSBuildPanel.BuildStateChanged -= BuildStateChanged;
+            BuildManager.BuildFinished -= BuildFinished;
         }
 
         public override void _ExitTree()
@@ -661,6 +692,13 @@ namespace GodotTools
                     _exportPluginWeak.Dispose();
                 }
 
+                if (IsInstanceValid(_inspectorPluginWeak))
+                {
+                    (_inspectorPluginWeak.GetRef().AsGodotObject() as InspectorPlugin)?.Dispose();
+
+                    _inspectorPluginWeak.Dispose();
+                }
+
                 GodotIdeManager?.Dispose();
             }
 

+ 37 - 0
modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorOutOfSyncWarning.cs

@@ -0,0 +1,37 @@
+using Godot;
+using GodotTools.Internals;
+
+namespace GodotTools.Inspector
+{
+    public partial class InspectorOutOfSyncWarning : HBoxContainer
+    {
+        public override void _Ready()
+        {
+            SetAnchorsPreset(LayoutPreset.TopWide);
+
+            var iconTexture = GetThemeIcon("StatusWarning", "EditorIcons");
+
+            var icon = new TextureRect()
+            {
+                Texture = iconTexture,
+                ExpandMode = TextureRect.ExpandModeEnum.FitWidthProportional,
+                CustomMinimumSize = iconTexture.GetSize(),
+            };
+
+            icon.SizeFlagsVertical = SizeFlags.ShrinkCenter;
+
+            var label = new Label()
+            {
+                Text = "This inspector might be out of date. Please build the C# project.".TTR(),
+                AutowrapMode = TextServer.AutowrapMode.WordSmart,
+                CustomMinimumSize = new Vector2(100f, 0f),
+            };
+
+            label.AddThemeColorOverride("font_color", GetThemeColor("warning_color", "Editor"));
+            label.SizeFlagsHorizontal = SizeFlags.Fill | SizeFlags.Expand;
+
+            AddChild(icon);
+            AddChild(label);
+        }
+    }
+}

+ 45 - 0
modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs

@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using Godot;
+using GodotTools.Utils;
+
+namespace GodotTools.Inspector
+{
+    public partial class InspectorPlugin : EditorInspectorPlugin
+    {
+        public override bool _CanHandle(GodotObject godotObject)
+        {
+            foreach (var script in EnumerateScripts(godotObject))
+            {
+                if (script is CSharpScript)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public override void _ParseBegin(GodotObject godotObject)
+        {
+            foreach (var script in EnumerateScripts(godotObject))
+            {
+                if (script is not CSharpScript) continue;
+
+                if (File.GetLastWriteTime(script.ResourcePath) > GodotSharpEditor.Instance.LastValidBuildDateTime)
+                {
+                    AddCustomControl(new InspectorOutOfSyncWarning());
+                    break;
+                }
+            }
+        }
+
+        private static IEnumerable<Script> EnumerateScripts(GodotObject godotObject)
+        {
+            var script = godotObject.GetScript().As<Script>();
+            while (script != null)
+            {
+                yield return script;
+                script = script.GetBaseScript();
+            }
+        }
+    }
+}