fix: Changed flag management to EditorPrefs (#408)
* fix: Changed flag management to EditorPrefs * refactor: Improve code readability and error handling in MCP window toggle * fix: Refactor MCP window toggle logic to use new helper methods for better readability and maintainability * fix: Reorder using directives and improve error logging format in MCP window * Address CodeRabbit feedback: use McpLog.Warn and guard against repeated CreateGUI calls --------- Co-authored-by: David Sarno <david@lighthaus.us>main
parent
0d6c274e3c
commit
b57a2ece9d
|
|
@ -5,42 +5,25 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace MCPForUnity.Editor.MenuItems
|
namespace MCPForUnity.Editor.MenuItems
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Centralized menu items for MCP For Unity
|
|
||||||
/// </summary>
|
|
||||||
public static class MCPForUnityMenu
|
public static class MCPForUnityMenu
|
||||||
{
|
{
|
||||||
// ========================================
|
|
||||||
// Main Menu Items
|
|
||||||
// ========================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Show the Setup Window
|
|
||||||
/// </summary>
|
|
||||||
[MenuItem("Window/MCP For Unity/Setup Window", priority = 1)]
|
[MenuItem("Window/MCP For Unity/Setup Window", priority = 1)]
|
||||||
public static void ShowSetupWindow()
|
public static void ShowSetupWindow()
|
||||||
{
|
{
|
||||||
SetupWindowService.ShowSetupWindow();
|
SetupWindowService.ShowSetupWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Toggle the main MCP For Unity window
|
|
||||||
/// </summary>
|
|
||||||
[MenuItem("Window/MCP For Unity/Toggle MCP Window %#m", priority = 2)]
|
[MenuItem("Window/MCP For Unity/Toggle MCP Window %#m", priority = 2)]
|
||||||
public static void ToggleMCPWindow()
|
public static void ToggleMCPWindow()
|
||||||
{
|
{
|
||||||
if (EditorWindow.HasOpenInstances<MCPForUnityEditorWindow>())
|
if (MCPForUnityEditorWindow.HasAnyOpenWindow())
|
||||||
{
|
{
|
||||||
foreach (var window in UnityEngine.Resources.FindObjectsOfTypeAll<MCPForUnityEditorWindow>())
|
MCPForUnityEditorWindow.CloseAllOpenWindows();
|
||||||
{
|
|
||||||
window.Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MCPForUnityEditorWindow.ShowWindow();
|
MCPForUnityEditorWindow.ShowWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ namespace MCPForUnity.Editor.Setup
|
||||||
{
|
{
|
||||||
private const string SETUP_COMPLETED_KEY = EditorPrefKeys.SetupCompleted;
|
private const string SETUP_COMPLETED_KEY = EditorPrefKeys.SetupCompleted;
|
||||||
private const string SETUP_DISMISSED_KEY = EditorPrefKeys.SetupDismissed;
|
private const string SETUP_DISMISSED_KEY = EditorPrefKeys.SetupDismissed;
|
||||||
private static bool _hasCheckedThisSession = false;
|
|
||||||
|
// Use SessionState to persist "checked this editor session" across domain reloads.
|
||||||
|
// SessionState survives assembly reloads within the same Editor session, which prevents
|
||||||
|
// the setup window from reappearing after code reloads / playmode transitions.
|
||||||
|
private const string SessionCheckedKey = "MCPForUnity.SetupWindowCheckedThisEditorSession";
|
||||||
|
|
||||||
static SetupWindowService()
|
static SetupWindowService()
|
||||||
{
|
{
|
||||||
|
|
@ -35,10 +39,12 @@ namespace MCPForUnity.Editor.Setup
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void CheckSetupNeeded()
|
private static void CheckSetupNeeded()
|
||||||
{
|
{
|
||||||
if (_hasCheckedThisSession)
|
// Ensure we only run once per Editor session (survives domain reloads).
|
||||||
|
// This avoids showing the setup dialog repeatedly when scripts recompile or Play mode toggles.
|
||||||
|
if (SessionState.GetBool(SessionCheckedKey, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_hasCheckedThisSession = true;
|
SessionState.SetBool(SessionCheckedKey, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -48,11 +54,16 @@ namespace MCPForUnity.Editor.Setup
|
||||||
bool userOverrodeHttpUrl = EditorPrefs.HasKey(EditorPrefKeys.HttpBaseUrl);
|
bool userOverrodeHttpUrl = EditorPrefs.HasKey(EditorPrefKeys.HttpBaseUrl);
|
||||||
|
|
||||||
// In Asset Store builds with a remote default URL (and no user override), skip the local setup wizard.
|
// In Asset Store builds with a remote default URL (and no user override), skip the local setup wizard.
|
||||||
if (!userOverrodeHttpUrl
|
if (
|
||||||
|
!userOverrodeHttpUrl
|
||||||
&& McpDistribution.Settings.skipSetupWindowWhenRemoteDefault
|
&& McpDistribution.Settings.skipSetupWindowWhenRemoteDefault
|
||||||
&& McpDistribution.Settings.IsRemoteDefault)
|
&& McpDistribution.Settings.IsRemoteDefault
|
||||||
|
)
|
||||||
{
|
{
|
||||||
McpLog.Info("Skipping Setup Window because this distribution ships with a hosted MCP URL. Open Window/MCP For Unity/Setup Window if you want to configure a local runtime.", always: false);
|
McpLog.Info(
|
||||||
|
"Skipping Setup Window because this distribution ships with a hosted MCP URL. Open Window/MCP For Unity/Setup Window if you want to configure a local runtime.",
|
||||||
|
always: false
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,7 +77,10 @@ namespace MCPForUnity.Editor.Setup
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
McpLog.Info("Setup Window skipped - previously completed or dismissed", always: false);
|
McpLog.Info(
|
||||||
|
"Setup Window skipped - previously completed or dismissed",
|
||||||
|
always: false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -108,6 +122,5 @@ namespace MCPForUnity.Editor.Setup
|
||||||
EditorPrefs.SetBool(SETUP_DISMISSED_KEY, true);
|
EditorPrefs.SetBool(SETUP_DISMISSED_KEY, true);
|
||||||
McpLog.Info("Setup marked as dismissed");
|
McpLog.Info("Setup marked as dismissed");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MCPForUnity.Editor.Helpers;
|
||||||
|
using MCPForUnity.Editor.Services;
|
||||||
|
using MCPForUnity.Editor.Windows.Components.ClientConfig;
|
||||||
|
using MCPForUnity.Editor.Windows.Components.Connection;
|
||||||
|
using MCPForUnity.Editor.Windows.Components.Settings;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
using MCPForUnity.Editor.Helpers;
|
|
||||||
using MCPForUnity.Editor.Services;
|
|
||||||
using MCPForUnity.Editor.Windows.Components.Settings;
|
|
||||||
using MCPForUnity.Editor.Windows.Components.Connection;
|
|
||||||
using MCPForUnity.Editor.Windows.Components.ClientConfig;
|
|
||||||
|
|
||||||
namespace MCPForUnity.Editor.Windows
|
namespace MCPForUnity.Editor.Windows
|
||||||
{
|
{
|
||||||
|
|
@ -20,14 +20,47 @@ namespace MCPForUnity.Editor.Windows
|
||||||
private McpClientConfigSection clientConfigSection;
|
private McpClientConfigSection clientConfigSection;
|
||||||
|
|
||||||
private static readonly HashSet<MCPForUnityEditorWindow> OpenWindows = new();
|
private static readonly HashSet<MCPForUnityEditorWindow> OpenWindows = new();
|
||||||
|
private bool guiCreated = false;
|
||||||
|
|
||||||
public static void ShowWindow()
|
public static void ShowWindow()
|
||||||
{
|
{
|
||||||
var window = GetWindow<MCPForUnityEditorWindow>("MCP For Unity");
|
var window = GetWindow<MCPForUnityEditorWindow>("MCP For Unity");
|
||||||
window.minSize = new Vector2(500, 600);
|
window.minSize = new Vector2(500, 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to check and manage open windows from other classes
|
||||||
|
public static bool HasAnyOpenWindow()
|
||||||
|
{
|
||||||
|
return OpenWindows.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CloseAllOpenWindows()
|
||||||
|
{
|
||||||
|
if (OpenWindows.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Copy to array to avoid modifying the collection while iterating
|
||||||
|
var arr = new MCPForUnityEditorWindow[OpenWindows.Count];
|
||||||
|
OpenWindows.CopyTo(arr);
|
||||||
|
foreach (var window in arr)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
window?.Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
McpLog.Warn($"Error closing MCP window: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CreateGUI()
|
public void CreateGUI()
|
||||||
{
|
{
|
||||||
|
// Guard against repeated CreateGUI calls (e.g., domain reloads)
|
||||||
|
if (guiCreated)
|
||||||
|
return;
|
||||||
|
|
||||||
string basePath = AssetPathUtility.GetMcpPackageRootPath();
|
string basePath = AssetPathUtility.GetMcpPackageRootPath();
|
||||||
|
|
||||||
// Load main window UXML
|
// Load main window UXML
|
||||||
|
|
@ -37,7 +70,9 @@ namespace MCPForUnity.Editor.Windows
|
||||||
|
|
||||||
if (visualTree == null)
|
if (visualTree == null)
|
||||||
{
|
{
|
||||||
McpLog.Error($"Failed to load UXML at: {basePath}/Editor/Windows/MCPForUnityEditorWindow.uxml");
|
McpLog.Error(
|
||||||
|
$"Failed to load UXML at: {basePath}/Editor/Windows/MCPForUnityEditorWindow.uxml"
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,8 +113,10 @@ namespace MCPForUnity.Editor.Windows
|
||||||
var settingsRoot = settingsTree.Instantiate();
|
var settingsRoot = settingsTree.Instantiate();
|
||||||
sectionsContainer.Add(settingsRoot);
|
sectionsContainer.Add(settingsRoot);
|
||||||
settingsSection = new McpSettingsSection(settingsRoot);
|
settingsSection = new McpSettingsSection(settingsRoot);
|
||||||
settingsSection.OnGitUrlChanged += () => clientConfigSection?.UpdateManualConfiguration();
|
settingsSection.OnGitUrlChanged += () =>
|
||||||
settingsSection.OnHttpServerCommandUpdateRequested += () => connectionSection?.UpdateHttpServerCommandDisplay();
|
clientConfigSection?.UpdateManualConfiguration();
|
||||||
|
settingsSection.OnHttpServerCommandUpdateRequested += () =>
|
||||||
|
connectionSection?.UpdateHttpServerCommandDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load and initialize Connection section
|
// Load and initialize Connection section
|
||||||
|
|
@ -91,7 +128,8 @@ namespace MCPForUnity.Editor.Windows
|
||||||
var connectionRoot = connectionTree.Instantiate();
|
var connectionRoot = connectionTree.Instantiate();
|
||||||
sectionsContainer.Add(connectionRoot);
|
sectionsContainer.Add(connectionRoot);
|
||||||
connectionSection = new McpConnectionSection(connectionRoot);
|
connectionSection = new McpConnectionSection(connectionRoot);
|
||||||
connectionSection.OnManualConfigUpdateRequested += () => clientConfigSection?.UpdateManualConfiguration();
|
connectionSection.OnManualConfigUpdateRequested += () =>
|
||||||
|
clientConfigSection?.UpdateManualConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load and initialize Client Configuration section
|
// Load and initialize Client Configuration section
|
||||||
|
|
@ -105,6 +143,8 @@ namespace MCPForUnity.Editor.Windows
|
||||||
clientConfigSection = new McpClientConfigSection(clientConfigRoot);
|
clientConfigSection = new McpClientConfigSection(clientConfigRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guiCreated = true;
|
||||||
|
|
||||||
// Initial updates
|
// Initial updates
|
||||||
RefreshAllData();
|
RefreshAllData();
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +159,7 @@ namespace MCPForUnity.Editor.Windows
|
||||||
{
|
{
|
||||||
EditorApplication.update -= OnEditorUpdate;
|
EditorApplication.update -= OnEditorUpdate;
|
||||||
OpenWindows.Remove(this);
|
OpenWindows.Remove(this);
|
||||||
|
guiCreated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFocus()
|
private void OnFocus()
|
||||||
|
|
@ -163,11 +204,11 @@ namespace MCPForUnity.Editor.Windows
|
||||||
{
|
{
|
||||||
EditorApplication.delayCall += async () =>
|
EditorApplication.delayCall += async () =>
|
||||||
{
|
{
|
||||||
if (this == null)
|
if (this == null || connectionSection == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await connectionSection?.VerifyBridgeConnectionAsync();
|
await connectionSection.VerifyBridgeConnectionAsync();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue