unity-mcp/MCPForUnity/Editor/Windows/EditorPrefs/EditorPrefsWindow.cs

348 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Helpers;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace MCPForUnity.Editor.Windows
{
/// <summary>
/// Editor window for managing Unity EditorPrefs, specifically for MCP For Unity development
/// </summary>
public class EditorPrefsWindow : EditorWindow
{
// UI Elements
private ScrollView scrollView;
private VisualElement prefsContainer;
// Data
private List<EditorPrefItem> currentPrefs = new List<EditorPrefItem>();
private HashSet<string> knownMcpKeys = new HashSet<string>();
// Type mapping for known EditorPrefs
private readonly Dictionary<string, EditorPrefType> knownPrefTypes = new Dictionary<string, EditorPrefType>
{
// Boolean prefs
{ EditorPrefKeys.DebugLogs, EditorPrefType.Bool },
{ EditorPrefKeys.UseHttpTransport, EditorPrefType.Bool },
{ EditorPrefKeys.ResumeHttpAfterReload, EditorPrefType.Bool },
{ EditorPrefKeys.ResumeStdioAfterReload, EditorPrefType.Bool },
{ EditorPrefKeys.UseEmbeddedServer, EditorPrefType.Bool },
{ EditorPrefKeys.LockCursorConfig, EditorPrefType.Bool },
{ EditorPrefKeys.AutoRegisterEnabled, EditorPrefType.Bool },
{ EditorPrefKeys.SetupCompleted, EditorPrefType.Bool },
{ EditorPrefKeys.SetupDismissed, EditorPrefType.Bool },
{ EditorPrefKeys.CustomToolRegistrationEnabled, EditorPrefType.Bool },
{ EditorPrefKeys.TelemetryDisabled, EditorPrefType.Bool },
// Integer prefs
{ EditorPrefKeys.UnitySocketPort, EditorPrefType.Int },
{ EditorPrefKeys.ValidationLevel, EditorPrefType.Int },
{ EditorPrefKeys.LastUpdateCheck, EditorPrefType.Int },
{ EditorPrefKeys.LastStdIoUpgradeVersion, EditorPrefType.Int },
// String prefs
{ EditorPrefKeys.EditorWindowActivePanel, EditorPrefType.String },
{ EditorPrefKeys.ClaudeCliPathOverride, EditorPrefType.String },
{ EditorPrefKeys.UvxPathOverride, EditorPrefType.String },
{ EditorPrefKeys.HttpBaseUrl, EditorPrefType.String },
{ EditorPrefKeys.SessionId, EditorPrefType.String },
{ EditorPrefKeys.WebSocketUrlOverride, EditorPrefType.String },
{ EditorPrefKeys.GitUrlOverride, EditorPrefType.String },
{ EditorPrefKeys.PackageDeploySourcePath, EditorPrefType.String },
{ EditorPrefKeys.PackageDeployLastBackupPath, EditorPrefType.String },
{ EditorPrefKeys.PackageDeployLastTargetPath, EditorPrefType.String },
{ EditorPrefKeys.PackageDeployLastSourcePath, EditorPrefType.String },
{ EditorPrefKeys.ServerSrc, EditorPrefType.String },
{ EditorPrefKeys.LatestKnownVersion, EditorPrefType.String },
};
// Templates
private VisualTreeAsset itemTemplate;
/// <summary>
/// Show the EditorPrefs window
/// </summary>
public static void ShowWindow()
{
var window = GetWindow<EditorPrefsWindow>("EditorPrefs");
window.minSize = new Vector2(600, 400);
window.Show();
}
public void CreateGUI()
{
string basePath = AssetPathUtility.GetMcpPackageRootPath();
// Load UXML
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{basePath}/Editor/Windows/EditorPrefs/EditorPrefsWindow.uxml"
);
if (visualTree == null)
{
Debug.LogError("Failed to load EditorPrefsWindow.uxml template");
return;
}
// Load item template
itemTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{basePath}/Editor/Windows/EditorPrefs/EditorPrefItem.uxml"
);
if (itemTemplate == null)
{
Debug.LogError("Failed to load EditorPrefItem.uxml template");
return;
}
visualTree.CloneTree(rootVisualElement);
// Get references
scrollView = rootVisualElement.Q<ScrollView>("scroll-view");
prefsContainer = rootVisualElement.Q<VisualElement>("prefs-container");
// Load known MCP keys
LoadKnownMcpKeys();
// Load initial data
RefreshPrefs();
}
private void LoadKnownMcpKeys()
{
knownMcpKeys.Clear();
var fields = typeof(EditorPrefKeys).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
foreach (var field in fields)
{
if (field.IsLiteral && !field.IsInitOnly)
{
knownMcpKeys.Add(field.GetValue(null).ToString());
}
}
}
private void RefreshPrefs()
{
currentPrefs.Clear();
prefsContainer.Clear();
// Get all EditorPrefs keys
var allKeys = new List<string>();
// Always show all MCP keys
allKeys.AddRange(knownMcpKeys);
// Try to find additional MCP keys
var mcpKeys = GetAllMcpKeys();
foreach (var key in mcpKeys)
{
if (!allKeys.Contains(key))
{
allKeys.Add(key);
}
}
// Sort keys
allKeys.Sort();
// Create items for existing prefs
foreach (var key in allKeys)
{
// Skip Customer UUID but show everything else that's defined
if (key != EditorPrefKeys.CustomerUuid)
{
var item = CreateEditorPrefItem(key);
if (item != null)
{
currentPrefs.Add(item);
prefsContainer.Add(CreateItemUI(item));
}
}
}
}
private List<string> GetAllMcpKeys()
{
// This is a simplified approach - in reality, getting all EditorPrefs is platform-specific
// For now, we'll return known MCP keys that might exist
var keys = new List<string>();
// Add some common MCP keys that might not be in EditorPrefKeys
keys.Add("MCPForUnity.TestKey");
// Filter to only those that actually exist
return keys.Where(EditorPrefs.HasKey).ToList();
}
private EditorPrefItem CreateEditorPrefItem(string key)
{
var item = new EditorPrefItem { Key = key, IsKnown = knownMcpKeys.Contains(key) };
// Check if we know the type of this pref
if (knownPrefTypes.TryGetValue(key, out var knownType))
{
// Use the known type
switch (knownType)
{
case EditorPrefType.Bool:
item.Type = EditorPrefType.Bool;
item.Value = EditorPrefs.GetBool(key, false).ToString();
break;
case EditorPrefType.Int:
item.Type = EditorPrefType.Int;
item.Value = EditorPrefs.GetInt(key, 0).ToString();
break;
case EditorPrefType.Float:
item.Type = EditorPrefType.Float;
item.Value = EditorPrefs.GetFloat(key, 0f).ToString();
break;
case EditorPrefType.String:
item.Type = EditorPrefType.String;
item.Value = EditorPrefs.GetString(key, "");
break;
}
}
else
{
// Only try to detect type for unknown keys that actually exist
if (!EditorPrefs.HasKey(key))
{
// Key doesn't exist and we don't know its type, skip it
return null;
}
// Unknown pref - try to detect type
var stringValue = EditorPrefs.GetString(key, "");
if (int.TryParse(stringValue, out var intValue))
{
item.Type = EditorPrefType.Int;
item.Value = intValue.ToString();
}
else if (float.TryParse(stringValue, out var floatValue))
{
item.Type = EditorPrefType.Float;
item.Value = floatValue.ToString();
}
else if (bool.TryParse(stringValue, out var boolValue))
{
item.Type = EditorPrefType.Bool;
item.Value = boolValue.ToString();
}
else
{
item.Type = EditorPrefType.String;
item.Value = stringValue;
}
}
return item;
}
private VisualElement CreateItemUI(EditorPrefItem item)
{
if (itemTemplate == null)
{
Debug.LogError("Item template not loaded");
return new VisualElement();
}
var itemElement = itemTemplate.CloneTree();
// Set values
itemElement.Q<Label>("key-label").text = item.Key;
var valueField = itemElement.Q<TextField>("value-field");
valueField.value = item.Value;
var typeDropdown = itemElement.Q<DropdownField>("type-dropdown");
typeDropdown.index = (int)item.Type;
// Buttons
var saveButton = itemElement.Q<Button>("save-button");
// Callbacks
saveButton.clicked += () => SavePref(item, valueField.value, (EditorPrefType)typeDropdown.index);
return itemElement;
}
private void SavePref(EditorPrefItem item, string newValue, EditorPrefType newType)
{
SaveValue(item.Key, newValue, newType);
RefreshPrefs();
}
private void SaveValue(string key, string value, EditorPrefType type)
{
switch (type)
{
case EditorPrefType.String:
EditorPrefs.SetString(key, value);
break;
case EditorPrefType.Int:
if (int.TryParse(value, out var intValue))
{
EditorPrefs.SetInt(key, intValue);
}
else
{
EditorUtility.DisplayDialog("Error", $"Cannot convert '{value}' to int", "OK");
return;
}
break;
case EditorPrefType.Float:
if (float.TryParse(value, out var floatValue))
{
EditorPrefs.SetFloat(key, floatValue);
}
else
{
EditorUtility.DisplayDialog("Error", $"Cannot convert '{value}' to float", "OK");
return;
}
break;
case EditorPrefType.Bool:
if (bool.TryParse(value, out var boolValue))
{
EditorPrefs.SetBool(key, boolValue);
}
else
{
EditorUtility.DisplayDialog("Error", $"Cannot convert '{value}' to bool (use 'True' or 'False')", "OK");
return;
}
break;
}
}
}
/// <summary>
/// Represents an EditorPrefs item
/// </summary>
public class EditorPrefItem
{
public string Key { get; set; }
public string Value { get; set; }
public EditorPrefType Type { get; set; }
public bool IsKnown { get; set; }
}
/// <summary>
/// EditorPrefs value types
/// </summary>
public enum EditorPrefType
{
String,
Int,
Float,
Bool
}
}