From 204e95a6001d2033d5bb9a3829cd78bb7bf229d5 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Sun, 11 Jan 2026 19:22:58 +0800 Subject: [PATCH 01/23] fix: resolve UV path override not being detected in System Requirements Fixes #538 The System Requirements panel showed "UV Package Manager: Not Found" even when a valid UV path override was configured in Advanced Settings. Root cause: PlatformDetectorBase.DetectUv() only searched PATH with bare command names ("uvx", "uv") and never consulted PathResolverService which respects the user's override setting. Changes: - Refactor DetectUv() to use PathResolverService.GetUvxPath() which checks override path first, then system PATH, then falls back to "uvx" - Add TryValidateUvExecutable() to verify executables by running --version instead of just checking File.Exists - Prioritize PATH environment variable in EnumerateUvxCandidates() for better compatibility with official uv install scripts - Fix process output read order (ReadToEnd before WaitForExit) to prevent potential deadlocks Co-Authored-By: ChatGLM 4.7 --- .../LinuxPlatformDetector.cs | 30 +++- .../MacOSPlatformDetector.cs | 31 +++- .../PlatformDetectors/PlatformDetectorBase.cs | 61 ++----- .../Editor/Services/IPathResolverService.cs | 8 + .../Editor/Services/PathResolverService.cs | 157 ++++++++++++++++-- .../Components/Settings/McpSettingsSection.cs | 15 +- 6 files changed, 211 insertions(+), 91 deletions(-) diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs index 1c5bf4587..ac3a09ef2 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.Services; namespace MCPForUnity.Editor.Dependencies.PlatformDetectors { @@ -92,10 +93,18 @@ public override string GetInstallationRecommendations() public override DependencyStatus DetectUv() { - var status = new DependencyStatus("uv Package Manager", isRequired: true) + // First, honor overrides and cross-platform resolution via the base implementation + var status = base.DetectUv(); + if (status.IsAvailable) { - InstallationHint = GetUvInstallUrl() - }; + return status; + } + + // If the user configured an override path, keep the base result (failure typically means the override path is invalid) + if (MCPServiceLocator.Paths.HasUvxPathOverride) + { + return status; + } try { @@ -107,6 +116,7 @@ public override DependencyStatus DetectUv() status.Version = version; status.Path = fullPath; status.Details = $"Found uv {version} in PATH"; + status.ErrorMessage = null; return status; } @@ -120,6 +130,7 @@ public override DependencyStatus DetectUv() status.Version = version; status.Path = fullPath; status.Details = $"Found uv {version} in PATH"; + status.ErrorMessage = null; return status; } } @@ -217,11 +228,16 @@ private bool TryValidateUv(string uvPath, out string version, out string fullPat string output = process.StandardOutput.ReadToEnd().Trim(); process.WaitForExit(5000); - if (process.ExitCode == 0 && output.StartsWith("uv ")) + if (process.ExitCode == 0 && (output.StartsWith("uv ") || output.StartsWith("uvx "))) { - version = output.Substring(3).Trim(); - fullPath = uvPath; - return true; + // Extract version: "uvx 0.9.18" -> "0.9.18" + int spaceIndex = output.IndexOf(' '); + if (spaceIndex >= 0) + { + version = output.Substring(spaceIndex + 1).Trim(); + fullPath = uvPath; + return true; + } } } catch diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs index 0f9c6e112..0c5946d77 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.Services; namespace MCPForUnity.Editor.Dependencies.PlatformDetectors { @@ -90,10 +91,18 @@ public override string GetInstallationRecommendations() public override DependencyStatus DetectUv() { - var status = new DependencyStatus("uv Package Manager", isRequired: true) + // First, honor overrides and cross-platform resolution via the base implementation + var status = base.DetectUv(); + if (status.IsAvailable) { - InstallationHint = GetUvInstallUrl() - }; + return status; + } + + // If the user provided an override path, keep the base result (failure likely means the override is invalid) + if (MCPServiceLocator.Paths.HasUvxPathOverride) + { + return status; + } try { @@ -105,6 +114,7 @@ public override DependencyStatus DetectUv() status.Version = version; status.Path = fullPath; status.Details = $"Found uv {version} in PATH"; + status.ErrorMessage = null; return status; } @@ -118,6 +128,7 @@ public override DependencyStatus DetectUv() status.Version = version; status.Path = fullPath; status.Details = $"Found uv {version} in PATH"; + status.ErrorMessage = null; return status; } } @@ -212,14 +223,20 @@ private bool TryValidateUv(string uvPath, out string version, out string fullPat using var process = Process.Start(psi); if (process == null) return false; + string output = process.StandardOutput.ReadToEnd().Trim(); process.WaitForExit(5000); - if (process.ExitCode == 0 && output.StartsWith("uv ")) + if (process.ExitCode == 0 && (output.StartsWith("uv ") || output.StartsWith("uvx "))) { - version = output.Substring(3).Trim(); - fullPath = uvPath; - return true; + // Extract version: "uvx 0.9.18" -> "0.9.18" + int spaceIndex = output.IndexOf(' '); + if (spaceIndex >= 0) + { + version = output.Substring(spaceIndex + 1).Trim(); + fullPath = uvPath; + return true; + } } } catch diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs index dd554aff4..77edd19c4 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs @@ -1,6 +1,6 @@ using System; -using System.Diagnostics; using MCPForUnity.Editor.Dependencies.Models; +using MCPForUnity.Editor.Services; namespace MCPForUnity.Editor.Dependencies.PlatformDetectors { @@ -26,18 +26,23 @@ public virtual DependencyStatus DetectUv() try { - // Try to find uv/uvx in PATH - if (TryFindUvInPath(out string uvPath, out string version)) + // Get uv path from PathResolverService (respects override) + string uvPath = MCPServiceLocator.Paths.GetUvxPath(); + + // Verify uv executable and get version + if (MCPServiceLocator.Paths.TryValidateUvExecutable(uvPath, out string version)) { status.IsAvailable = true; status.Version = version; status.Path = uvPath; - status.Details = $"Found uv {version} in PATH"; + status.Details = MCPServiceLocator.Paths.HasUvxPathOverride + ? $"Found uv {version} (override path)" + : $"Found uv {version} in system path"; return status; } - status.ErrorMessage = "uv not found in PATH"; - status.Details = "Install uv package manager and ensure it's added to PATH."; + status.ErrorMessage = "uv not found"; + status.Details = "Install uv package manager or configure path override in Advanced Settings."; } catch (Exception ex) { @@ -47,50 +52,6 @@ public virtual DependencyStatus DetectUv() return status; } - protected bool TryFindUvInPath(out string uvPath, out string version) - { - uvPath = null; - version = null; - - // Try common uv command names - var commands = new[] { "uvx", "uv" }; - - foreach (var cmd in commands) - { - try - { - var psi = new ProcessStartInfo - { - FileName = cmd, - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - using var process = Process.Start(psi); - if (process == null) continue; - - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(5000); - - if (process.ExitCode == 0 && output.StartsWith("uv ")) - { - version = output.Substring(3).Trim(); - uvPath = cmd; - return true; - } - } - catch - { - // Try next command - } - } - - return false; - } - protected bool TryParseVersion(string version, out int major, out int minor) { major = 0; diff --git a/MCPForUnity/Editor/Services/IPathResolverService.cs b/MCPForUnity/Editor/Services/IPathResolverService.cs index 104c31134..a5d7cd190 100644 --- a/MCPForUnity/Editor/Services/IPathResolverService.cs +++ b/MCPForUnity/Editor/Services/IPathResolverService.cs @@ -60,5 +60,13 @@ public interface IPathResolverService /// Gets whether a Claude CLI path override is active /// bool HasClaudeCliPathOverride { get; } + + /// + /// Validates the provided uv executable by running "--version" and parsing the output. + /// + /// Absolute or relative path to the uv/uvx executable. + /// Parsed version string if successful. + /// True when the executable runs and returns a uv version string. + bool TryValidateUvExecutable(string uvPath, out string version); } } diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index 4947a16d8..03348c8b9 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -154,6 +154,25 @@ private static IEnumerable EnumerateUvxCandidates() { string exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "uvx.exe" : "uvx"; + // Priority 1: User-configured PATH (most common scenario from official install scripts) + string pathEnv = Environment.GetEnvironmentVariable("PATH"); + if (!string.IsNullOrEmpty(pathEnv)) + { + foreach (string rawDir in pathEnv.Split(Path.PathSeparator)) + { + if (string.IsNullOrWhiteSpace(rawDir)) continue; + string dir = rawDir.Trim(); + yield return Path.Combine(dir, exeName); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Some PATH entries may already contain the file without extension + yield return Path.Combine(dir, "uvx"); + } + } + } + + // Priority 2: User directories string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); if (!string.IsNullOrEmpty(home)) { @@ -161,6 +180,7 @@ private static IEnumerable EnumerateUvxCandidates() yield return Path.Combine(home, ".cargo", "bin", exeName); } + // Priority 3: System directories (platform-specific) if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { yield return "/opt/homebrew/bin/" + exeName; @@ -173,6 +193,7 @@ private static IEnumerable EnumerateUvxCandidates() } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + // Priority 4: Windows-specific program directories string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); @@ -186,23 +207,6 @@ private static IEnumerable EnumerateUvxCandidates() yield return Path.Combine(programFiles, "uv", exeName); } } - - string pathEnv = Environment.GetEnvironmentVariable("PATH"); - if (!string.IsNullOrEmpty(pathEnv)) - { - foreach (string rawDir in pathEnv.Split(Path.PathSeparator)) - { - if (string.IsNullOrWhiteSpace(rawDir)) continue; - string dir = rawDir.Trim(); - yield return Path.Combine(dir, exeName); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - // Some PATH entries may already contain the file without extension - yield return Path.Combine(dir, "uvx"); - } - } - } } public void SetUvxPathOverride(string path) @@ -246,5 +250,124 @@ public void ClearClaudeCliPathOverride() { EditorPrefs.DeleteKey(EditorPrefKeys.ClaudeCliPathOverride); } + + /// + /// Validates the provided uv executable by running "--version" and parsing the output. + /// + /// Absolute or relative path to the uv/uvx executable. + /// Parsed version string if successful. + /// True when the executable runs and returns a uv version string. + public bool TryValidateUvExecutable(string uvPath, out string version) + { + version = null; + + if (string.IsNullOrEmpty(uvPath)) + return false; + + try + { + // Check if the path is just a command name (no directory separator) + bool isBareCommand = !uvPath.Contains('/') && !uvPath.Contains('\\'); + // McpLog.Debug($"TryValidateUvExecutable: path='{uvPath}', isBare={isBareCommand}"); + + ProcessStartInfo psi; + if (isBareCommand) + { + // For bare commands like "uvx", use where/which to find full path first + string fullPath = FindExecutableInPath(uvPath); + if (string.IsNullOrEmpty(fullPath)) + { + // McpLog.Debug($"TryValidateUvExecutable: Could not find '{uvPath}' in PATH"); + return false; + } + // McpLog.Debug($"TryValidateUvExecutable: Found full path: '{fullPath}'"); + uvPath = fullPath; + } + + // Execute the command (full path) + psi = new ProcessStartInfo + { + FileName = uvPath, + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + using var process = Process.Start(psi); + if (process == null) + return false; + + + string output = process.StandardOutput.ReadToEnd().Trim(); + string error = process.StandardError.ReadToEnd().Trim(); + // wait for the process to exit with a timeout of 5000ms (5 seconds) + if (!process.WaitForExit(5000)) return false; + + // McpLog.Debug($"TryValidateUvExecutable: exitCode={process.ExitCode}, stdout='{output}', stderr='{error}'"); + + // Check stdout first, then stderr (some tools output to stderr) + string versionOutput = !string.IsNullOrEmpty(output) ? output : error; + + // uvx outputs "uvx x.y.z" or "uv x.y.z", extract version number + if (process.ExitCode == 0 && + (versionOutput.StartsWith("uv ") || versionOutput.StartsWith("uvx "))) + { + // Extract version: "uvx 0.9.18 (hash date)" -> "0.9.18" + int spaceIndex = versionOutput.IndexOf(' '); + if (spaceIndex >= 0) + { + string afterCommand = versionOutput.Substring(spaceIndex + 1).Trim(); + // Version is up to the first space or parenthesis + int parenIndex = afterCommand.IndexOf('('); + version = parenIndex > 0 + ? afterCommand.Substring(0, parenIndex).Trim() + : afterCommand.Split(' ')[0]; + // McpLog.Debug($"TryValidateUvExecutable: SUCCESS - version={version}"); + return true; + } + } + // McpLog.Debug($"TryValidateUvExecutable: FAILED - exitCode={process.ExitCode}"); + } + //catch (Exception ex) + catch + { + // McpLog.Debug($"TryValidateUvExecutable: EXCEPTION - {ex.Message}"); + } + + return false; + } + + private string FindExecutableInPath(string commandName) + { + try + { + string exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !commandName.EndsWith(".exe") + ? commandName + ".exe" + : commandName; + + // First try EnumerateUvxCandidates which checks File.Exists + foreach (string candidate in EnumerateUvxCandidates()) + { + if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate)) + { + // Check if this candidate matches our command name + string candidateName = Path.GetFileName(candidate); + if (candidateName.Equals(exeName, StringComparison.OrdinalIgnoreCase) || + candidateName.Equals(commandName, StringComparison.OrdinalIgnoreCase)) + { + return candidate; + } + } + } + } + catch + { + // Ignore errors + } + + return null; + } } } diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs index 7f782f8ae..69739b630 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs @@ -197,20 +197,15 @@ public void UpdatePathOverrides() uvxPathStatus.RemoveFromClassList("valid"); uvxPathStatus.RemoveFromClassList("invalid"); - if (hasOverride) + + string actualUvxPath = MCPServiceLocator.Paths.GetUvxPath(); + if (MCPServiceLocator.Paths.TryValidateUvExecutable(actualUvxPath, out string version)) { - if (!string.IsNullOrEmpty(uvxPath) && File.Exists(uvxPath)) - { - uvxPathStatus.AddToClassList("valid"); - } - else - { - uvxPathStatus.AddToClassList("invalid"); - } + uvxPathStatus.AddToClassList("valid"); } else { - uvxPathStatus.AddToClassList("valid"); + uvxPathStatus.AddToClassList("invalid"); } gitUrlOverride.value = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, ""); From 25e5d0577085013822a2c375d61df45804395389 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Sun, 11 Jan 2026 19:46:27 +0800 Subject: [PATCH 02/23] fix: improve uv/uvx detection robustness on macOS and Linux - Read both stdout and stderr when validating uv/uvx executables - Respect WaitForExit timeout return value instead of ignoring it - Fix version parsing to handle extra tokens like "(Homebrew 2025-01-01)" - Resolve bare commands ("uv"/"uvx") to absolute paths after validation - Rename FindExecutableInPath to FindUvxExecutableInPath for clarity Co-Authored-By: Claude Opus 4.5 --- .../LinuxPlatformDetector.cs | 34 +++++++++++++++++-- .../MacOSPlatformDetector.cs | 33 ++++++++++++++++-- .../Editor/Services/PathResolverService.cs | 4 +-- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs index ac3a09ef2..9c763170a 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs @@ -112,6 +112,12 @@ public override DependencyStatus DetectUv() if (TryValidateUv("uv", out string version, out string fullPath) || TryValidateUv("uvx", out version, out fullPath)) { + // If we validated via bare command, resolve to absolute path + if (fullPath == "uv" && TryFindInPath("uv", out var resolvedUv)) + fullPath = resolvedUv; + else if (fullPath == "uvx" && TryFindInPath("uvx", out var resolvedUvx)) + fullPath = resolvedUvx; + status.IsAvailable = true; status.Version = version; status.Path = fullPath; @@ -225,16 +231,38 @@ private bool TryValidateUv(string uvPath, out string version, out string fullPat using var process = Process.Start(psi); if (process == null) return false; - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(5000); + // Read both streams to avoid missing output when tools write version to stderr + string stdout = process.StandardOutput.ReadToEnd(); + string stderr = process.StandardError.ReadToEnd(); + + // Respect timeout - check return value + if (!process.WaitForExit(5000)) + return false; + + // Use stdout first, fallback to stderr (some tools output to stderr) + string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); if (process.ExitCode == 0 && (output.StartsWith("uv ") || output.StartsWith("uvx "))) { // Extract version: "uvx 0.9.18" -> "0.9.18" + // Handle extra tokens: "uvx 0.9.18 (build info)" -> "0.9.18" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { - version = output.Substring(spaceIndex + 1).Trim(); + var remainder = output.Substring(spaceIndex + 1).Trim(); + // Extract only the version number (up to next space or parenthesis) + int nextSpace = remainder.IndexOf(' '); + int parenIndex = remainder.IndexOf('('); + int endIndex = -1; + + if (nextSpace >= 0 && parenIndex >= 0) + endIndex = Math.Min(nextSpace, parenIndex); + else if (nextSpace >= 0) + endIndex = nextSpace; + else if (parenIndex >= 0) + endIndex = parenIndex; + + version = endIndex >= 0 ? remainder.Substring(0, endIndex).Trim() : remainder; fullPath = uvPath; return true; } diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs index 0c5946d77..bcd79aa02 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs @@ -110,6 +110,12 @@ public override DependencyStatus DetectUv() if (TryValidateUv("uv", out string version, out string fullPath) || TryValidateUv("uvx", out version, out fullPath)) { + // If we validated via bare command, resolve to absolute path + if (fullPath == "uv" && TryFindInPath("uv", out var resolvedUv)) + fullPath = resolvedUv; + else if (fullPath == "uvx" && TryFindInPath("uvx", out var resolvedUvx)) + fullPath = resolvedUvx; + status.IsAvailable = true; status.Version = version; status.Path = fullPath; @@ -223,17 +229,38 @@ private bool TryValidateUv(string uvPath, out string version, out string fullPat using var process = Process.Start(psi); if (process == null) return false; + // Read both streams to avoid missing output when tools write version to stderr + string stdout = process.StandardOutput.ReadToEnd(); + string stderr = process.StandardError.ReadToEnd(); - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(5000); + // Respect timeout - check return value + if (!process.WaitForExit(5000)) + return false; + + // Use stdout first, fallback to stderr (some tools output to stderr) + string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); if (process.ExitCode == 0 && (output.StartsWith("uv ") || output.StartsWith("uvx "))) { // Extract version: "uvx 0.9.18" -> "0.9.18" + // Handle extra tokens: "uvx 0.9.18 (Homebrew 2025-01-01)" -> "0.9.18" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { - version = output.Substring(spaceIndex + 1).Trim(); + var remainder = output.Substring(spaceIndex + 1).Trim(); + // Extract only the version number (up to next space or parenthesis) + int nextSpace = remainder.IndexOf(' '); + int parenIndex = remainder.IndexOf('('); + int endIndex = -1; + + if (nextSpace >= 0 && parenIndex >= 0) + endIndex = Math.Min(nextSpace, parenIndex); + else if (nextSpace >= 0) + endIndex = nextSpace; + else if (parenIndex >= 0) + endIndex = parenIndex; + + version = endIndex >= 0 ? remainder.Substring(0, endIndex).Trim() : remainder; fullPath = uvPath; return true; } diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index 03348c8b9..02871944a 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -274,7 +274,7 @@ public bool TryValidateUvExecutable(string uvPath, out string version) if (isBareCommand) { // For bare commands like "uvx", use where/which to find full path first - string fullPath = FindExecutableInPath(uvPath); + string fullPath = FindUvxExecutableInPath(uvPath); if (string.IsNullOrEmpty(fullPath)) { // McpLog.Debug($"TryValidateUvExecutable: Could not find '{uvPath}' in PATH"); @@ -339,7 +339,7 @@ public bool TryValidateUvExecutable(string uvPath, out string version) return false; } - private string FindExecutableInPath(string commandName) + private string FindUvxExecutableInPath(string commandName) { try { From 8d5fa2fa1814116ff05dbf53a891c343e649f0de Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Sun, 11 Jan 2026 21:01:09 +0800 Subject: [PATCH 03/23] refactor: unify process execution with ExecPath.TryRun and add Windows PATH augmentation Replace direct Process.Start calls with ExecPath.TryRun across all platform detectors. This change: - Fixes potential deadlocks by using async output reading - Adds proper timeout handling with process termination - Removes redundant fallback logic and simplifies version parsing - Adds Windows PATH augmentation with common uv, npm, and Python installation paths Co-Authored-By: Claude Opus 4.5 --- .../LinuxPlatformDetector.cs | 129 +++------------ .../MacOSPlatformDetector.cs | 130 +++------------ .../WindowsPlatformDetector.cs | 152 +++++++++--------- MCPForUnity/Editor/Helpers/ExecPath.cs | 33 +++- .../Editor/Services/PathResolverService.cs | 65 ++------ 5 files changed, 169 insertions(+), 340 deletions(-) diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs index 9c763170a..95b6ee74e 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Services; @@ -108,16 +109,12 @@ public override DependencyStatus DetectUv() try { - // Try running uv/uvx directly with augmented PATH - if (TryValidateUv("uv", out string version, out string fullPath) || - TryValidateUv("uvx", out version, out fullPath)) - { - // If we validated via bare command, resolve to absolute path - if (fullPath == "uv" && TryFindInPath("uv", out var resolvedUv)) - fullPath = resolvedUv; - else if (fullPath == "uvx" && TryFindInPath("uvx", out var resolvedUvx)) - fullPath = resolvedUvx; + string augmentedPath = BuildAugmentedPath(); + // Try uv first, then uvx, using ExecPath.TryRun for proper timeout handling + if (TryValidateUvWithPath("uv", augmentedPath, out string version, out string fullPath) || + TryValidateUvWithPath("uvx", augmentedPath, out version, out fullPath)) + { status.IsAvailable = true; status.Version = version; status.Path = fullPath; @@ -126,21 +123,6 @@ public override DependencyStatus DetectUv() return status; } - // Fallback: use which with augmented PATH - if (TryFindInPath("uv", out string pathResult) || - TryFindInPath("uvx", out pathResult)) - { - if (TryValidateUv(pathResult, out version, out fullPath)) - { - status.IsAvailable = true; - status.Version = version; - status.Path = fullPath; - status.Details = $"Found uv {version} in PATH"; - status.ErrorMessage = null; - return status; - } - } - status.ErrorMessage = "uv not found in PATH"; status.Details = "Install uv package manager and ensure it's added to PATH."; } @@ -159,17 +141,6 @@ private bool TryValidatePython(string pythonPath, out string version, out string try { - var psi = new ProcessStartInfo - { - FileName = pythonPath, - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - // Set PATH to include common locations var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var pathAdditions = new[] { @@ -179,22 +150,18 @@ private bool TryValidatePython(string pythonPath, out string version, out string "/snap/bin", Path.Combine(homeDir, ".local", "bin") }; + string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); - string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - psi.EnvironmentVariables["PATH"] = string.Join(":", pathAdditions) + ":" + currentPath; - - using var process = Process.Start(psi); - if (process == null) return false; - - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(5000); + if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr, + 5000, augmentedPath)) + return false; - if (process.ExitCode == 0 && output.StartsWith("Python ")) + string output = stdout.Trim(); + if (output.StartsWith("Python ")) { - version = output.Substring(7); // Remove "Python " prefix + version = output.Substring(7); fullPath = pythonPath; - // Validate minimum version (Python 4+ or Python 3.10+) if (TryParseVersion(version, out var major, out var minor)) { return major > 3 || (major >= 3 && minor >= 10); @@ -209,61 +176,30 @@ private bool TryValidatePython(string pythonPath, out string version, out string return false; } - private bool TryValidateUv(string uvPath, out string version, out string fullPath) + private bool TryValidateUvWithPath(string command, string augmentedPath, out string version, out string fullPath) { version = null; fullPath = null; try { - var psi = new ProcessStartInfo - { - FileName = uvPath, - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - psi.EnvironmentVariables["PATH"] = BuildAugmentedPath(); - - using var process = Process.Start(psi); - if (process == null) return false; - - // Read both streams to avoid missing output when tools write version to stderr - string stdout = process.StandardOutput.ReadToEnd(); - string stderr = process.StandardError.ReadToEnd(); - - // Respect timeout - check return value - if (!process.WaitForExit(5000)) + // Use ExecPath.TryRun which properly handles async output reading and timeouts + if (!ExecPath.TryRun(command, "--version", null, out string stdout, out string stderr, + 5000, augmentedPath)) return false; - // Use stdout first, fallback to stderr (some tools output to stderr) string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); - if (process.ExitCode == 0 && (output.StartsWith("uv ") || output.StartsWith("uvx "))) + if (output.StartsWith("uv ") || output.StartsWith("uvx ")) { // Extract version: "uvx 0.9.18" -> "0.9.18" - // Handle extra tokens: "uvx 0.9.18 (build info)" -> "0.9.18" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { var remainder = output.Substring(spaceIndex + 1).Trim(); - // Extract only the version number (up to next space or parenthesis) - int nextSpace = remainder.IndexOf(' '); int parenIndex = remainder.IndexOf('('); - int endIndex = -1; - - if (nextSpace >= 0 && parenIndex >= 0) - endIndex = Math.Min(nextSpace, parenIndex); - else if (nextSpace >= 0) - endIndex = nextSpace; - else if (parenIndex >= 0) - endIndex = parenIndex; - - version = endIndex >= 0 ? remainder.Substring(0, endIndex).Trim() : remainder; - fullPath = uvPath; + version = parenIndex > 0 ? remainder.Substring(0, parenIndex).Trim() : remainder; + fullPath = command; return true; } } @@ -301,17 +237,6 @@ private bool TryFindInPath(string executable, out string fullPath) try { - var psi = new ProcessStartInfo - { - FileName = "/usr/bin/which", - Arguments = executable, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - // Enhance PATH for Unity's GUI environment var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var pathAdditions = new[] { @@ -321,17 +246,13 @@ private bool TryFindInPath(string executable, out string fullPath) "/snap/bin", Path.Combine(homeDir, ".local", "bin") }; + string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); - string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - psi.EnvironmentVariables["PATH"] = string.Join(":", pathAdditions) + ":" + currentPath; - - using var process = Process.Start(psi); - if (process == null) return false; - - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(3000); + if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath)) + return false; - if (process.ExitCode == 0 && !string.IsNullOrEmpty(output) && File.Exists(output)) + string output = stdout.Trim(); + if (!string.IsNullOrEmpty(output) && File.Exists(output)) { fullPath = output; return true; diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs index bcd79aa02..e4ed8a916 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Services; @@ -106,16 +107,12 @@ public override DependencyStatus DetectUv() try { - // Try running uv/uvx directly with augmented PATH - if (TryValidateUv("uv", out string version, out string fullPath) || - TryValidateUv("uvx", out version, out fullPath)) - { - // If we validated via bare command, resolve to absolute path - if (fullPath == "uv" && TryFindInPath("uv", out var resolvedUv)) - fullPath = resolvedUv; - else if (fullPath == "uvx" && TryFindInPath("uvx", out var resolvedUvx)) - fullPath = resolvedUvx; + string augmentedPath = BuildAugmentedPath(); + // Try uv first, then uvx, using ExecPath.TryRun for proper timeout handling + if (TryValidateUvWithPath("uv", augmentedPath, out string version, out string fullPath) || + TryValidateUvWithPath("uvx", augmentedPath, out version, out fullPath)) + { status.IsAvailable = true; status.Version = version; status.Path = fullPath; @@ -124,21 +121,6 @@ public override DependencyStatus DetectUv() return status; } - // Fallback: use which with augmented PATH - if (TryFindInPath("uv", out string pathResult) || - TryFindInPath("uvx", out pathResult)) - { - if (TryValidateUv(pathResult, out version, out fullPath)) - { - status.IsAvailable = true; - status.Version = version; - status.Path = fullPath; - status.Details = $"Found uv {version} in PATH"; - status.ErrorMessage = null; - return status; - } - } - status.ErrorMessage = "uv not found in PATH"; status.Details = "Install uv package manager and ensure it's added to PATH."; } @@ -157,17 +139,6 @@ private bool TryValidatePython(string pythonPath, out string version, out string try { - var psi = new ProcessStartInfo - { - FileName = pythonPath, - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - // Set PATH to include common locations var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var pathAdditions = new[] { @@ -176,22 +147,18 @@ private bool TryValidatePython(string pythonPath, out string version, out string "/usr/bin", Path.Combine(homeDir, ".local", "bin") }; + string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); - string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - psi.EnvironmentVariables["PATH"] = string.Join(":", pathAdditions) + ":" + currentPath; - - using var process = Process.Start(psi); - if (process == null) return false; - - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(5000); + if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr, + 5000, augmentedPath)) + return false; - if (process.ExitCode == 0 && output.StartsWith("Python ")) + string output = stdout.Trim(); + if (output.StartsWith("Python ")) { - version = output.Substring(7); // Remove "Python " prefix + version = output.Substring(7); fullPath = pythonPath; - // Validate minimum version (Python 4+ or Python 3.10+) if (TryParseVersion(version, out var major, out var minor)) { return major > 3 || (major >= 3 && minor >= 10); @@ -206,62 +173,30 @@ private bool TryValidatePython(string pythonPath, out string version, out string return false; } - private bool TryValidateUv(string uvPath, out string version, out string fullPath) + private bool TryValidateUvWithPath(string command, string augmentedPath, out string version, out string fullPath) { version = null; fullPath = null; try { - var psi = new ProcessStartInfo - { - FileName = uvPath, - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - var augmentedPath = BuildAugmentedPath(); - psi.EnvironmentVariables["PATH"] = augmentedPath; - - using var process = Process.Start(psi); - if (process == null) return false; - - // Read both streams to avoid missing output when tools write version to stderr - string stdout = process.StandardOutput.ReadToEnd(); - string stderr = process.StandardError.ReadToEnd(); - - // Respect timeout - check return value - if (!process.WaitForExit(5000)) + // Use ExecPath.TryRun which properly handles async output reading and timeouts + if (!ExecPath.TryRun(command, "--version", null, out string stdout, out string stderr, + 5000, augmentedPath)) return false; - // Use stdout first, fallback to stderr (some tools output to stderr) string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); - if (process.ExitCode == 0 && (output.StartsWith("uv ") || output.StartsWith("uvx "))) + if (output.StartsWith("uv ") || output.StartsWith("uvx ")) { // Extract version: "uvx 0.9.18" -> "0.9.18" - // Handle extra tokens: "uvx 0.9.18 (Homebrew 2025-01-01)" -> "0.9.18" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { var remainder = output.Substring(spaceIndex + 1).Trim(); - // Extract only the version number (up to next space or parenthesis) - int nextSpace = remainder.IndexOf(' '); int parenIndex = remainder.IndexOf('('); - int endIndex = -1; - - if (nextSpace >= 0 && parenIndex >= 0) - endIndex = Math.Min(nextSpace, parenIndex); - else if (nextSpace >= 0) - endIndex = nextSpace; - else if (parenIndex >= 0) - endIndex = parenIndex; - - version = endIndex >= 0 ? remainder.Substring(0, endIndex).Trim() : remainder; - fullPath = uvPath; + version = parenIndex > 0 ? remainder.Substring(0, parenIndex).Trim() : remainder; + fullPath = command; return true; } } @@ -300,17 +235,6 @@ private bool TryFindInPath(string executable, out string fullPath) try { - var psi = new ProcessStartInfo - { - FileName = "/usr/bin/which", - Arguments = executable, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - // Enhance PATH for Unity's GUI environment var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var pathAdditions = new[] { @@ -320,17 +244,13 @@ private bool TryFindInPath(string executable, out string fullPath) "/bin", Path.Combine(homeDir, ".local", "bin") }; + string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); - string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - psi.EnvironmentVariables["PATH"] = string.Join(":", pathAdditions) + ":" + currentPath; - - using var process = Process.Start(psi); - if (process == null) return false; - - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(3000); + if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath)) + return false; - if (process.ExitCode == 0 && !string.IsNullOrEmpty(output) && File.Exists(output)) + string output = stdout.Trim(); + if (!string.IsNullOrEmpty(output) && File.Exists(output)) { fullPath = output; return true; diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs index f21d58ff2..d11129e44 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Runtime.InteropServices; +using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Helpers; @@ -103,44 +106,26 @@ private bool TryFindPythonViaUv(out string version, out string fullPath) try { - var psi = new ProcessStartInfo - { - FileName = "uv", // Assume uv is in path or user can't use this fallback - Arguments = "python list", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - using var process = Process.Start(psi); - if (process == null) return false; - - string output = process.StandardOutput.ReadToEnd(); - process.WaitForExit(5000); + string augmentedPath = BuildAugmentedPath(); + // Try to list installed python versions via uv + if (!ExecPath.TryRun("uv", "python list", null, out string stdout, out string stderr, 5000, augmentedPath)) + return false; - if (process.ExitCode == 0 && !string.IsNullOrEmpty(output)) + var lines = stdout.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) { - var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var line in lines) + if (line.Contains("")) continue; + + var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length >= 2) { - // Look for installed python paths - // Format is typically: - // Skip lines with "" - if (line.Contains("")) continue; - - // The path is typically the last part of the line - var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - if (parts.Length >= 2) + string potentialPath = parts[parts.Length - 1]; + if (File.Exists(potentialPath) && + (potentialPath.EndsWith("python.exe") || potentialPath.EndsWith("python3.exe"))) { - string potentialPath = parts[parts.Length - 1]; - if (File.Exists(potentialPath) && - (potentialPath.EndsWith("python.exe") || potentialPath.EndsWith("python3.exe"))) + if (TryValidatePython(potentialPath, out version, out fullPath)) { - if (TryValidatePython(potentialPath, out version, out fullPath)) - { - return true; - } + return true; } } } @@ -161,28 +146,17 @@ private bool TryValidatePython(string pythonPath, out string version, out string try { - var psi = new ProcessStartInfo - { - FileName = pythonPath, - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - using var process = Process.Start(psi); - if (process == null) return false; + string augmentedPath = BuildAugmentedPath(); + // Run 'python --version' to get the version + if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr, 5000, augmentedPath)) + return false; - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(5000); - - if (process.ExitCode == 0 && output.StartsWith("Python ")) + string output = stdout.Trim(); + if (output.StartsWith("Python ")) { - version = output.Substring(7); // Remove "Python " prefix + version = output.Substring(7); fullPath = pythonPath; - // Validate minimum version (Python 4+ or Python 3.10+) if (TryParseVersion(version, out var major, out var minor)) { return major > 3 || (major >= 3 && minor >= 10); @@ -203,31 +177,16 @@ private bool TryFindInPath(string executable, out string fullPath) try { - var psi = new ProcessStartInfo - { - FileName = "where", - Arguments = executable, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - using var process = Process.Start(psi); - if (process == null) return false; + string augmentedPath = BuildAugmentedPath(); + // Use 'where' command to find the executable in PATH + if (!ExecPath.TryRun("where", executable, null, out string stdout, out string stderr, 3000, augmentedPath)) + return false; - string output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(3000); - - if (process.ExitCode == 0 && !string.IsNullOrEmpty(output)) + var lines = stdout.Trim().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + if (lines.Length > 0) { - // Take the first result - var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - if (lines.Length > 0) - { - fullPath = lines[0].Trim(); - return File.Exists(fullPath); - } + fullPath = lines[0].Trim(); + return File.Exists(fullPath); } } catch @@ -237,5 +196,50 @@ private bool TryFindInPath(string executable, out string fullPath) return false; } + + private string BuildAugmentedPath() + { + string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; + return string.Join(Path.PathSeparator, GetPathAdditions()) + Path.PathSeparator + currentPath; + } + + private string[] GetPathAdditions() + { + var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + var additions = new List(); + + // uv common installation paths + if (!string.IsNullOrEmpty(localAppData)) + additions.Add(Path.Combine(localAppData, "Programs", "uv")); + if (!string.IsNullOrEmpty(programFiles)) + additions.Add(Path.Combine(programFiles, "uv")); + + // npm global paths + if (!string.IsNullOrEmpty(appData)) + additions.Add(Path.Combine(appData, "npm")); + if (!string.IsNullOrEmpty(localAppData)) + additions.Add(Path.Combine(localAppData, "npm")); + + // Python common paths + if (!string.IsNullOrEmpty(localAppData)) + additions.Add(Path.Combine(localAppData, "Programs", "Python")); + if (!string.IsNullOrEmpty(programFiles)) + { + additions.Add(Path.Combine(programFiles, "Python313")); + additions.Add(Path.Combine(programFiles, "Python312")); + additions.Add(Path.Combine(programFiles, "Python311")); + additions.Add(Path.Combine(programFiles, "Python310")); + } + + // User scripts + if (!string.IsNullOrEmpty(homeDir)) + additions.Add(Path.Combine(homeDir, ".local", "bin")); + + return additions.Where(Directory.Exists).ToArray(); + } } } diff --git a/MCPForUnity/Editor/Helpers/ExecPath.cs b/MCPForUnity/Editor/Helpers/ExecPath.cs index 2224009ed..fbb7cb3e5 100644 --- a/MCPForUnity/Editor/Helpers/ExecPath.cs +++ b/MCPForUnity/Editor/Helpers/ExecPath.cs @@ -239,9 +239,22 @@ private static string Which(string exe, string prependPath) }; string path = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; psi.EnvironmentVariables["PATH"] = string.IsNullOrEmpty(path) ? prependPath : (prependPath + Path.PathSeparator + path); + using var p = Process.Start(psi); - string output = p?.StandardOutput.ReadToEnd().Trim(); - p?.WaitForExit(1500); + if (p == null) return null; + + var so = new StringBuilder(); + p.OutputDataReceived += (_, e) => { if (e.Data != null) so.AppendLine(e.Data); }; + p.BeginOutputReadLine(); + + if (!p.WaitForExit(1500)) + { + try { p.Kill(); } catch { } + return null; + } + + p.WaitForExit(); + string output = so.ToString().Trim(); return (!string.IsNullOrEmpty(output) && File.Exists(output)) ? output : null; } catch { return null; } @@ -260,10 +273,22 @@ private static string Where(string exe) CreateNoWindow = true, }; using var p = Process.Start(psi); - string first = p?.StandardOutput.ReadToEnd() + if (p == null) return null; + + var so = new StringBuilder(); + p.OutputDataReceived += (_, e) => { if (e.Data != null) so.AppendLine(e.Data); }; + p.BeginOutputReadLine(); + + if (!p.WaitForExit(1500)) + { + try { p.Kill(); } catch { } + return null; + } + + p.WaitForExit(); + string first = so.ToString() .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .FirstOrDefault(); - p?.WaitForExit(1500); return (!string.IsNullOrEmpty(first) && File.Exists(first)) ? first : null; } catch { return null; } diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index 02871944a..2bcd8d8f0 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -104,25 +104,13 @@ public string GetClaudeCliPath() public bool IsPythonDetected() { - try - { - var psi = new ProcessStartInfo - { - FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "python.exe" : "python3", - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - using var p = Process.Start(psi); - p.WaitForExit(2000); - return p.ExitCode == 0; - } - catch - { - return false; - } + return ExecPath.TryRun( + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "python.exe" : "python3", + "--version", + null, + out _, + out _, + 2000); } public bool IsClaudeCliDetected() @@ -268,51 +256,25 @@ public bool TryValidateUvExecutable(string uvPath, out string version) { // Check if the path is just a command name (no directory separator) bool isBareCommand = !uvPath.Contains('/') && !uvPath.Contains('\\'); - // McpLog.Debug($"TryValidateUvExecutable: path='{uvPath}', isBare={isBareCommand}"); - ProcessStartInfo psi; if (isBareCommand) { // For bare commands like "uvx", use where/which to find full path first string fullPath = FindUvxExecutableInPath(uvPath); if (string.IsNullOrEmpty(fullPath)) - { - // McpLog.Debug($"TryValidateUvExecutable: Could not find '{uvPath}' in PATH"); return false; - } - // McpLog.Debug($"TryValidateUvExecutable: Found full path: '{fullPath}'"); uvPath = fullPath; } - // Execute the command (full path) - psi = new ProcessStartInfo - { - FileName = uvPath, - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - using var process = Process.Start(psi); - if (process == null) + // Use ExecPath.TryRun which properly handles async output reading and timeouts + if (!ExecPath.TryRun(uvPath, "--version", null, out string stdout, out string stderr, 5000)) return false; - - string output = process.StandardOutput.ReadToEnd().Trim(); - string error = process.StandardError.ReadToEnd().Trim(); - // wait for the process to exit with a timeout of 5000ms (5 seconds) - if (!process.WaitForExit(5000)) return false; - - // McpLog.Debug($"TryValidateUvExecutable: exitCode={process.ExitCode}, stdout='{output}', stderr='{error}'"); - // Check stdout first, then stderr (some tools output to stderr) - string versionOutput = !string.IsNullOrEmpty(output) ? output : error; + string versionOutput = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim(); // uvx outputs "uvx x.y.z" or "uv x.y.z", extract version number - if (process.ExitCode == 0 && - (versionOutput.StartsWith("uv ") || versionOutput.StartsWith("uvx "))) + if (versionOutput.StartsWith("uv ") || versionOutput.StartsWith("uvx ")) { // Extract version: "uvx 0.9.18 (hash date)" -> "0.9.18" int spaceIndex = versionOutput.IndexOf(' '); @@ -324,16 +286,13 @@ public bool TryValidateUvExecutable(string uvPath, out string version) version = parenIndex > 0 ? afterCommand.Substring(0, parenIndex).Trim() : afterCommand.Split(' ')[0]; - // McpLog.Debug($"TryValidateUvExecutable: SUCCESS - version={version}"); return true; } } - // McpLog.Debug($"TryValidateUvExecutable: FAILED - exitCode={process.ExitCode}"); } - //catch (Exception ex) catch { - // McpLog.Debug($"TryValidateUvExecutable: EXCEPTION - {ex.Message}"); + // Ignore validation errors } return false; From 84cee8ccdeb0ade74a750ce749d8f772dc590185 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Sun, 11 Jan 2026 21:11:52 +0800 Subject: [PATCH 04/23] fix: improve version parsing to handle both spaces and parentheses The version extraction logic now properly handles outputs like: - "uvx 0.9.18" -> "0.9.18" - "uvx 0.9.18 (hash date)" -> "0.9.18" - "uvx 0.9.18 extra info" -> "0.9.18" Uses Math.Min to find the first occurrence of either space or parenthesis. Co-Authored-By: Claude Opus 4.5 --- .../PlatformDetectors/LinuxPlatformDetector.cs | 7 ++++++- .../PlatformDetectors/MacOSPlatformDetector.cs | 7 ++++++- MCPForUnity/Editor/Services/PathResolverService.cs | 9 ++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs index 95b6ee74e..395396c60 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs @@ -197,8 +197,13 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str if (spaceIndex >= 0) { var remainder = output.Substring(spaceIndex + 1).Trim(); + int nextSpace = remainder.IndexOf(' '); int parenIndex = remainder.IndexOf('('); - version = parenIndex > 0 ? remainder.Substring(0, parenIndex).Trim() : remainder; + int endIndex = Math.Min( + nextSpace >= 0 ? nextSpace : int.MaxValue, + parenIndex >= 0 ? parenIndex : int.MaxValue + ); + version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; fullPath = command; return true; } diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs index e4ed8a916..eee8b064a 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs @@ -194,8 +194,13 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str if (spaceIndex >= 0) { var remainder = output.Substring(spaceIndex + 1).Trim(); + int nextSpace = remainder.IndexOf(' '); int parenIndex = remainder.IndexOf('('); - version = parenIndex > 0 ? remainder.Substring(0, parenIndex).Trim() : remainder; + int endIndex = Math.Min( + nextSpace >= 0 ? nextSpace : int.MaxValue, + parenIndex >= 0 ? parenIndex : int.MaxValue + ); + version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; fullPath = command; return true; } diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index 2bcd8d8f0..56c05667c 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -282,10 +282,13 @@ public bool TryValidateUvExecutable(string uvPath, out string version) { string afterCommand = versionOutput.Substring(spaceIndex + 1).Trim(); // Version is up to the first space or parenthesis + int nextSpace = afterCommand.IndexOf(' '); int parenIndex = afterCommand.IndexOf('('); - version = parenIndex > 0 - ? afterCommand.Substring(0, parenIndex).Trim() - : afterCommand.Split(' ')[0]; + int endIndex = Math.Min( + nextSpace >= 0 ? nextSpace : int.MaxValue, + parenIndex >= 0 ? parenIndex : int.MaxValue + ); + version = endIndex < int.MaxValue ? afterCommand.Substring(0, endIndex).Trim() : afterCommand; return true; } } From 510e6313eade594eff61b1856a718876646d4c69 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Sun, 11 Jan 2026 22:59:20 +0800 Subject: [PATCH 05/23] refactor: improve platform detectors with absolute path resolution - Add absolute path resolution in TryValidatePython and TryValidateUvWithPath for better UI display - Fix BuildAugmentedPath to avoid PATH duplication - Add comprehensive comments for version parsing logic - Ensure cross-platform consistency across all three detectors - Fix override path validation logic with clear state handling - Fix platform detector path resolution and Python version detection - Use UserProfile consistently in GetClaudeCliPath instead of Personal - All platforms now use protected BuildAugmentedPath method This change improves user experience by displaying full paths in the UI while maintaining robust fallback behavior if path resolution fails. Co-Authored-By: GLM4.7 --- .../Readme.asset.meta => CustomTools.meta | 6 +- .../RoslynRuntimeCompilation.meta | 6 +- ...ighFidelity.asset.meta => MCPForUnity.meta | 6 +- .../LinuxPlatformDetector.cs | 57 ++-- .../MacOSPlatformDetector.cs | 57 ++-- .../WindowsPlatformDetector.cs | 31 +- .../Editor/Services/PathResolverService.cs | 272 +++++++++++------- ...P-Balanced.asset.meta => README-zh.md.meta | 5 +- README.md.meta | 7 + Server.meta | 8 + Server/DOCKER_OVERVIEW.md.meta | 7 + Server/Dockerfile.meta | 7 + Server/README.md.meta | 7 + Server/__init__.py.meta | 7 + Server/pyproject.toml.meta | 7 + Server/pyrightconfig.json.meta | 7 + Server/src.meta | 8 + Server/src/__init__.py.meta | 7 + Server/src/core.meta | 8 + Server/src/core/__init__.py.meta | 7 + Server/src/core/config.py.meta | 7 + Server/src/core/logging_decorator.py.meta | 7 + Server/src/core/telemetry.py.meta | 7 + Server/src/core/telemetry_decorator.py.meta | 7 + Server/src/main.py.meta | 7 + Server/src/mcpforunityserver.egg-info.meta | 8 + Server/src/models.meta | 8 + Server/src/models/__init__.py.meta | 7 + Server/src/models/models.py.meta | 7 + Server/src/models/unity_response.py.meta | 7 + Server/src/services.meta | 8 + Server/src/services/__init__.py.meta | 7 + .../src/services/custom_tool_service.py.meta | 7 + Server/src/services/registry.meta | 8 + Server/src/services/registry/__init__.py.meta | 7 + .../registry/resource_registry.py.meta | 7 + .../services/registry/tool_registry.py.meta | 7 + Server/src/services/resources.meta | 8 + .../src/services/resources/__init__.py.meta | 7 + .../services/resources/active_tool.py.meta | 7 + .../services/resources/custom_tools.py.meta | 7 + .../services/resources/editor_state.py.meta | 7 + .../src/services/resources/gameobject.py.meta | 7 + Server/src/services/resources/layers.py.meta | 7 + .../src/services/resources/menu_items.py.meta | 7 + .../services/resources/prefab_stage.py.meta | 7 + .../services/resources/project_info.py.meta | 7 + .../src/services/resources/selection.py.meta | 7 + Server/src/services/resources/tags.py.meta | 7 + Server/src/services/resources/tests.py.meta | 7 + .../resources/unity_instances.py.meta | 7 + Server/src/services/resources/windows.py.meta | 7 + Server/src/services/state.meta | 8 + .../state/external_changes_scanner.py.meta | 7 + Server/src/services/tools.meta | 8 + Server/src/services/tools/__init__.py.meta | 7 + .../src/services/tools/batch_execute.py.meta | 7 + .../tools/debug_request_context.py.meta | 7 + .../tools/execute_custom_tool.py.meta | 7 + .../services/tools/execute_menu_item.py.meta | 7 + .../services/tools/find_gameobjects.py.meta | 7 + .../src/services/tools/find_in_file.py.meta | 7 + .../src/services/tools/manage_asset.py.meta | 7 + .../services/tools/manage_components.py.meta | 7 + .../src/services/tools/manage_editor.py.meta | 7 + .../services/tools/manage_gameobject.py.meta | 7 + .../services/tools/manage_material.py.meta | 7 + .../src/services/tools/manage_prefabs.py.meta | 7 + .../src/services/tools/manage_scene.py.meta | 7 + .../src/services/tools/manage_script.py.meta | 7 + .../tools/manage_scriptable_object.py.meta | 7 + .../src/services/tools/manage_shader.py.meta | 7 + Server/src/services/tools/manage_vfx.py.meta | 7 + Server/src/services/tools/preflight.py.meta | 7 + .../src/services/tools/read_console.py.meta | 7 + .../src/services/tools/refresh_unity.py.meta | 7 + Server/src/services/tools/run_tests.py.meta | 7 + .../services/tools/script_apply_edits.py.meta | 7 + .../tools/set_active_instance.py.meta | 7 + Server/src/services/tools/utils.py.meta | 7 + Server/src/transport.meta | 8 + Server/src/transport/__init__.py.meta | 7 + Server/src/transport/legacy.meta | 8 + .../transport/legacy/port_discovery.py.meta | 7 + .../legacy/stdio_port_registry.py.meta | 7 + .../transport/legacy/unity_connection.py.meta | 7 + Server/src/transport/models.py.meta | 7 + Server/src/transport/plugin_hub.py.meta | 7 + Server/src/transport/plugin_registry.py.meta | 7 + .../unity_instance_middleware.py.meta | 7 + Server/src/transport/unity_transport.py.meta | 7 + Server/src/utils.meta | 8 + Server/src/utils/module_discovery.py.meta | 7 + Server/src/utils/reload_sentinel.py.meta | 7 + Server/tests.meta | 8 + Server/tests/__init__.py.meta | 7 + Server/tests/integration.meta | 8 + Server/tests/integration/__init__.py.meta | 7 + Server/tests/integration/conftest.py.meta | 7 + ..._debug_request_context_diagnostics.py.meta | 7 + .../test_domain_reload_resilience.py.meta | 7 + .../test_edit_normalization_and_noop.py.meta | 7 + .../test_edit_strict_and_warnings.py.meta | 7 + .../test_editor_state_v2_contract.py.meta | 7 + .../test_external_changes_scanner.py.meta | 7 + .../integration/test_find_gameobjects.py.meta | 7 + .../test_find_in_file_minimal.py.meta | 7 + .../test_gameobject_resources.py.meta | 7 + Server/tests/integration/test_get_sha.py.meta | 7 + Server/tests/integration/test_helpers.py.meta | 7 + .../test_improved_anchor_matching.py.meta | 7 + .../test_instance_autoselect.py.meta | 7 + ...est_instance_routing_comprehensive.py.meta | 7 + ...test_instance_targeting_resolution.py.meta | 7 + .../test_json_parsing_simple.py.meta | 7 + .../integration/test_logging_stdout.py.meta | 7 + .../test_manage_asset_json_parsing.py.meta | 7 + .../test_manage_asset_param_coercion.py.meta | 7 + .../test_manage_components.py.meta | 7 + ...t_manage_gameobject_param_coercion.py.meta | 7 + .../test_manage_scene_paging_params.py.meta | 7 + .../test_manage_script_uri.py.meta | 7 + ...test_manage_scriptable_object_tool.py.meta | 7 + .../test_read_console_truncate.py.meta | 7 + .../test_read_resource_minimal.py.meta | 7 + .../test_refresh_unity_registration.py.meta | 7 + .../test_refresh_unity_retry_recovery.py.meta | 7 + .../integration/test_resources_api.py.meta | 7 + .../integration/test_run_tests_async.py.meta | 7 + .../integration/test_script_editing.py.meta | 7 + .../integration/test_script_tools.py.meta | 7 + ...test_telemetry_endpoint_validation.py.meta | 7 + .../test_telemetry_queue_worker.py.meta | 7 + .../test_telemetry_subaction.py.meta | 7 + .../test_tool_signatures_paging.py.meta | 7 + .../test_transport_framing.py.meta | 7 + .../test_validate_script_summary.py.meta | 7 + Server/tests/pytest.ini.meta | 7 + Server/uv.lock.meta | 7 + TestProjects.meta | 8 + TestProjects/AssetStoreUploads.meta | 8 + TestProjects/AssetStoreUploads/Assets.meta | 8 + .../Settings/URP-Balanced-Renderer.asset.meta | 8 - .../URP-HighFidelity-Renderer.asset.meta | 8 - .../URP-Performant-Renderer.asset.meta | 8 - .../Assets/Settings/URP-Performant.asset.meta | 8 - ...salRenderPipelineGlobalSettings.asset.meta | 8 - TestProjects/AssetStoreUploads/Packages.meta | 8 + .../Packages/com.unity.asset-store-tools.meta | 8 + .../Generic/Check Animation Clips.asset.meta | 8 - .../Generic/Check Audio Clipping.asset.meta | 8 - .../Tests/Generic/Check Colliders.asset.meta | 8 - .../Generic/Check Compressed Files.asset.meta | 8 - .../Generic/Check Empty Prefabs.asset.meta | 8 - .../Generic/Check File Menu Names.asset.meta | 8 - .../Tests/Generic/Check LODs.asset.meta | 8 - .../Generic/Check Line Endings.asset.meta | 8 - .../Generic/Check Mesh Prefabs.asset.meta | 8 - ...ck Missing Components in Assets.asset.meta | 8 - ...ck Missing Components in Scenes.asset.meta | 8 - .../Check Model Import Logs.asset.meta | 8 - .../Check Model Orientation.asset.meta | 8 - .../Generic/Check Model Types.asset.meta | 8 - .../Check Normal Map Textures.asset.meta | 8 - .../Generic/Check Package Naming.asset.meta | 8 - .../Generic/Check Particle Systems.asset.meta | 8 - .../Generic/Check Path Lengths.asset.meta | 8 - .../Check Prefab Transforms.asset.meta | 8 - .../Check Script Compilation.asset.meta | 8 - .../Check Shader Compilation.asset.meta | 8 - .../Check Texture Dimensions.asset.meta | 8 - .../Generic/Check Type Namespaces.asset.meta | 8 - .../Remove Executable Files.asset.meta | 8 - .../Tests/Generic/Remove JPG Files.asset.meta | 8 - .../Remove JavaScript Files.asset.meta | 8 - .../Remove Lossy Audio Files.asset.meta | 8 - .../Generic/Remove Mixamo Files.asset.meta | 8 - .../Generic/Remove SpeedTree Files.asset.meta | 8 - .../Generic/Remove Video Files.asset.meta | 8 - .../UnityPackage/Check Demo Scenes.asset.meta | 8 - .../Check Documentation.asset.meta | 8 - .../Check Package Size.asset.meta | 8 - .../Check Project Template Assets.asset.meta | 8 - .../Packages/manifest.json.meta | 7 + .../Packages/packages-lock.json.meta | 7 + .../AssetStoreUploads/ProjectSettings.meta | 8 + ...rstAotSettings_StandaloneWindows.json.meta | 7 + .../CommonBurstAotSettings.json.meta | 7 + .../ProjectSettings/ProjectVersion.txt.meta | 7 + .../SceneTemplateSettings.json.meta | 7 + TestProjects/UnityMCPTests.meta | 8 + TestProjects/UnityMCPTests/Assets.meta | 8 + TestProjects/UnityMCPTests/Packages.meta | 8 + .../UnityMCPTests/Packages/manifest.json.meta | 7 + .../UnityMCPTests/ProjectSettings.meta | 8 + .../ProjectSettings/Packages.meta | 8 + .../com.unity.testtools.codecoverage.meta | 8 + .../Settings.json.meta | 7 + .../ProjectSettings/ProjectVersion.txt.meta | 7 + .../SceneTemplateSettings.json.meta | 7 + claude_skill_unity.zip.meta | 7 + deploy-dev.bat.meta | 7 + docker-compose.yml.meta | 7 + docs.meta | 8 + docs/CURSOR_HELP.md.meta | 7 + docs/CUSTOM_TOOLS.md.meta | 7 + docs/MCP_CLIENT_CONFIGURATORS.md.meta | 7 + docs/README-DEV-zh.md.meta | 7 + docs/README-DEV.md.meta | 7 + docs/TELEMETRY.md.meta | 7 + docs/images.meta | 8 + docs/images/advanced-setting.png.meta | 127 ++++++++ docs/images/building_scene.gif.meta | 127 ++++++++ docs/images/coplay-logo.png.meta | 127 ++++++++ docs/images/logo.png.meta | 127 ++++++++ docs/images/networking-architecture.png.meta | 127 ++++++++ docs/images/readme_ui.png.meta | 127 ++++++++ docs/images/unity-mcp-ui-v8.6.png.meta | 127 ++++++++ docs/images/v5_01_uninstall.png.meta | 127 ++++++++ docs/images/v5_02_install.png.meta | 127 ++++++++ docs/images/v5_03_open_mcp_window.png.meta | 127 ++++++++ docs/images/v5_04_rebuild_mcp_server.png.meta | 127 ++++++++ docs/images/v5_05_rebuild_success.png.meta | 127 ++++++++ .../v6_2_create_python_tools_asset.png.meta | 127 ++++++++ docs/images/v6_2_python_tools_asset.png.meta | 127 ++++++++ .../v6_new_ui_asset_store_version.png.meta | 127 ++++++++ docs/images/v6_new_ui_dark.png.meta | 127 ++++++++ docs/images/v6_new_ui_light.png.meta | 127 ++++++++ docs/v5_MIGRATION.md.meta | 7 + docs/v6_NEW_UI_CHANGES.md.meta | 7 + docs/v8_NEW_NETWORKING_SETUP.md.meta | 7 + mcp_source.py.meta | 7 + prune_tool_results.py.meta | 7 + restore-dev.bat.meta | 7 + scripts.meta | 8 + scripts/validate-nlt-coverage.sh.meta | 7 + test_unity_socket_framing.py.meta | 7 + tools.meta | 8 + .../prepare_unity_asset_store_release.py.meta | 7 + tools/stress_mcp.py.meta | 7 + 240 files changed, 3685 insertions(+), 489 deletions(-) rename TestProjects/AssetStoreUploads/Assets/Readme.asset.meta => CustomTools.meta (54%) rename TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta => CustomTools/RoslynRuntimeCompilation.meta (54%) rename TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta => MCPForUnity.meta (54%) rename TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta => README-zh.md.meta (54%) create mode 100644 README.md.meta create mode 100644 Server.meta create mode 100644 Server/DOCKER_OVERVIEW.md.meta create mode 100644 Server/Dockerfile.meta create mode 100644 Server/README.md.meta create mode 100644 Server/__init__.py.meta create mode 100644 Server/pyproject.toml.meta create mode 100644 Server/pyrightconfig.json.meta create mode 100644 Server/src.meta create mode 100644 Server/src/__init__.py.meta create mode 100644 Server/src/core.meta create mode 100644 Server/src/core/__init__.py.meta create mode 100644 Server/src/core/config.py.meta create mode 100644 Server/src/core/logging_decorator.py.meta create mode 100644 Server/src/core/telemetry.py.meta create mode 100644 Server/src/core/telemetry_decorator.py.meta create mode 100644 Server/src/main.py.meta create mode 100644 Server/src/mcpforunityserver.egg-info.meta create mode 100644 Server/src/models.meta create mode 100644 Server/src/models/__init__.py.meta create mode 100644 Server/src/models/models.py.meta create mode 100644 Server/src/models/unity_response.py.meta create mode 100644 Server/src/services.meta create mode 100644 Server/src/services/__init__.py.meta create mode 100644 Server/src/services/custom_tool_service.py.meta create mode 100644 Server/src/services/registry.meta create mode 100644 Server/src/services/registry/__init__.py.meta create mode 100644 Server/src/services/registry/resource_registry.py.meta create mode 100644 Server/src/services/registry/tool_registry.py.meta create mode 100644 Server/src/services/resources.meta create mode 100644 Server/src/services/resources/__init__.py.meta create mode 100644 Server/src/services/resources/active_tool.py.meta create mode 100644 Server/src/services/resources/custom_tools.py.meta create mode 100644 Server/src/services/resources/editor_state.py.meta create mode 100644 Server/src/services/resources/gameobject.py.meta create mode 100644 Server/src/services/resources/layers.py.meta create mode 100644 Server/src/services/resources/menu_items.py.meta create mode 100644 Server/src/services/resources/prefab_stage.py.meta create mode 100644 Server/src/services/resources/project_info.py.meta create mode 100644 Server/src/services/resources/selection.py.meta create mode 100644 Server/src/services/resources/tags.py.meta create mode 100644 Server/src/services/resources/tests.py.meta create mode 100644 Server/src/services/resources/unity_instances.py.meta create mode 100644 Server/src/services/resources/windows.py.meta create mode 100644 Server/src/services/state.meta create mode 100644 Server/src/services/state/external_changes_scanner.py.meta create mode 100644 Server/src/services/tools.meta create mode 100644 Server/src/services/tools/__init__.py.meta create mode 100644 Server/src/services/tools/batch_execute.py.meta create mode 100644 Server/src/services/tools/debug_request_context.py.meta create mode 100644 Server/src/services/tools/execute_custom_tool.py.meta create mode 100644 Server/src/services/tools/execute_menu_item.py.meta create mode 100644 Server/src/services/tools/find_gameobjects.py.meta create mode 100644 Server/src/services/tools/find_in_file.py.meta create mode 100644 Server/src/services/tools/manage_asset.py.meta create mode 100644 Server/src/services/tools/manage_components.py.meta create mode 100644 Server/src/services/tools/manage_editor.py.meta create mode 100644 Server/src/services/tools/manage_gameobject.py.meta create mode 100644 Server/src/services/tools/manage_material.py.meta create mode 100644 Server/src/services/tools/manage_prefabs.py.meta create mode 100644 Server/src/services/tools/manage_scene.py.meta create mode 100644 Server/src/services/tools/manage_script.py.meta create mode 100644 Server/src/services/tools/manage_scriptable_object.py.meta create mode 100644 Server/src/services/tools/manage_shader.py.meta create mode 100644 Server/src/services/tools/manage_vfx.py.meta create mode 100644 Server/src/services/tools/preflight.py.meta create mode 100644 Server/src/services/tools/read_console.py.meta create mode 100644 Server/src/services/tools/refresh_unity.py.meta create mode 100644 Server/src/services/tools/run_tests.py.meta create mode 100644 Server/src/services/tools/script_apply_edits.py.meta create mode 100644 Server/src/services/tools/set_active_instance.py.meta create mode 100644 Server/src/services/tools/utils.py.meta create mode 100644 Server/src/transport.meta create mode 100644 Server/src/transport/__init__.py.meta create mode 100644 Server/src/transport/legacy.meta create mode 100644 Server/src/transport/legacy/port_discovery.py.meta create mode 100644 Server/src/transport/legacy/stdio_port_registry.py.meta create mode 100644 Server/src/transport/legacy/unity_connection.py.meta create mode 100644 Server/src/transport/models.py.meta create mode 100644 Server/src/transport/plugin_hub.py.meta create mode 100644 Server/src/transport/plugin_registry.py.meta create mode 100644 Server/src/transport/unity_instance_middleware.py.meta create mode 100644 Server/src/transport/unity_transport.py.meta create mode 100644 Server/src/utils.meta create mode 100644 Server/src/utils/module_discovery.py.meta create mode 100644 Server/src/utils/reload_sentinel.py.meta create mode 100644 Server/tests.meta create mode 100644 Server/tests/__init__.py.meta create mode 100644 Server/tests/integration.meta create mode 100644 Server/tests/integration/__init__.py.meta create mode 100644 Server/tests/integration/conftest.py.meta create mode 100644 Server/tests/integration/test_debug_request_context_diagnostics.py.meta create mode 100644 Server/tests/integration/test_domain_reload_resilience.py.meta create mode 100644 Server/tests/integration/test_edit_normalization_and_noop.py.meta create mode 100644 Server/tests/integration/test_edit_strict_and_warnings.py.meta create mode 100644 Server/tests/integration/test_editor_state_v2_contract.py.meta create mode 100644 Server/tests/integration/test_external_changes_scanner.py.meta create mode 100644 Server/tests/integration/test_find_gameobjects.py.meta create mode 100644 Server/tests/integration/test_find_in_file_minimal.py.meta create mode 100644 Server/tests/integration/test_gameobject_resources.py.meta create mode 100644 Server/tests/integration/test_get_sha.py.meta create mode 100644 Server/tests/integration/test_helpers.py.meta create mode 100644 Server/tests/integration/test_improved_anchor_matching.py.meta create mode 100644 Server/tests/integration/test_instance_autoselect.py.meta create mode 100644 Server/tests/integration/test_instance_routing_comprehensive.py.meta create mode 100644 Server/tests/integration/test_instance_targeting_resolution.py.meta create mode 100644 Server/tests/integration/test_json_parsing_simple.py.meta create mode 100644 Server/tests/integration/test_logging_stdout.py.meta create mode 100644 Server/tests/integration/test_manage_asset_json_parsing.py.meta create mode 100644 Server/tests/integration/test_manage_asset_param_coercion.py.meta create mode 100644 Server/tests/integration/test_manage_components.py.meta create mode 100644 Server/tests/integration/test_manage_gameobject_param_coercion.py.meta create mode 100644 Server/tests/integration/test_manage_scene_paging_params.py.meta create mode 100644 Server/tests/integration/test_manage_script_uri.py.meta create mode 100644 Server/tests/integration/test_manage_scriptable_object_tool.py.meta create mode 100644 Server/tests/integration/test_read_console_truncate.py.meta create mode 100644 Server/tests/integration/test_read_resource_minimal.py.meta create mode 100644 Server/tests/integration/test_refresh_unity_registration.py.meta create mode 100644 Server/tests/integration/test_refresh_unity_retry_recovery.py.meta create mode 100644 Server/tests/integration/test_resources_api.py.meta create mode 100644 Server/tests/integration/test_run_tests_async.py.meta create mode 100644 Server/tests/integration/test_script_editing.py.meta create mode 100644 Server/tests/integration/test_script_tools.py.meta create mode 100644 Server/tests/integration/test_telemetry_endpoint_validation.py.meta create mode 100644 Server/tests/integration/test_telemetry_queue_worker.py.meta create mode 100644 Server/tests/integration/test_telemetry_subaction.py.meta create mode 100644 Server/tests/integration/test_tool_signatures_paging.py.meta create mode 100644 Server/tests/integration/test_transport_framing.py.meta create mode 100644 Server/tests/integration/test_validate_script_summary.py.meta create mode 100644 Server/tests/pytest.ini.meta create mode 100644 Server/uv.lock.meta create mode 100644 TestProjects.meta create mode 100644 TestProjects/AssetStoreUploads.meta create mode 100644 TestProjects/AssetStoreUploads/Assets.meta delete mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/manifest.json.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta create mode 100644 TestProjects/AssetStoreUploads/ProjectSettings.meta create mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta create mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta create mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta create mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta create mode 100644 TestProjects/UnityMCPTests.meta create mode 100644 TestProjects/UnityMCPTests/Assets.meta create mode 100644 TestProjects/UnityMCPTests/Packages.meta create mode 100644 TestProjects/UnityMCPTests/Packages/manifest.json.meta create mode 100644 TestProjects/UnityMCPTests/ProjectSettings.meta create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/Packages.meta create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta create mode 100644 claude_skill_unity.zip.meta create mode 100644 deploy-dev.bat.meta create mode 100644 docker-compose.yml.meta create mode 100644 docs.meta create mode 100644 docs/CURSOR_HELP.md.meta create mode 100644 docs/CUSTOM_TOOLS.md.meta create mode 100644 docs/MCP_CLIENT_CONFIGURATORS.md.meta create mode 100644 docs/README-DEV-zh.md.meta create mode 100644 docs/README-DEV.md.meta create mode 100644 docs/TELEMETRY.md.meta create mode 100644 docs/images.meta create mode 100644 docs/images/advanced-setting.png.meta create mode 100644 docs/images/building_scene.gif.meta create mode 100644 docs/images/coplay-logo.png.meta create mode 100644 docs/images/logo.png.meta create mode 100644 docs/images/networking-architecture.png.meta create mode 100644 docs/images/readme_ui.png.meta create mode 100644 docs/images/unity-mcp-ui-v8.6.png.meta create mode 100644 docs/images/v5_01_uninstall.png.meta create mode 100644 docs/images/v5_02_install.png.meta create mode 100644 docs/images/v5_03_open_mcp_window.png.meta create mode 100644 docs/images/v5_04_rebuild_mcp_server.png.meta create mode 100644 docs/images/v5_05_rebuild_success.png.meta create mode 100644 docs/images/v6_2_create_python_tools_asset.png.meta create mode 100644 docs/images/v6_2_python_tools_asset.png.meta create mode 100644 docs/images/v6_new_ui_asset_store_version.png.meta create mode 100644 docs/images/v6_new_ui_dark.png.meta create mode 100644 docs/images/v6_new_ui_light.png.meta create mode 100644 docs/v5_MIGRATION.md.meta create mode 100644 docs/v6_NEW_UI_CHANGES.md.meta create mode 100644 docs/v8_NEW_NETWORKING_SETUP.md.meta create mode 100644 mcp_source.py.meta create mode 100644 prune_tool_results.py.meta create mode 100644 restore-dev.bat.meta create mode 100644 scripts.meta create mode 100644 scripts/validate-nlt-coverage.sh.meta create mode 100644 test_unity_socket_framing.py.meta create mode 100644 tools.meta create mode 100644 tools/prepare_unity_asset_store_release.py.meta create mode 100644 tools/stress_mcp.py.meta diff --git a/TestProjects/AssetStoreUploads/Assets/Readme.asset.meta b/CustomTools.meta similarity index 54% rename from TestProjects/AssetStoreUploads/Assets/Readme.asset.meta rename to CustomTools.meta index ab3ad4535..15c0e2e9b 100644 --- a/TestProjects/AssetStoreUploads/Assets/Readme.asset.meta +++ b/CustomTools.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: 8105016687592461f977c054a80ce2f2 -NativeFormatImporter: +guid: 77119eb495f8bd34e97e027dfc10164d +folderAsset: yes +DefaultImporter: externalObjects: {} - mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta b/CustomTools/RoslynRuntimeCompilation.meta similarity index 54% rename from TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta rename to CustomTools/RoslynRuntimeCompilation.meta index f8cce646a..ec3ccf2fb 100644 --- a/TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta +++ b/CustomTools/RoslynRuntimeCompilation.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: a6560a915ef98420e9faacc1c7438823 -NativeFormatImporter: +guid: cb28c23ce26c4954f90a988b0fb8232b +folderAsset: yes +DefaultImporter: externalObjects: {} - mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta b/MCPForUnity.meta similarity index 54% rename from TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta rename to MCPForUnity.meta index 7416e17a3..b8bba153d 100644 --- a/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta +++ b/MCPForUnity.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: 7b7fd9122c28c4d15b667c7040e3b3fd -NativeFormatImporter: +guid: 0d2e5a49aaf8cd2429de11605995a74c +folderAsset: yes +DefaultImporter: externalObjects: {} - mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs index 395396c60..cd071b41e 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs @@ -141,26 +141,25 @@ private bool TryValidatePython(string pythonPath, out string version, out string try { - var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - var pathAdditions = new[] + string augmentedPath = BuildAugmentedPath(); + + // First, try to resolve the absolute path for better UI/logging display + string commandToRun = pythonPath; + if (TryFindInPath(pythonPath, out string resolvedPath)) { - "/usr/local/bin", - "/usr/bin", - "/bin", - "/snap/bin", - Path.Combine(homeDir, ".local", "bin") - }; - string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); - - if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr, + commandToRun = resolvedPath; + } + + if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, 5000, augmentedPath)) return false; - string output = stdout.Trim(); + // Check stdout first, then stderr (some Python distributions output to stderr) + string output = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim(); if (output.StartsWith("Python ")) { version = output.Substring(7); - fullPath = pythonPath; + fullPath = commandToRun; if (TryParseVersion(version, out var major, out var minor)) { @@ -183,8 +182,15 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str try { + // First, try to resolve the absolute path for better UI/logging display + string commandToRun = command; + if (TryFindInPath(command, out string resolvedPath)) + { + commandToRun = resolvedPath; + } + // Use ExecPath.TryRun which properly handles async output reading and timeouts - if (!ExecPath.TryRun(command, "--version", null, out string stdout, out string stderr, + if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, 5000, augmentedPath)) return false; @@ -193,6 +199,7 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str if (output.StartsWith("uv ") || output.StartsWith("uvx ")) { // Extract version: "uvx 0.9.18" -> "0.9.18" + // Handle extra tokens: "uvx 0.9.18 extra" or "uvx 0.9.18 (build info)" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { @@ -204,7 +211,7 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str parenIndex >= 0 ? parenIndex : int.MaxValue ); version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; - fullPath = command; + fullPath = commandToRun; return true; } } @@ -217,10 +224,13 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str return false; } - private string BuildAugmentedPath() + protected string BuildAugmentedPath() { - string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - return string.Join(":", GetPathAdditions()) + ":" + currentPath; + var additions = GetPathAdditions(); + if (additions.Length == 0) return null; + + // Only return the additions - ExecPath.TryRun will prepend to existing PATH + return string.Join(Path.PathSeparator, additions); } private string[] GetPathAdditions() @@ -242,16 +252,7 @@ private bool TryFindInPath(string executable, out string fullPath) try { - var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - var pathAdditions = new[] - { - "/usr/local/bin", - "/usr/bin", - "/bin", - "/snap/bin", - Path.Combine(homeDir, ".local", "bin") - }; - string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); + string augmentedPath = BuildAugmentedPath(); if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath)) return false; diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs index eee8b064a..20cb2c6d0 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs @@ -139,25 +139,25 @@ private bool TryValidatePython(string pythonPath, out string version, out string try { - var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - var pathAdditions = new[] + string augmentedPath = BuildAugmentedPath(); + + // First, try to resolve the absolute path for better UI/logging display + string commandToRun = pythonPath; + if (TryFindInPath(pythonPath, out string resolvedPath)) { - "/opt/homebrew/bin", - "/usr/local/bin", - "/usr/bin", - Path.Combine(homeDir, ".local", "bin") - }; - string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); - - if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr, + commandToRun = resolvedPath; + } + + if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, 5000, augmentedPath)) return false; - string output = stdout.Trim(); + // Check stdout first, then stderr (some Python distributions output to stderr) + string output = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim(); if (output.StartsWith("Python ")) { version = output.Substring(7); - fullPath = pythonPath; + fullPath = commandToRun; if (TryParseVersion(version, out var major, out var minor)) { @@ -180,8 +180,15 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str try { + // First, try to resolve the absolute path for better UI/logging display + string commandToRun = command; + if (TryFindInPath(command, out string resolvedPath)) + { + commandToRun = resolvedPath; + } + // Use ExecPath.TryRun which properly handles async output reading and timeouts - if (!ExecPath.TryRun(command, "--version", null, out string stdout, out string stderr, + if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, 5000, augmentedPath)) return false; @@ -190,6 +197,7 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str if (output.StartsWith("uv ") || output.StartsWith("uvx ")) { // Extract version: "uvx 0.9.18" -> "0.9.18" + // Handle extra tokens: "uvx 0.9.18 extra" or "uvx 0.9.18 (build info)" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { @@ -201,7 +209,7 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str parenIndex >= 0 ? parenIndex : int.MaxValue ); version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; - fullPath = command; + fullPath = commandToRun; return true; } } @@ -214,11 +222,13 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str return false; } - private string BuildAugmentedPath() + protected string BuildAugmentedPath() { - var pathAdditions = GetPathAdditions(); - string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - return string.Join(":", pathAdditions) + ":" + currentPath; + var additions = GetPathAdditions(); + if (additions.Length == 0) return null; + + // Only return the additions - ExecPath.TryRun will prepend to existing PATH + return string.Join(Path.PathSeparator, additions); } private string[] GetPathAdditions() @@ -240,16 +250,7 @@ private bool TryFindInPath(string executable, out string fullPath) try { - var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - var pathAdditions = new[] - { - "/opt/homebrew/bin", - "/usr/local/bin", - "/usr/bin", - "/bin", - Path.Combine(homeDir, ".local", "bin") - }; - string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? ""); + string augmentedPath = BuildAugmentedPath(); if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath)) return false; diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs index d11129e44..16896319b 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs @@ -1,3 +1,8 @@ +/* + //Windows currently does not override DetectUv(), relying entirely on the base class. This is correct because: + //The PathResolverService already includes Windows-specific paths. + //There are no additional Windows-specific detection requirements. +*/ using System; using System.Collections.Generic; using System.Diagnostics; @@ -147,15 +152,24 @@ private bool TryValidatePython(string pythonPath, out string version, out string try { string augmentedPath = BuildAugmentedPath(); + + // First, try to resolve the absolute path for better UI/logging display + string commandToRun = pythonPath; + if (TryFindInPath(pythonPath, out string resolvedPath)) + { + commandToRun = resolvedPath; + } + // Run 'python --version' to get the version - if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr, 5000, augmentedPath)) + if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, 5000, augmentedPath)) return false; - string output = stdout.Trim(); + // Check stdout first, then stderr (some Python distributions output to stderr) + string output = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim(); if (output.StartsWith("Python ")) { version = output.Substring(7); - fullPath = pythonPath; + fullPath = commandToRun; if (TryParseVersion(version, out var major, out var minor)) { @@ -197,10 +211,13 @@ private bool TryFindInPath(string executable, out string fullPath) return false; } - private string BuildAugmentedPath() + protected string BuildAugmentedPath() { - string currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - return string.Join(Path.PathSeparator, GetPathAdditions()) + Path.PathSeparator + currentPath; + var additions = GetPathAdditions(); + if (additions.Length == 0) return null; + + // Only return the additions - ExecPath.TryRun will prepend to existing PATH + return string.Join(Path.PathSeparator, additions); } private string[] GetPathAdditions() @@ -239,7 +256,7 @@ private string[] GetPathAdditions() if (!string.IsNullOrEmpty(homeDir)) additions.Add(Path.Combine(homeDir, ".local", "bin")); - return additions.Where(Directory.Exists).ToArray(); + return additions.ToArray(); } } } diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index 56c05667c..29366969c 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -21,112 +21,51 @@ public class PathResolverService : IPathResolverService public string GetUvxPath() { - try + // Check override first - only validate if explicitly set + if (HasUvxPathOverride) { string overridePath = EditorPrefs.GetString(EditorPrefKeys.UvxPathOverride, string.Empty); - if (!string.IsNullOrEmpty(overridePath)) + // Validate the override - if invalid, don't fall back to discovery + if (TryValidateUvExecutable(overridePath, out string version)) { return overridePath; } - } - catch - { - // ignore EditorPrefs read errors and fall back to default command - McpLog.Debug("No uvx path override found, falling back to default command"); + // Override is set but invalid - return null (no fallback) + return null; } + // No override set - try discovery (uvx first, then uv) string discovered = ResolveUvxFromSystem(); if (!string.IsNullOrEmpty(discovered)) { return discovered; } + // Fallback to bare command return "uvx"; } - public string GetClaudeCliPath() - { - try - { - string overridePath = EditorPrefs.GetString(EditorPrefKeys.ClaudeCliPathOverride, string.Empty); - if (!string.IsNullOrEmpty(overridePath) && File.Exists(overridePath)) - { - return overridePath; - } - } - catch { /* ignore */ } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string[] candidates = new[] - { - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "claude", "claude.exe"), - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "claude", "claude.exe"), - "claude.exe" - }; - - foreach (var c in candidates) - { - if (File.Exists(c)) return c; - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - string[] candidates = new[] - { - "/opt/homebrew/bin/claude", - "/usr/local/bin/claude", - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".local", "bin", "claude") - }; - - foreach (var c in candidates) - { - if (File.Exists(c)) return c; - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - string[] candidates = new[] - { - "/usr/bin/claude", - "/usr/local/bin/claude", - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".local", "bin", "claude") - }; - - foreach (var c in candidates) - { - if (File.Exists(c)) return c; - } - } - - return null; - } - - public bool IsPythonDetected() - { - return ExecPath.TryRun( - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "python.exe" : "python3", - "--version", - null, - out _, - out _, - 2000); - } - - public bool IsClaudeCliDetected() - { - return !string.IsNullOrEmpty(GetClaudeCliPath()); - } - + /// + /// Resolves uv/uvx from system by trying both commands. + /// Returns the full path if found, null otherwise. + /// private static string ResolveUvxFromSystem() { try { - foreach (string candidate in EnumerateUvxCandidates()) + // Try uvx first, then uv + string[] commandNames = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? new[] { "uvx.exe", "uv.exe" } + : new[] { "uvx", "uv" }; + + foreach (string commandName in commandNames) { - if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate)) + foreach (string candidate in EnumerateUvxCandidates(commandName)) { - return candidate; + if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate)) + { + return candidate; + } } } } @@ -138,9 +77,12 @@ private static string ResolveUvxFromSystem() return null; } - private static IEnumerable EnumerateUvxCandidates() + /// + /// Enumerates candidate paths for uv/uvx executables. + /// + private static IEnumerable EnumerateUvxCandidates(string commandName) { - string exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "uvx.exe" : "uvx"; + string exeName = commandName; // Priority 1: User-configured PATH (most common scenario from official install scripts) string pathEnv = Environment.GetEnvironmentVariable("PATH"); @@ -152,10 +94,10 @@ private static IEnumerable EnumerateUvxCandidates() string dir = rawDir.Trim(); yield return Path.Combine(dir, exeName); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && commandName.EndsWith(".exe")) { // Some PATH entries may already contain the file without extension - yield return Path.Combine(dir, "uvx"); + yield return Path.Combine(dir, commandName.Replace(".exe", "")); } } } @@ -197,6 +139,84 @@ private static IEnumerable EnumerateUvxCandidates() } } + public string GetClaudeCliPath() + { + // Check override first - only validate if explicitly set + if (HasClaudeCliPathOverride) + { + string overridePath = EditorPrefs.GetString(EditorPrefKeys.ClaudeCliPathOverride, string.Empty); + // Validate the override - if invalid, don't fall back to discovery + if (File.Exists(overridePath)) + { + return overridePath; + } + // Override is set but invalid - return null (no fallback) + return null; + } + + // No override - use platform-specific discovery + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string[] candidates = new[] + { + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "claude", "claude.exe"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "claude", "claude.exe"), + "claude.exe" + }; + + foreach (var c in candidates) + { + if (File.Exists(c)) return c; + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + string[] candidates = new[] + { + "/opt/homebrew/bin/claude", + "/usr/local/bin/claude", + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "bin", "claude") + }; + + foreach (var c in candidates) + { + if (File.Exists(c)) return c; + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + string[] candidates = new[] + { + "/usr/bin/claude", + "/usr/local/bin/claude", + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "bin", "claude") + }; + + foreach (var c in candidates) + { + if (File.Exists(c)) return c; + } + } + + return null; + } + + public bool IsPythonDetected() + { + return ExecPath.TryRun( + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "python.exe" : "python3", + "--version", + null, + out _, + out _, + 2000); + } + + public bool IsClaudeCliDetected() + { + return !string.IsNullOrEmpty(GetClaudeCliPath()); + } + public void SetUvxPathOverride(string path) { if (string.IsNullOrEmpty(path)) @@ -259,7 +279,7 @@ public bool TryValidateUvExecutable(string uvPath, out string version) if (isBareCommand) { - // For bare commands like "uvx", use where/which to find full path first + // For bare commands like "uvx" or "uv", use EnumerateCommandCandidates to find full path first string fullPath = FindUvxExecutableInPath(uvPath); if (string.IsNullOrEmpty(fullPath)) return false; @@ -305,22 +325,12 @@ private string FindUvxExecutableInPath(string commandName) { try { - string exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !commandName.EndsWith(".exe") - ? commandName + ".exe" - : commandName; - - // First try EnumerateUvxCandidates which checks File.Exists - foreach (string candidate in EnumerateUvxCandidates()) + // Generic search for any command in PATH and common locations + foreach (string candidate in EnumerateCommandCandidates(commandName)) { if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate)) { - // Check if this candidate matches our command name - string candidateName = Path.GetFileName(candidate); - if (candidateName.Equals(exeName, StringComparison.OrdinalIgnoreCase) || - candidateName.Equals(commandName, StringComparison.OrdinalIgnoreCase)) - { - return candidate; - } + return candidate; } } } @@ -331,5 +341,63 @@ private string FindUvxExecutableInPath(string commandName) return null; } + + /// + /// Enumerates candidate paths for a generic command name. + /// Searches PATH and common locations. + /// + private static IEnumerable EnumerateCommandCandidates(string commandName) + { + string exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !commandName.EndsWith(".exe") + ? commandName + ".exe" + : commandName; + + // Search PATH first + string pathEnv = Environment.GetEnvironmentVariable("PATH"); + if (!string.IsNullOrEmpty(pathEnv)) + { + foreach (string rawDir in pathEnv.Split(Path.PathSeparator)) + { + if (string.IsNullOrWhiteSpace(rawDir)) continue; + string dir = rawDir.Trim(); + yield return Path.Combine(dir, exeName); + } + } + + // User-local binary directories + string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + if (!string.IsNullOrEmpty(home)) + { + yield return Path.Combine(home, ".local", "bin", exeName); + yield return Path.Combine(home, ".cargo", "bin", exeName); + } + + // System directories (platform-specific) + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + yield return "/opt/homebrew/bin/" + exeName; + yield return "/usr/local/bin/" + exeName; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + yield return "/usr/local/bin/" + exeName; + yield return "/usr/bin/" + exeName; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + + if (!string.IsNullOrEmpty(localAppData)) + { + yield return Path.Combine(localAppData, "Programs", "uv", exeName); + } + + if (!string.IsNullOrEmpty(programFiles)) + { + yield return Path.Combine(programFiles, "uv", exeName); + } + } + } } } diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta b/README-zh.md.meta similarity index 54% rename from TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta rename to README-zh.md.meta index f524db054..b241e048c 100644 --- a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta +++ b/README-zh.md.meta @@ -1,8 +1,7 @@ fileFormatVersion: 2 -guid: e1260c1148f6143b28bae5ace5e9c5d1 -NativeFormatImporter: +guid: 7ee419ac1dd966449a6635af11188445 +TextScriptImporter: externalObjects: {} - mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 000000000..2f71f10f1 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 22e770f7b5882c7479bb7133120bb971 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server.meta b/Server.meta new file mode 100644 index 000000000..4ef920302 --- /dev/null +++ b/Server.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b2b012d14c198e44eadc8c28c0da7876 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/DOCKER_OVERVIEW.md.meta b/Server/DOCKER_OVERVIEW.md.meta new file mode 100644 index 000000000..51c82b455 --- /dev/null +++ b/Server/DOCKER_OVERVIEW.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e637ae94b7783074c88738e9ea38718e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/Dockerfile.meta b/Server/Dockerfile.meta new file mode 100644 index 000000000..a07b294e8 --- /dev/null +++ b/Server/Dockerfile.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 98f232acd1be4c946a388d944ad87837 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/README.md.meta b/Server/README.md.meta new file mode 100644 index 000000000..8fa4bea66 --- /dev/null +++ b/Server/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f99295e86aef46742aa4541dfe8c5ada +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/__init__.py.meta b/Server/__init__.py.meta new file mode 100644 index 000000000..1b420dac5 --- /dev/null +++ b/Server/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 40efb7c3491369146b26c222d4258279 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/pyproject.toml.meta b/Server/pyproject.toml.meta new file mode 100644 index 000000000..23c3844ff --- /dev/null +++ b/Server/pyproject.toml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5249476a602f62c4cb465c78e769e119 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/pyrightconfig.json.meta b/Server/pyrightconfig.json.meta new file mode 100644 index 000000000..58d63b728 --- /dev/null +++ b/Server/pyrightconfig.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ec742965bbe2dd44f804c59dd84407fa +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src.meta b/Server/src.meta new file mode 100644 index 000000000..bf2e8f313 --- /dev/null +++ b/Server/src.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f464e790de0083e478e2e7ab904aaac5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/__init__.py.meta b/Server/src/__init__.py.meta new file mode 100644 index 000000000..34adddab3 --- /dev/null +++ b/Server/src/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 81ea0272634405542845ab080758c08b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/core.meta b/Server/src/core.meta new file mode 100644 index 000000000..4729e3cd2 --- /dev/null +++ b/Server/src/core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39bff2dd227e914418cca82e651e70e5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/core/__init__.py.meta b/Server/src/core/__init__.py.meta new file mode 100644 index 000000000..6d5fda274 --- /dev/null +++ b/Server/src/core/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ae450420d0f9de74fa3dbf4199439547 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/core/config.py.meta b/Server/src/core/config.py.meta new file mode 100644 index 000000000..76b222c3c --- /dev/null +++ b/Server/src/core/config.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0e33e98914fc1ca469e53306b1d37e1c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/core/logging_decorator.py.meta b/Server/src/core/logging_decorator.py.meta new file mode 100644 index 000000000..d551facc8 --- /dev/null +++ b/Server/src/core/logging_decorator.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e993bbd747b756848914704f3ae59a49 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/core/telemetry.py.meta b/Server/src/core/telemetry.py.meta new file mode 100644 index 000000000..3217b73fb --- /dev/null +++ b/Server/src/core/telemetry.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 82c021e32497c9242830656e7f294f93 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/core/telemetry_decorator.py.meta b/Server/src/core/telemetry_decorator.py.meta new file mode 100644 index 000000000..a7f1a1cb2 --- /dev/null +++ b/Server/src/core/telemetry_decorator.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0eef8a1c20884e642b1b9c0041d7a9ed +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/main.py.meta b/Server/src/main.py.meta new file mode 100644 index 000000000..395393ee7 --- /dev/null +++ b/Server/src/main.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b50f9566865be6242a1f919d8d82309f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/mcpforunityserver.egg-info.meta b/Server/src/mcpforunityserver.egg-info.meta new file mode 100644 index 000000000..c84ef947b --- /dev/null +++ b/Server/src/mcpforunityserver.egg-info.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0d06746de9afd6a44b595a7ec18d4884 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/models.meta b/Server/src/models.meta new file mode 100644 index 000000000..61496e8d8 --- /dev/null +++ b/Server/src/models.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bcd618313eb241d47b7f2501e49bbe90 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/models/__init__.py.meta b/Server/src/models/__init__.py.meta new file mode 100644 index 000000000..bafd6cff4 --- /dev/null +++ b/Server/src/models/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 78d969287a07afa46baa8cc15b6c38f4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/models/models.py.meta b/Server/src/models/models.py.meta new file mode 100644 index 000000000..7dbecefc8 --- /dev/null +++ b/Server/src/models/models.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: af569acc9ee99ef46b187b6bbda568cf +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/models/unity_response.py.meta b/Server/src/models/unity_response.py.meta new file mode 100644 index 000000000..b0660c6c3 --- /dev/null +++ b/Server/src/models/unity_response.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9a1e7f68f806ef743be1b8113df9f1c6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services.meta b/Server/src/services.meta new file mode 100644 index 000000000..d58561093 --- /dev/null +++ b/Server/src/services.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cef3c50d7527f8643ae9c4bfacccdea8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/__init__.py.meta b/Server/src/services/__init__.py.meta new file mode 100644 index 000000000..74bd0b38e --- /dev/null +++ b/Server/src/services/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5bb0bfd5f53931b42af61b1bcf5ed0a4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/custom_tool_service.py.meta b/Server/src/services/custom_tool_service.py.meta new file mode 100644 index 000000000..c5fb64a90 --- /dev/null +++ b/Server/src/services/custom_tool_service.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a92813394c110014cba4b99609ea2671 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/registry.meta b/Server/src/services/registry.meta new file mode 100644 index 000000000..365dbabbe --- /dev/null +++ b/Server/src/services/registry.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce0efc970a25f5d46bb04a4def011c28 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/registry/__init__.py.meta b/Server/src/services/registry/__init__.py.meta new file mode 100644 index 000000000..beddce3f0 --- /dev/null +++ b/Server/src/services/registry/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dbb9c43a38438654fa75186177f9ca8c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/registry/resource_registry.py.meta b/Server/src/services/registry/resource_registry.py.meta new file mode 100644 index 000000000..b8f44100b --- /dev/null +++ b/Server/src/services/registry/resource_registry.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 65579c33e0d1da3448dd3d21098ff052 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/registry/tool_registry.py.meta b/Server/src/services/registry/tool_registry.py.meta new file mode 100644 index 000000000..905a0470c --- /dev/null +++ b/Server/src/services/registry/tool_registry.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2665f8971919fc249aaa72b5abb22271 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources.meta b/Server/src/services/resources.meta new file mode 100644 index 000000000..7433decf3 --- /dev/null +++ b/Server/src/services/resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 41122f17012fb11489adacfe3727b21f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/__init__.py.meta b/Server/src/services/resources/__init__.py.meta new file mode 100644 index 000000000..17821ce5f --- /dev/null +++ b/Server/src/services/resources/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cac7644223502944ca6e77405f582169 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/active_tool.py.meta b/Server/src/services/resources/active_tool.py.meta new file mode 100644 index 000000000..e3d359881 --- /dev/null +++ b/Server/src/services/resources/active_tool.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2ae46c9c998c6b3468c29a6fd1374379 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/custom_tools.py.meta b/Server/src/services/resources/custom_tools.py.meta new file mode 100644 index 000000000..244229647 --- /dev/null +++ b/Server/src/services/resources/custom_tools.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: efaee24cbd6df8a498fa43fcd8ebbb69 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/editor_state.py.meta b/Server/src/services/resources/editor_state.py.meta new file mode 100644 index 000000000..b607e171d --- /dev/null +++ b/Server/src/services/resources/editor_state.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 34ff3e20c32932c4aa62d88e59e5f75f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/gameobject.py.meta b/Server/src/services/resources/gameobject.py.meta new file mode 100644 index 000000000..abaa2cf4e --- /dev/null +++ b/Server/src/services/resources/gameobject.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d2352c5730ed24944a93c279fc80f16b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/layers.py.meta b/Server/src/services/resources/layers.py.meta new file mode 100644 index 000000000..1b1885b40 --- /dev/null +++ b/Server/src/services/resources/layers.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0c176e1a999897342a46284ac65245fd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/menu_items.py.meta b/Server/src/services/resources/menu_items.py.meta new file mode 100644 index 000000000..5a342daef --- /dev/null +++ b/Server/src/services/resources/menu_items.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cfb45e8d081d768429671db7f4fbbc30 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/prefab_stage.py.meta b/Server/src/services/resources/prefab_stage.py.meta new file mode 100644 index 000000000..2f81a461a --- /dev/null +++ b/Server/src/services/resources/prefab_stage.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 94254ab181839034d8f4349a613ba862 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/project_info.py.meta b/Server/src/services/resources/project_info.py.meta new file mode 100644 index 000000000..8a748d049 --- /dev/null +++ b/Server/src/services/resources/project_info.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5326951abe940934c926ac4c3bbe34a1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/selection.py.meta b/Server/src/services/resources/selection.py.meta new file mode 100644 index 000000000..fa437cc8a --- /dev/null +++ b/Server/src/services/resources/selection.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 962c6804fb29c5c429bf19476fdb2f20 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/tags.py.meta b/Server/src/services/resources/tags.py.meta new file mode 100644 index 000000000..95fc38389 --- /dev/null +++ b/Server/src/services/resources/tags.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b92b14d6764ccb0478555d42fea6d9d8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/tests.py.meta b/Server/src/services/resources/tests.py.meta new file mode 100644 index 000000000..0ec6dba03 --- /dev/null +++ b/Server/src/services/resources/tests.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 97fa5345ee85e2640a7b8c8ed2f98b90 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/unity_instances.py.meta b/Server/src/services/resources/unity_instances.py.meta new file mode 100644 index 000000000..e3cfda465 --- /dev/null +++ b/Server/src/services/resources/unity_instances.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0eb71ea954cbc14429ca78a4ac88ac14 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/resources/windows.py.meta b/Server/src/services/resources/windows.py.meta new file mode 100644 index 000000000..6a593ec01 --- /dev/null +++ b/Server/src/services/resources/windows.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8ddacca6a44d2d449bdf46fcf93adba4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/state.meta b/Server/src/services/state.meta new file mode 100644 index 000000000..7e07e4c2c --- /dev/null +++ b/Server/src/services/state.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f52ba560b50b2274aac05efcb9f1433a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/state/external_changes_scanner.py.meta b/Server/src/services/state/external_changes_scanner.py.meta new file mode 100644 index 000000000..77c562b31 --- /dev/null +++ b/Server/src/services/state/external_changes_scanner.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 222c99256eece3640ad06890823e6e07 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools.meta b/Server/src/services/tools.meta new file mode 100644 index 000000000..f1f2328e2 --- /dev/null +++ b/Server/src/services/tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 44c48e9900d70404ebce0437f7f0e72f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/__init__.py.meta b/Server/src/services/tools/__init__.py.meta new file mode 100644 index 000000000..a520c9687 --- /dev/null +++ b/Server/src/services/tools/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c5f53f694b279dd48911be214b48fe09 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/batch_execute.py.meta b/Server/src/services/tools/batch_execute.py.meta new file mode 100644 index 000000000..bb1ce6b53 --- /dev/null +++ b/Server/src/services/tools/batch_execute.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: caffd99bf73e1754eba84830c7403f0b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/debug_request_context.py.meta b/Server/src/services/tools/debug_request_context.py.meta new file mode 100644 index 000000000..1208a0da3 --- /dev/null +++ b/Server/src/services/tools/debug_request_context.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f06210583487df04cab73e4947070bf5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/execute_custom_tool.py.meta b/Server/src/services/tools/execute_custom_tool.py.meta new file mode 100644 index 000000000..22b20302f --- /dev/null +++ b/Server/src/services/tools/execute_custom_tool.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 66101c93c5808ad4b84976a85245db8d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/execute_menu_item.py.meta b/Server/src/services/tools/execute_menu_item.py.meta new file mode 100644 index 000000000..9eae8a841 --- /dev/null +++ b/Server/src/services/tools/execute_menu_item.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c1cbe79d893c18c41b90638e0e46339c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/find_gameobjects.py.meta b/Server/src/services/tools/find_gameobjects.py.meta new file mode 100644 index 000000000..332ee699a --- /dev/null +++ b/Server/src/services/tools/find_gameobjects.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b7d875dec66df784399a76ab510897cd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/find_in_file.py.meta b/Server/src/services/tools/find_in_file.py.meta new file mode 100644 index 000000000..1ee822e93 --- /dev/null +++ b/Server/src/services/tools/find_in_file.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 90171f31bffff4543a50e7cd4c181cbc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_asset.py.meta b/Server/src/services/tools/manage_asset.py.meta new file mode 100644 index 000000000..c7bc99e0f --- /dev/null +++ b/Server/src/services/tools/manage_asset.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 67fcf75cf05591d45ae0bcd27e8aed93 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_components.py.meta b/Server/src/services/tools/manage_components.py.meta new file mode 100644 index 000000000..e9f80ad0b --- /dev/null +++ b/Server/src/services/tools/manage_components.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7bdf6eeed3b58c24db395639e621b105 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_editor.py.meta b/Server/src/services/tools/manage_editor.py.meta new file mode 100644 index 000000000..9dfce3496 --- /dev/null +++ b/Server/src/services/tools/manage_editor.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 437a1624dc11ba54d869a15022596a03 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_gameobject.py.meta b/Server/src/services/tools/manage_gameobject.py.meta new file mode 100644 index 000000000..f24389b8a --- /dev/null +++ b/Server/src/services/tools/manage_gameobject.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ffbf4b2d4792418499c871bca6d6ad26 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_material.py.meta b/Server/src/services/tools/manage_material.py.meta new file mode 100644 index 000000000..7fc3c0791 --- /dev/null +++ b/Server/src/services/tools/manage_material.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 688e38c2457ec794199ac56a40559b9b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_prefabs.py.meta b/Server/src/services/tools/manage_prefabs.py.meta new file mode 100644 index 000000000..682cd070e --- /dev/null +++ b/Server/src/services/tools/manage_prefabs.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6e712e8aac9a8954191ed50dc3eb68b3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_scene.py.meta b/Server/src/services/tools/manage_scene.py.meta new file mode 100644 index 000000000..73689c52d --- /dev/null +++ b/Server/src/services/tools/manage_scene.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a3a132bde6db56744912f55f7b2a0e08 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_script.py.meta b/Server/src/services/tools/manage_script.py.meta new file mode 100644 index 000000000..44571ae25 --- /dev/null +++ b/Server/src/services/tools/manage_script.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1f104cddffd93f44998948be5031ce39 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_scriptable_object.py.meta b/Server/src/services/tools/manage_scriptable_object.py.meta new file mode 100644 index 000000000..254fad805 --- /dev/null +++ b/Server/src/services/tools/manage_scriptable_object.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 69b0baab1ac58aa49abf3ee2558eedec +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_shader.py.meta b/Server/src/services/tools/manage_shader.py.meta new file mode 100644 index 000000000..e2f7b7861 --- /dev/null +++ b/Server/src/services/tools/manage_shader.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 40b4724d8510941499bf1987f443c4e8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/manage_vfx.py.meta b/Server/src/services/tools/manage_vfx.py.meta new file mode 100644 index 000000000..98736cf66 --- /dev/null +++ b/Server/src/services/tools/manage_vfx.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 748c1b09d1d872c4a97ede6331d0ccdc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/preflight.py.meta b/Server/src/services/tools/preflight.py.meta new file mode 100644 index 000000000..986baaf55 --- /dev/null +++ b/Server/src/services/tools/preflight.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6a21777f1dcb9054eb220139a7e3420a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/read_console.py.meta b/Server/src/services/tools/read_console.py.meta new file mode 100644 index 000000000..1830520d3 --- /dev/null +++ b/Server/src/services/tools/read_console.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 76618a99018a8ea4d9e5882cf1774899 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/refresh_unity.py.meta b/Server/src/services/tools/refresh_unity.py.meta new file mode 100644 index 000000000..b64a3d8e0 --- /dev/null +++ b/Server/src/services/tools/refresh_unity.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dbc4e2e0bab39d049afc6c093dd297dd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/run_tests.py.meta b/Server/src/services/tools/run_tests.py.meta new file mode 100644 index 000000000..68f32401e --- /dev/null +++ b/Server/src/services/tools/run_tests.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e78e9cdaa4badd6479868fbd97b2d72c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/script_apply_edits.py.meta b/Server/src/services/tools/script_apply_edits.py.meta new file mode 100644 index 000000000..7e2197826 --- /dev/null +++ b/Server/src/services/tools/script_apply_edits.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3c4276cd4c0c5654c863fbedbcd6e4e3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/set_active_instance.py.meta b/Server/src/services/tools/set_active_instance.py.meta new file mode 100644 index 000000000..5c4d45043 --- /dev/null +++ b/Server/src/services/tools/set_active_instance.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eebaeac441a02654c97ee4bc8b2a8d1b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/services/tools/utils.py.meta b/Server/src/services/tools/utils.py.meta new file mode 100644 index 000000000..d0cd9cede --- /dev/null +++ b/Server/src/services/tools/utils.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 89f5ae66560cf09488dd80c253841057 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport.meta b/Server/src/transport.meta new file mode 100644 index 000000000..ed61c8f3c --- /dev/null +++ b/Server/src/transport.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9a5563aa3841d240871b6955fb97058 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/__init__.py.meta b/Server/src/transport/__init__.py.meta new file mode 100644 index 000000000..d018b05b9 --- /dev/null +++ b/Server/src/transport/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b255dd0281768af4ba49f0fc3e8b2f3b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/legacy.meta b/Server/src/transport/legacy.meta new file mode 100644 index 000000000..172d6c8be --- /dev/null +++ b/Server/src/transport/legacy.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7554a33516319ea49bc5e10d7a01cd16 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/legacy/port_discovery.py.meta b/Server/src/transport/legacy/port_discovery.py.meta new file mode 100644 index 000000000..fb4ad4807 --- /dev/null +++ b/Server/src/transport/legacy/port_discovery.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 619465c600774b04887aebb480da38b7 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/legacy/stdio_port_registry.py.meta b/Server/src/transport/legacy/stdio_port_registry.py.meta new file mode 100644 index 000000000..157a23c2d --- /dev/null +++ b/Server/src/transport/legacy/stdio_port_registry.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f14d54d79a0355440a7e5ac4cb91cb0c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/legacy/unity_connection.py.meta b/Server/src/transport/legacy/unity_connection.py.meta new file mode 100644 index 000000000..4a2798f3f --- /dev/null +++ b/Server/src/transport/legacy/unity_connection.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 936a855b9daafed4b93791f783dad48a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/models.py.meta b/Server/src/transport/models.py.meta new file mode 100644 index 000000000..7acf62038 --- /dev/null +++ b/Server/src/transport/models.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 56f323ff419f1e94780c5f83ea72e363 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/plugin_hub.py.meta b/Server/src/transport/plugin_hub.py.meta new file mode 100644 index 000000000..6e2426c57 --- /dev/null +++ b/Server/src/transport/plugin_hub.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8191732cc50582c468404fc739bf3b2e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/plugin_registry.py.meta b/Server/src/transport/plugin_registry.py.meta new file mode 100644 index 000000000..e6d0e9f67 --- /dev/null +++ b/Server/src/transport/plugin_registry.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e6c350ac6176ee54badf5db9439c432a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/unity_instance_middleware.py.meta b/Server/src/transport/unity_instance_middleware.py.meta new file mode 100644 index 000000000..4cf4e1fa3 --- /dev/null +++ b/Server/src/transport/unity_instance_middleware.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 456dec3abb618ea40ac4b35e396a587d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/transport/unity_transport.py.meta b/Server/src/transport/unity_transport.py.meta new file mode 100644 index 000000000..f76365a7f --- /dev/null +++ b/Server/src/transport/unity_transport.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f086a5cbe1422a14981fe47c83d88670 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/utils.meta b/Server/src/utils.meta new file mode 100644 index 000000000..f48731ac8 --- /dev/null +++ b/Server/src/utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d6f5bca6b22bd3468dbb3f0235cee67 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/utils/module_discovery.py.meta b/Server/src/utils/module_discovery.py.meta new file mode 100644 index 000000000..84adff64e --- /dev/null +++ b/Server/src/utils/module_discovery.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 652f3ab8d3c99c74298b87d588c02f02 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/src/utils/reload_sentinel.py.meta b/Server/src/utils/reload_sentinel.py.meta new file mode 100644 index 000000000..03eb0dc7c --- /dev/null +++ b/Server/src/utils/reload_sentinel.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d8d62316caa283041906a9c769c23554 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests.meta b/Server/tests.meta new file mode 100644 index 000000000..10b8d58b8 --- /dev/null +++ b/Server/tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73f3440d5e14b104bb14b6ed5322fe9e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/__init__.py.meta b/Server/tests/__init__.py.meta new file mode 100644 index 000000000..19d8e82c4 --- /dev/null +++ b/Server/tests/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b6a435683a37bfb4c98690b72607a152 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration.meta b/Server/tests/integration.meta new file mode 100644 index 000000000..6fb54249b --- /dev/null +++ b/Server/tests/integration.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 72d784ed2e7184043a93da74377ecfe1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/__init__.py.meta b/Server/tests/integration/__init__.py.meta new file mode 100644 index 000000000..74551c93e --- /dev/null +++ b/Server/tests/integration/__init__.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fc17eda1077966d4d97aa133383f687d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/conftest.py.meta b/Server/tests/integration/conftest.py.meta new file mode 100644 index 000000000..0b6144b8f --- /dev/null +++ b/Server/tests/integration/conftest.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8ac762753744ad44ba9e1800bf3b39a6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_debug_request_context_diagnostics.py.meta b/Server/tests/integration/test_debug_request_context_diagnostics.py.meta new file mode 100644 index 000000000..0da6e60a1 --- /dev/null +++ b/Server/tests/integration/test_debug_request_context_diagnostics.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 225d1a276f26cd34594eea7b70b6af97 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_domain_reload_resilience.py.meta b/Server/tests/integration/test_domain_reload_resilience.py.meta new file mode 100644 index 000000000..db8b2bf5c --- /dev/null +++ b/Server/tests/integration/test_domain_reload_resilience.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6e9bae83b1dfb1c44b5b89d377b8e9bc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_edit_normalization_and_noop.py.meta b/Server/tests/integration/test_edit_normalization_and_noop.py.meta new file mode 100644 index 000000000..62ee31784 --- /dev/null +++ b/Server/tests/integration/test_edit_normalization_and_noop.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6a6c220bd546d6141bc81caf5c5d5c0c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_edit_strict_and_warnings.py.meta b/Server/tests/integration/test_edit_strict_and_warnings.py.meta new file mode 100644 index 000000000..83117f359 --- /dev/null +++ b/Server/tests/integration/test_edit_strict_and_warnings.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 68d819ebdd34b9b4d94cf2a724deaab8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_editor_state_v2_contract.py.meta b/Server/tests/integration/test_editor_state_v2_contract.py.meta new file mode 100644 index 000000000..245bc46e8 --- /dev/null +++ b/Server/tests/integration/test_editor_state_v2_contract.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 80931e72bd2d4a641afc1c2e51af0f0c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_external_changes_scanner.py.meta b/Server/tests/integration/test_external_changes_scanner.py.meta new file mode 100644 index 000000000..797dbfbb4 --- /dev/null +++ b/Server/tests/integration/test_external_changes_scanner.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0f8f3a867304c854aa3832ef822964f0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_find_gameobjects.py.meta b/Server/tests/integration/test_find_gameobjects.py.meta new file mode 100644 index 000000000..18185429e --- /dev/null +++ b/Server/tests/integration/test_find_gameobjects.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dd1df5ab6fdec464493d139099f4ee72 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_find_in_file_minimal.py.meta b/Server/tests/integration/test_find_in_file_minimal.py.meta new file mode 100644 index 000000000..1298aee0e --- /dev/null +++ b/Server/tests/integration/test_find_in_file_minimal.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 37376021dec04ce4fab4ab73b6339e18 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_gameobject_resources.py.meta b/Server/tests/integration/test_gameobject_resources.py.meta new file mode 100644 index 000000000..5e09eda82 --- /dev/null +++ b/Server/tests/integration/test_gameobject_resources.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 66dfd0872ba5e2e4da5ffabae751a6ff +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_get_sha.py.meta b/Server/tests/integration/test_get_sha.py.meta new file mode 100644 index 000000000..928e45099 --- /dev/null +++ b/Server/tests/integration/test_get_sha.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2ddb4afbcf9c9c9449c412b9b10adfd0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_helpers.py.meta b/Server/tests/integration/test_helpers.py.meta new file mode 100644 index 000000000..b1cfcb4c0 --- /dev/null +++ b/Server/tests/integration/test_helpers.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1a2c73119a1c91f4ca90ccfd8848d0c7 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_improved_anchor_matching.py.meta b/Server/tests/integration/test_improved_anchor_matching.py.meta new file mode 100644 index 000000000..8d7e3476b --- /dev/null +++ b/Server/tests/integration/test_improved_anchor_matching.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bd611b066c1b0484b97f0a6a7d625c48 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_instance_autoselect.py.meta b/Server/tests/integration/test_instance_autoselect.py.meta new file mode 100644 index 000000000..716e18a0e --- /dev/null +++ b/Server/tests/integration/test_instance_autoselect.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 06aa9fb33062a304ca844c4a005db296 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_instance_routing_comprehensive.py.meta b/Server/tests/integration/test_instance_routing_comprehensive.py.meta new file mode 100644 index 000000000..98bd990eb --- /dev/null +++ b/Server/tests/integration/test_instance_routing_comprehensive.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 691f7d1fb9b83344fb3b9c6296f63e16 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_instance_targeting_resolution.py.meta b/Server/tests/integration/test_instance_targeting_resolution.py.meta new file mode 100644 index 000000000..5fd04e329 --- /dev/null +++ b/Server/tests/integration/test_instance_targeting_resolution.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 573f1751e435e57479cad68f5f40e87f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_json_parsing_simple.py.meta b/Server/tests/integration/test_json_parsing_simple.py.meta new file mode 100644 index 000000000..cec3c657c --- /dev/null +++ b/Server/tests/integration/test_json_parsing_simple.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 49697388fd65a5d4fb1249aa20738c95 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_logging_stdout.py.meta b/Server/tests/integration/test_logging_stdout.py.meta new file mode 100644 index 000000000..e798dd5c8 --- /dev/null +++ b/Server/tests/integration/test_logging_stdout.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1df170c7abf4ecc4f9273490bcc8d72a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_manage_asset_json_parsing.py.meta b/Server/tests/integration/test_manage_asset_json_parsing.py.meta new file mode 100644 index 000000000..4c26f7712 --- /dev/null +++ b/Server/tests/integration/test_manage_asset_json_parsing.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d16b3428ed90b514793830470bb536eb +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_manage_asset_param_coercion.py.meta b/Server/tests/integration/test_manage_asset_param_coercion.py.meta new file mode 100644 index 000000000..9f2f77729 --- /dev/null +++ b/Server/tests/integration/test_manage_asset_param_coercion.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d045dff8ac41d7544a1cacc16c965f89 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_manage_components.py.meta b/Server/tests/integration/test_manage_components.py.meta new file mode 100644 index 000000000..cedd147f0 --- /dev/null +++ b/Server/tests/integration/test_manage_components.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5fe7edc74b58b8545b5a9dfa668be8f6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_manage_gameobject_param_coercion.py.meta b/Server/tests/integration/test_manage_gameobject_param_coercion.py.meta new file mode 100644 index 000000000..35e6ef1a4 --- /dev/null +++ b/Server/tests/integration/test_manage_gameobject_param_coercion.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c951b394891014740bfc9169e6f4a70b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_manage_scene_paging_params.py.meta b/Server/tests/integration/test_manage_scene_paging_params.py.meta new file mode 100644 index 000000000..04824a7ec --- /dev/null +++ b/Server/tests/integration/test_manage_scene_paging_params.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2806f394b02d5f640a42e8a5f479e302 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_manage_script_uri.py.meta b/Server/tests/integration/test_manage_script_uri.py.meta new file mode 100644 index 000000000..148314b9f --- /dev/null +++ b/Server/tests/integration/test_manage_script_uri.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0c8b277e9e833194b8e73cba04d5106f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_manage_scriptable_object_tool.py.meta b/Server/tests/integration/test_manage_scriptable_object_tool.py.meta new file mode 100644 index 000000000..6be23921e --- /dev/null +++ b/Server/tests/integration/test_manage_scriptable_object_tool.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4aec37777cc49cb46a91d70cf659c723 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_read_console_truncate.py.meta b/Server/tests/integration/test_read_console_truncate.py.meta new file mode 100644 index 000000000..0f9eb9643 --- /dev/null +++ b/Server/tests/integration/test_read_console_truncate.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5fda2f179924d964cacc799835995688 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_read_resource_minimal.py.meta b/Server/tests/integration/test_read_resource_minimal.py.meta new file mode 100644 index 000000000..e7835d2ee --- /dev/null +++ b/Server/tests/integration/test_read_resource_minimal.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a2c68347f81c43d4e8ba0cd12e645f44 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_refresh_unity_registration.py.meta b/Server/tests/integration/test_refresh_unity_registration.py.meta new file mode 100644 index 000000000..6f42ff129 --- /dev/null +++ b/Server/tests/integration/test_refresh_unity_registration.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ebd90212a1ce6854cb1102eb6a9c79fe +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_refresh_unity_retry_recovery.py.meta b/Server/tests/integration/test_refresh_unity_retry_recovery.py.meta new file mode 100644 index 000000000..506a224f1 --- /dev/null +++ b/Server/tests/integration/test_refresh_unity_retry_recovery.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fd63fc3435c8f444581f5e75c48340f8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_resources_api.py.meta b/Server/tests/integration/test_resources_api.py.meta new file mode 100644 index 000000000..56517bada --- /dev/null +++ b/Server/tests/integration/test_resources_api.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2e13401eaa145dd4496736dd5c271a0e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_run_tests_async.py.meta b/Server/tests/integration/test_run_tests_async.py.meta new file mode 100644 index 000000000..e2bfbd1f6 --- /dev/null +++ b/Server/tests/integration/test_run_tests_async.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6501557977f3ba84292d88cc51ef8bc4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_script_editing.py.meta b/Server/tests/integration/test_script_editing.py.meta new file mode 100644 index 000000000..c802296a4 --- /dev/null +++ b/Server/tests/integration/test_script_editing.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 76fa6a23a7f972941abc6d3404c2e3df +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_script_tools.py.meta b/Server/tests/integration/test_script_tools.py.meta new file mode 100644 index 000000000..c3f22ef1e --- /dev/null +++ b/Server/tests/integration/test_script_tools.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: faed355daa66d8446b7483ca217a9b0b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_telemetry_endpoint_validation.py.meta b/Server/tests/integration/test_telemetry_endpoint_validation.py.meta new file mode 100644 index 000000000..545faacc9 --- /dev/null +++ b/Server/tests/integration/test_telemetry_endpoint_validation.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fa4c7af843191e04fad10a339e3cbfb8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_telemetry_queue_worker.py.meta b/Server/tests/integration/test_telemetry_queue_worker.py.meta new file mode 100644 index 000000000..60b7a68bc --- /dev/null +++ b/Server/tests/integration/test_telemetry_queue_worker.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6756a2de965b0df41865a27401773ed3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_telemetry_subaction.py.meta b/Server/tests/integration/test_telemetry_subaction.py.meta new file mode 100644 index 000000000..9c4772ecc --- /dev/null +++ b/Server/tests/integration/test_telemetry_subaction.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 218a726002b29b94381018d7ac8b1012 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_tool_signatures_paging.py.meta b/Server/tests/integration/test_tool_signatures_paging.py.meta new file mode 100644 index 000000000..e6eb3107b --- /dev/null +++ b/Server/tests/integration/test_tool_signatures_paging.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8f56c0b63e011f54a83ced53726ae4de +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_transport_framing.py.meta b/Server/tests/integration/test_transport_framing.py.meta new file mode 100644 index 000000000..16489b4e9 --- /dev/null +++ b/Server/tests/integration/test_transport_framing.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d9f90eba3847eba4196a72bc49d8f25a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/integration/test_validate_script_summary.py.meta b/Server/tests/integration/test_validate_script_summary.py.meta new file mode 100644 index 000000000..85c672515 --- /dev/null +++ b/Server/tests/integration/test_validate_script_summary.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 300c629bf12a4b54398d2c45cb9fd301 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/tests/pytest.ini.meta b/Server/tests/pytest.ini.meta new file mode 100644 index 000000000..da8ce2183 --- /dev/null +++ b/Server/tests/pytest.ini.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 74e7f5a79268a734992851fcdb0bee66 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Server/uv.lock.meta b/Server/uv.lock.meta new file mode 100644 index 000000000..5f71d4ec1 --- /dev/null +++ b/Server/uv.lock.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 454b5d1fe82dd634aaa32ae1d299f9bd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects.meta b/TestProjects.meta new file mode 100644 index 000000000..2f14f3fdf --- /dev/null +++ b/TestProjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 021a2ed85354b094b9c8ec2de93507f3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads.meta b/TestProjects/AssetStoreUploads.meta new file mode 100644 index 000000000..75ed4e300 --- /dev/null +++ b/TestProjects/AssetStoreUploads.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0d5ca4ca6bb7d943a15724c6300a1df +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets.meta b/TestProjects/AssetStoreUploads/Assets.meta new file mode 100644 index 000000000..94e8ea640 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47e8e17e1b0de3a4e8e3fe63ae7c7f59 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta deleted file mode 100644 index 8fa7f17dc..000000000 --- a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e634585d5c4544dd297acaee93dc2beb -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta deleted file mode 100644 index bcdff020b..000000000 --- a/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c40be3174f62c4acf8c1216858c64956 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta deleted file mode 100644 index 912ff6009..000000000 --- a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 707360a9c581a4bd7aa53bfeb1429f71 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta deleted file mode 100644 index 264c9c559..000000000 --- a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d0e2fc18fe036412f8223b3b3d9ad574 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta b/TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta deleted file mode 100644 index 81b84f2ae..000000000 --- a/TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 18dc0cd2c080841dea60987a38ce93fa -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages.meta b/TestProjects/AssetStoreUploads/Packages.meta new file mode 100644 index 000000000..49270c71f --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16e2c11c19f0fee4fb69ef5a6f418d9b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta new file mode 100644 index 000000000..ac43fd7f3 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 36d677e7e6b372648b771e2f873cb93d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta deleted file mode 100644 index e64790381..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e0426dd01b5136a4ca1d42d312e12fad -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta deleted file mode 100644 index f7b5dcf3d..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 03c6cd398931b3e41b0784e8589e153f -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta deleted file mode 100644 index 9b1b8d4ea..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 28ab5af444cf3c849800ed0d8f4a3102 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta deleted file mode 100644 index dbf116475..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 53189e6e51235b14192c4d5b3145dd27 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta deleted file mode 100644 index d2f3da2be..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 08790ea0ed0fd274fb1df75ccc32d415 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta deleted file mode 100644 index a5a922abb..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eaf232919893db04b8e05e91f6815424 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta deleted file mode 100644 index deb5c41ff..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ad52ffa05767e9d4bb4d92093ad68b03 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta deleted file mode 100644 index 699185ff2..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1e7b5480c1d8bda43ab4fa945939e243 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta deleted file mode 100644 index cff122c48..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 03b362b67028eb443b7ba8b84aedd5f2 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta deleted file mode 100644 index 6ba4103ab..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1a3d0b3827fc16347867bee335e8f4ea -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta deleted file mode 100644 index 42d6127f2..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bc2cb4e6635aa334ea4a52e2e3ce57c8 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta deleted file mode 100644 index ba55c59e6..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c889cdd91c2f41941a14363dad7a1a38 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta deleted file mode 100644 index 4f493136e..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 45b2b11da67e8864aacc62d928524b4c -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta deleted file mode 100644 index c4aef0714..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ffef800a102b0e04cae1a3b98549ef1b -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta deleted file mode 100644 index 66ff0da6b..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 241ad0174fcadb64da867011d196acbb -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta deleted file mode 100644 index f5e0feab8..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 04098aa074d151b4a908dfa79dfddec3 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta deleted file mode 100644 index 5404fd491..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 87da7eaed3cee0d4b8ada0b500e3a958 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta deleted file mode 100644 index 4ebd5acee..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 21f8ec0602ffac045b1f4a93f8a9b555 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta deleted file mode 100644 index 713d9087b..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 700026f446833f649a3c63b33a90a295 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta deleted file mode 100644 index 3a026fb4d..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 339e21c955642a04289482aa923e10b6 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta deleted file mode 100644 index c9ebccf60..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1450037453608204a989ff95dca62fae -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta deleted file mode 100644 index d0318d49f..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c23253393b8e28846b8e02aeaee7e152 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta deleted file mode 100644 index 2aa250d34..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: dd110ee16e8de4d48a602349ed7a0b25 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta deleted file mode 100644 index b27033d7d..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e996c53186de96e49a742d414648a809 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta deleted file mode 100644 index 45000c997..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 781021ae3aa6570468e08d78e3195127 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta deleted file mode 100644 index d41b9e650..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bf01c18b66907f54c99517f6a877e3e0 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta deleted file mode 100644 index 2026425ca..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a48657926de5cfb47ac559a7108d03ee -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta deleted file mode 100644 index 84abdb1b3..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a0a44055f786ec64f86a07a214d5f831 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta deleted file mode 100644 index ffc10af27..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 305bbe67f7c644d18bc8a5b2273aa6a4 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta deleted file mode 100644 index e62946cea..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 893a0df188c2026438be48eed39b301f -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta deleted file mode 100644 index d58914fe8..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f108107be07f69045813d69eff580078 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta deleted file mode 100644 index 4ee63356a..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b03433f7977b29e4ca7e8d76393a6c26 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta deleted file mode 100644 index 63433dd52..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 25721b2d7384e5b4f936cf3b33b80a02 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta deleted file mode 100644 index a00554e8f..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5392e9de0549574419ff76897d1e0fa1 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/manifest.json.meta b/TestProjects/AssetStoreUploads/Packages/manifest.json.meta new file mode 100644 index 000000000..d2ee1792b --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/manifest.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a0761e5f92276324aaec08f922c40f1f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta b/TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta new file mode 100644 index 000000000..fdf81f9ea --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c9942e867fc168d4f9a364af28d3d338 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings.meta b/TestProjects/AssetStoreUploads/ProjectSettings.meta new file mode 100644 index 000000000..8f22affc0 --- /dev/null +++ b/TestProjects/AssetStoreUploads/ProjectSettings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52996e512febf5942916921ed6e9b200 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta b/TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta new file mode 100644 index 000000000..beb59b36c --- /dev/null +++ b/TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 27f6f627a87621441983a9a83a7a87e5 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta b/TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta new file mode 100644 index 000000000..ebffcb104 --- /dev/null +++ b/TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 77b080dcddd96f54fa1d214108f7f1e8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta b/TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta new file mode 100644 index 000000000..db00e6897 --- /dev/null +++ b/TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f4d93c27cb5cc8c42b1b5d8ef4a66481 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta b/TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta new file mode 100644 index 000000000..f0a6a46a0 --- /dev/null +++ b/TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7b11105935e17ca4fb39ede15e69d91f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests.meta b/TestProjects/UnityMCPTests.meta new file mode 100644 index 000000000..a3a33f21e --- /dev/null +++ b/TestProjects/UnityMCPTests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b20d876ce504eb54b95acd2d2374b127 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Assets.meta b/TestProjects/UnityMCPTests/Assets.meta new file mode 100644 index 000000000..b3cba2c47 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 087c1ee3d6344234eb0048c3106564ea +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Packages.meta b/TestProjects/UnityMCPTests/Packages.meta new file mode 100644 index 000000000..9f2fa7c92 --- /dev/null +++ b/TestProjects/UnityMCPTests/Packages.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7106f5ef5cf5a3d4fb7de8dc41320b74 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Packages/manifest.json.meta b/TestProjects/UnityMCPTests/Packages/manifest.json.meta new file mode 100644 index 000000000..4735e5624 --- /dev/null +++ b/TestProjects/UnityMCPTests/Packages/manifest.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 42ee50e328de6af469c1f3290b7e5670 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings.meta b/TestProjects/UnityMCPTests/ProjectSettings.meta new file mode 100644 index 000000000..e15912fb1 --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67e2b34151b7c104dbec6354ad3618bf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/Packages.meta b/TestProjects/UnityMCPTests/ProjectSettings/Packages.meta new file mode 100644 index 000000000..753ff2c0d --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings/Packages.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 786d3ce7786502b4981f27f363f4b1e1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta new file mode 100644 index 000000000..113cbc66d --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2a7d199a1087a144afd05ff183414da +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta new file mode 100644 index 000000000..9146b71d1 --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 41726fe76ebd66a448f3f2b068ec2893 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta b/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta new file mode 100644 index 000000000..4817eb610 --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6f209388ecef66048883fdc45a7d79e1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta b/TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta new file mode 100644 index 000000000..b32a83503 --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 83c1d94e5535b0e49baa4c32c635d0ff +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/claude_skill_unity.zip.meta b/claude_skill_unity.zip.meta new file mode 100644 index 000000000..d638878f5 --- /dev/null +++ b/claude_skill_unity.zip.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 17022afa0ee8d764bba127ae4be3b838 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/deploy-dev.bat.meta b/deploy-dev.bat.meta new file mode 100644 index 000000000..43f6f447f --- /dev/null +++ b/deploy-dev.bat.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aa78a93ce81ef3b49b535e6dfad7c188 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docker-compose.yml.meta b/docker-compose.yml.meta new file mode 100644 index 000000000..3ef09649a --- /dev/null +++ b/docker-compose.yml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 722628ac8c02f8e45ad1ee86a325e0d0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs.meta b/docs.meta new file mode 100644 index 000000000..29e067d0b --- /dev/null +++ b/docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 77162687c5b9309478a58141f238cff0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/CURSOR_HELP.md.meta b/docs/CURSOR_HELP.md.meta new file mode 100644 index 000000000..9a5fb77ee --- /dev/null +++ b/docs/CURSOR_HELP.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eda97419642608047a689c1177610890 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/CUSTOM_TOOLS.md.meta b/docs/CUSTOM_TOOLS.md.meta new file mode 100644 index 000000000..c26a17935 --- /dev/null +++ b/docs/CUSTOM_TOOLS.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ccbdf7106a5bc774890092e3cc4ab1fa +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/MCP_CLIENT_CONFIGURATORS.md.meta b/docs/MCP_CLIENT_CONFIGURATORS.md.meta new file mode 100644 index 000000000..fa9626ccd --- /dev/null +++ b/docs/MCP_CLIENT_CONFIGURATORS.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 773ec24de26ffd84d837c47307981cdd +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/README-DEV-zh.md.meta b/docs/README-DEV-zh.md.meta new file mode 100644 index 000000000..baf666ab3 --- /dev/null +++ b/docs/README-DEV-zh.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bc8058c8dd3d0b544b23a7ab595e368c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/README-DEV.md.meta b/docs/README-DEV.md.meta new file mode 100644 index 000000000..3232d578f --- /dev/null +++ b/docs/README-DEV.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 880aea42120fe4e4fb4c5f94dd4cdd3f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/TELEMETRY.md.meta b/docs/TELEMETRY.md.meta new file mode 100644 index 000000000..a26680c51 --- /dev/null +++ b/docs/TELEMETRY.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f3c4dcf66d2f5fd4bb676edbcc1fa208 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images.meta b/docs/images.meta new file mode 100644 index 000000000..df3756ec5 --- /dev/null +++ b/docs/images.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c0acdabdddfdbfe48a52db3eb5941549 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/advanced-setting.png.meta b/docs/images/advanced-setting.png.meta new file mode 100644 index 000000000..22d96d25c --- /dev/null +++ b/docs/images/advanced-setting.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 2764160244f83084a93302d15498128d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/building_scene.gif.meta b/docs/images/building_scene.gif.meta new file mode 100644 index 000000000..58180cd0a --- /dev/null +++ b/docs/images/building_scene.gif.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 7fa0f73db31697448b8645c0a4ba71b8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/coplay-logo.png.meta b/docs/images/coplay-logo.png.meta new file mode 100644 index 000000000..8919d4c03 --- /dev/null +++ b/docs/images/coplay-logo.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: a39a9b142e147a24caeb72964423312c +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/logo.png.meta b/docs/images/logo.png.meta new file mode 100644 index 000000000..0c2d596e6 --- /dev/null +++ b/docs/images/logo.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 33dc77dcea2123b4e91a5c58ebb21867 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/networking-architecture.png.meta b/docs/images/networking-architecture.png.meta new file mode 100644 index 000000000..55b531de0 --- /dev/null +++ b/docs/images/networking-architecture.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: e76c69cddaa6aea42b5fcb181dda3a3a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/readme_ui.png.meta b/docs/images/readme_ui.png.meta new file mode 100644 index 000000000..9f265f381 --- /dev/null +++ b/docs/images/readme_ui.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 60028841f2110eb43bbfc65e9143d8f1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/unity-mcp-ui-v8.6.png.meta b/docs/images/unity-mcp-ui-v8.6.png.meta new file mode 100644 index 000000000..84de8bea0 --- /dev/null +++ b/docs/images/unity-mcp-ui-v8.6.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: b0b7ce5355f1c89488d95bd4b4b63ccf +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v5_01_uninstall.png.meta b/docs/images/v5_01_uninstall.png.meta new file mode 100644 index 000000000..3aa4fb65d --- /dev/null +++ b/docs/images/v5_01_uninstall.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: ea8ffd0b8fa96c14694c9dcdb1e33377 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v5_02_install.png.meta b/docs/images/v5_02_install.png.meta new file mode 100644 index 000000000..3ad7e70f6 --- /dev/null +++ b/docs/images/v5_02_install.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 9294bbc548170684ab67156901372dfd +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v5_03_open_mcp_window.png.meta b/docs/images/v5_03_open_mcp_window.png.meta new file mode 100644 index 000000000..86b7527e2 --- /dev/null +++ b/docs/images/v5_03_open_mcp_window.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 8c959712b1238d042ba1f2d6ec441208 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v5_04_rebuild_mcp_server.png.meta b/docs/images/v5_04_rebuild_mcp_server.png.meta new file mode 100644 index 000000000..01dd0cea5 --- /dev/null +++ b/docs/images/v5_04_rebuild_mcp_server.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: f219139b6631eca4d8fc83b5c04ff2df +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v5_05_rebuild_success.png.meta b/docs/images/v5_05_rebuild_success.png.meta new file mode 100644 index 000000000..b58930dbe --- /dev/null +++ b/docs/images/v5_05_rebuild_success.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: a5305ff7d7f39384ebf07cb98f994b94 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v6_2_create_python_tools_asset.png.meta b/docs/images/v6_2_create_python_tools_asset.png.meta new file mode 100644 index 000000000..9f5c985b9 --- /dev/null +++ b/docs/images/v6_2_create_python_tools_asset.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: aa5fd3e2722995e4d9ea55b5db8c3056 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v6_2_python_tools_asset.png.meta b/docs/images/v6_2_python_tools_asset.png.meta new file mode 100644 index 000000000..85e3c8ecb --- /dev/null +++ b/docs/images/v6_2_python_tools_asset.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 4053eeb0a34f11e4e9165d85598afe93 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v6_new_ui_asset_store_version.png.meta b/docs/images/v6_new_ui_asset_store_version.png.meta new file mode 100644 index 000000000..8b21e22f7 --- /dev/null +++ b/docs/images/v6_new_ui_asset_store_version.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 2d2b6c4eb29d0e346a126f58d2633366 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v6_new_ui_dark.png.meta b/docs/images/v6_new_ui_dark.png.meta new file mode 100644 index 000000000..049ce4b89 --- /dev/null +++ b/docs/images/v6_new_ui_dark.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: d8f160ed1e5569e4ab56ae71be2dd951 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/images/v6_new_ui_light.png.meta b/docs/images/v6_new_ui_light.png.meta new file mode 100644 index 000000000..e8114911f --- /dev/null +++ b/docs/images/v6_new_ui_light.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 6f7fa20b90de51b4e9832b379a240570 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/v5_MIGRATION.md.meta b/docs/v5_MIGRATION.md.meta new file mode 100644 index 000000000..abff3af45 --- /dev/null +++ b/docs/v5_MIGRATION.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 68f0682d75bb6bd40927ad43889a1317 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/v6_NEW_UI_CHANGES.md.meta b/docs/v6_NEW_UI_CHANGES.md.meta new file mode 100644 index 000000000..ce7b2f51a --- /dev/null +++ b/docs/v6_NEW_UI_CHANGES.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9bf383542a284b943923ff0861c15dc8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/v8_NEW_NETWORKING_SETUP.md.meta b/docs/v8_NEW_NETWORKING_SETUP.md.meta new file mode 100644 index 000000000..ecd2fd798 --- /dev/null +++ b/docs/v8_NEW_NETWORKING_SETUP.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f26e6570e81ca604aa82678cb7847504 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/mcp_source.py.meta b/mcp_source.py.meta new file mode 100644 index 000000000..b40d68766 --- /dev/null +++ b/mcp_source.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5effdbbfab676ca448dba87a904d1b60 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/prune_tool_results.py.meta b/prune_tool_results.py.meta new file mode 100644 index 000000000..96e41dc6b --- /dev/null +++ b/prune_tool_results.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7a1782aa87883b74ab0373cfa5be7b13 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/restore-dev.bat.meta b/restore-dev.bat.meta new file mode 100644 index 000000000..fb92f8649 --- /dev/null +++ b/restore-dev.bat.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 56859f68ea72ff54b8a2c93ef9f86c4b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/scripts.meta b/scripts.meta new file mode 100644 index 000000000..be553cd25 --- /dev/null +++ b/scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2d56e020953f5494895fbccbb042f031 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/scripts/validate-nlt-coverage.sh.meta b/scripts/validate-nlt-coverage.sh.meta new file mode 100644 index 000000000..bc82394e8 --- /dev/null +++ b/scripts/validate-nlt-coverage.sh.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 772111267bbc4634c9e609ec2c3ef8c3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/test_unity_socket_framing.py.meta b/test_unity_socket_framing.py.meta new file mode 100644 index 000000000..e9e589533 --- /dev/null +++ b/test_unity_socket_framing.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 63b84137149ce644eac635fbb95798f0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools.meta b/tools.meta new file mode 100644 index 000000000..5614312fe --- /dev/null +++ b/tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bacbaf659b7efdc44bc44ff0dfc108b0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools/prepare_unity_asset_store_release.py.meta b/tools/prepare_unity_asset_store_release.py.meta new file mode 100644 index 000000000..45108bee4 --- /dev/null +++ b/tools/prepare_unity_asset_store_release.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bd846af6127c76748a48cceb93abeee1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools/stress_mcp.py.meta b/tools/stress_mcp.py.meta new file mode 100644 index 000000000..9a0e1b770 --- /dev/null +++ b/tools/stress_mcp.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ff2b29403cc241f4cb1d185fb738d51f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From bf4147929c681db8a5c7ed5018c4fa339eaaccf0 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Sun, 11 Jan 2026 23:48:18 +0800 Subject: [PATCH 06/23] fix: improve error handling in PathResolverService by logging exceptions --- MCPForUnity/Editor/Services/PathResolverService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index 29366969c..f678afe6a 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -69,9 +69,9 @@ private static string ResolveUvxFromSystem() } } } - catch + catch (Exception ex) { - // fall back to bare command + McpLog.Debug($"PathResolver error: {ex.Message}"); } return null; From f39857c0b0cad3e1892c9ec4fb1e72ffc8bd2427 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 00:10:14 +0800 Subject: [PATCH 07/23] Remove .meta files added after fork and update .gitignore --- .gitignore | 4 + CustomTools.meta | 8 -- CustomTools/RoslynRuntimeCompilation.meta | 8 -- MCPForUnity.meta | 8 -- README-zh.md.meta | 7 - README.md.meta | 7 - Server.meta | 8 -- Server/DOCKER_OVERVIEW.md.meta | 7 - Server/Dockerfile.meta | 7 - Server/README.md.meta | 7 - Server/__init__.py.meta | 7 - Server/pyproject.toml.meta | 7 - Server/pyrightconfig.json.meta | 7 - Server/src.meta | 8 -- Server/src/__init__.py.meta | 7 - Server/src/core.meta | 8 -- Server/src/core/__init__.py.meta | 7 - Server/src/core/config.py.meta | 7 - Server/src/core/logging_decorator.py.meta | 7 - Server/src/core/telemetry.py.meta | 7 - Server/src/core/telemetry_decorator.py.meta | 7 - Server/src/main.py.meta | 7 - Server/src/mcpforunityserver.egg-info.meta | 8 -- Server/src/models.meta | 8 -- Server/src/models/__init__.py.meta | 7 - Server/src/models/models.py.meta | 7 - Server/src/models/unity_response.py.meta | 7 - Server/src/services.meta | 8 -- Server/src/services/__init__.py.meta | 7 - .../src/services/custom_tool_service.py.meta | 7 - Server/src/services/registry.meta | 8 -- Server/src/services/registry/__init__.py.meta | 7 - .../registry/resource_registry.py.meta | 7 - .../services/registry/tool_registry.py.meta | 7 - Server/src/services/resources.meta | 8 -- .../src/services/resources/__init__.py.meta | 7 - .../services/resources/active_tool.py.meta | 7 - .../services/resources/custom_tools.py.meta | 7 - .../services/resources/editor_state.py.meta | 7 - .../src/services/resources/gameobject.py.meta | 7 - Server/src/services/resources/layers.py.meta | 7 - .../src/services/resources/menu_items.py.meta | 7 - .../services/resources/prefab_stage.py.meta | 7 - .../services/resources/project_info.py.meta | 7 - .../src/services/resources/selection.py.meta | 7 - Server/src/services/resources/tags.py.meta | 7 - Server/src/services/resources/tests.py.meta | 7 - .../resources/unity_instances.py.meta | 7 - Server/src/services/resources/windows.py.meta | 7 - Server/src/services/state.meta | 8 -- .../state/external_changes_scanner.py.meta | 7 - Server/src/services/tools.meta | 8 -- Server/src/services/tools/__init__.py.meta | 7 - .../src/services/tools/batch_execute.py.meta | 7 - .../tools/debug_request_context.py.meta | 7 - .../tools/execute_custom_tool.py.meta | 7 - .../services/tools/execute_menu_item.py.meta | 7 - .../services/tools/find_gameobjects.py.meta | 7 - .../src/services/tools/find_in_file.py.meta | 7 - .../src/services/tools/manage_asset.py.meta | 7 - .../services/tools/manage_components.py.meta | 7 - .../src/services/tools/manage_editor.py.meta | 7 - .../services/tools/manage_gameobject.py.meta | 7 - .../services/tools/manage_material.py.meta | 7 - .../src/services/tools/manage_prefabs.py.meta | 7 - .../src/services/tools/manage_scene.py.meta | 7 - .../src/services/tools/manage_script.py.meta | 7 - .../tools/manage_scriptable_object.py.meta | 7 - .../src/services/tools/manage_shader.py.meta | 7 - Server/src/services/tools/manage_vfx.py.meta | 7 - Server/src/services/tools/preflight.py.meta | 7 - .../src/services/tools/read_console.py.meta | 7 - .../src/services/tools/refresh_unity.py.meta | 7 - Server/src/services/tools/run_tests.py.meta | 7 - .../services/tools/script_apply_edits.py.meta | 7 - .../tools/set_active_instance.py.meta | 7 - Server/src/services/tools/utils.py.meta | 7 - Server/src/transport.meta | 8 -- Server/src/transport/__init__.py.meta | 7 - Server/src/transport/legacy.meta | 8 -- .../transport/legacy/port_discovery.py.meta | 7 - .../legacy/stdio_port_registry.py.meta | 7 - .../transport/legacy/unity_connection.py.meta | 7 - Server/src/transport/models.py.meta | 7 - Server/src/transport/plugin_hub.py.meta | 7 - Server/src/transport/plugin_registry.py.meta | 7 - .../unity_instance_middleware.py.meta | 7 - Server/src/transport/unity_transport.py.meta | 7 - Server/src/utils.meta | 8 -- Server/src/utils/module_discovery.py.meta | 7 - Server/src/utils/reload_sentinel.py.meta | 7 - Server/tests.meta | 8 -- Server/tests/__init__.py.meta | 7 - Server/tests/integration.meta | 8 -- Server/tests/integration/__init__.py.meta | 7 - Server/tests/integration/conftest.py.meta | 7 - ..._debug_request_context_diagnostics.py.meta | 7 - .../test_domain_reload_resilience.py.meta | 7 - .../test_edit_normalization_and_noop.py.meta | 7 - .../test_edit_strict_and_warnings.py.meta | 7 - .../test_editor_state_v2_contract.py.meta | 7 - .../test_external_changes_scanner.py.meta | 7 - .../integration/test_find_gameobjects.py.meta | 7 - .../test_find_in_file_minimal.py.meta | 7 - .../test_gameobject_resources.py.meta | 7 - Server/tests/integration/test_get_sha.py.meta | 7 - Server/tests/integration/test_helpers.py.meta | 7 - .../test_improved_anchor_matching.py.meta | 7 - .../test_instance_autoselect.py.meta | 7 - ...est_instance_routing_comprehensive.py.meta | 7 - ...test_instance_targeting_resolution.py.meta | 7 - .../test_json_parsing_simple.py.meta | 7 - .../integration/test_logging_stdout.py.meta | 7 - .../test_manage_asset_json_parsing.py.meta | 7 - .../test_manage_asset_param_coercion.py.meta | 7 - .../test_manage_components.py.meta | 7 - ...t_manage_gameobject_param_coercion.py.meta | 7 - .../test_manage_scene_paging_params.py.meta | 7 - .../test_manage_script_uri.py.meta | 7 - ...test_manage_scriptable_object_tool.py.meta | 7 - .../test_read_console_truncate.py.meta | 7 - .../test_read_resource_minimal.py.meta | 7 - .../test_refresh_unity_registration.py.meta | 7 - .../test_refresh_unity_retry_recovery.py.meta | 7 - .../integration/test_resources_api.py.meta | 7 - .../integration/test_run_tests_async.py.meta | 7 - .../integration/test_script_editing.py.meta | 7 - .../integration/test_script_tools.py.meta | 7 - ...test_telemetry_endpoint_validation.py.meta | 7 - .../test_telemetry_queue_worker.py.meta | 7 - .../test_telemetry_subaction.py.meta | 7 - .../test_tool_signatures_paging.py.meta | 7 - .../test_transport_framing.py.meta | 7 - .../test_validate_script_summary.py.meta | 7 - Server/tests/pytest.ini.meta | 7 - Server/uv.lock.meta | 7 - TestProjects.meta | 8 -- TestProjects/AssetStoreUploads.meta | 8 -- TestProjects/AssetStoreUploads/Assets.meta | 8 -- TestProjects/AssetStoreUploads/Packages.meta | 8 -- .../Packages/com.unity.asset-store-tools.meta | 8 -- .../Packages/manifest.json.meta | 7 - .../Packages/packages-lock.json.meta | 7 - .../AssetStoreUploads/ProjectSettings.meta | 8 -- ...rstAotSettings_StandaloneWindows.json.meta | 7 - .../CommonBurstAotSettings.json.meta | 7 - .../ProjectSettings/ProjectVersion.txt.meta | 7 - .../SceneTemplateSettings.json.meta | 7 - TestProjects/UnityMCPTests.meta | 8 -- TestProjects/UnityMCPTests/Assets.meta | 8 -- TestProjects/UnityMCPTests/Packages.meta | 8 -- .../UnityMCPTests/Packages/manifest.json.meta | 7 - .../UnityMCPTests/ProjectSettings.meta | 8 -- .../ProjectSettings/Packages.meta | 8 -- .../com.unity.testtools.codecoverage.meta | 8 -- .../Settings.json.meta | 7 - .../ProjectSettings/ProjectVersion.txt.meta | 7 - .../SceneTemplateSettings.json.meta | 7 - claude_skill_unity.zip.meta | 7 - deploy-dev.bat.meta | 7 - docker-compose.yml.meta | 7 - docs.meta | 8 -- docs/CURSOR_HELP.md.meta | 7 - docs/CUSTOM_TOOLS.md.meta | 7 - docs/MCP_CLIENT_CONFIGURATORS.md.meta | 7 - docs/README-DEV-zh.md.meta | 7 - docs/README-DEV.md.meta | 7 - docs/TELEMETRY.md.meta | 7 - docs/images.meta | 8 -- docs/images/advanced-setting.png.meta | 127 ------------------ docs/images/building_scene.gif.meta | 127 ------------------ docs/images/coplay-logo.png.meta | 127 ------------------ docs/images/logo.png.meta | 127 ------------------ docs/images/networking-architecture.png.meta | 127 ------------------ docs/images/readme_ui.png.meta | 127 ------------------ docs/images/unity-mcp-ui-v8.6.png.meta | 127 ------------------ docs/images/v5_01_uninstall.png.meta | 127 ------------------ docs/images/v5_02_install.png.meta | 127 ------------------ docs/images/v5_03_open_mcp_window.png.meta | 127 ------------------ docs/images/v5_04_rebuild_mcp_server.png.meta | 127 ------------------ docs/images/v5_05_rebuild_success.png.meta | 127 ------------------ .../v6_2_create_python_tools_asset.png.meta | 127 ------------------ docs/images/v6_2_python_tools_asset.png.meta | 127 ------------------ .../v6_new_ui_asset_store_version.png.meta | 127 ------------------ docs/images/v6_new_ui_dark.png.meta | 127 ------------------ docs/images/v6_new_ui_light.png.meta | 127 ------------------ docs/v5_MIGRATION.md.meta | 7 - docs/v6_NEW_UI_CHANGES.md.meta | 7 - docs/v8_NEW_NETWORKING_SETUP.md.meta | 7 - mcp_source.py.meta | 7 - prune_tool_results.py.meta | 7 - restore-dev.bat.meta | 7 - scripts.meta | 8 -- scripts/validate-nlt-coverage.sh.meta | 7 - test_unity_socket_framing.py.meta | 7 - tools.meta | 8 -- .../prepare_unity_asset_store_release.py.meta | 7 - tools/stress_mcp.py.meta | 7 - 198 files changed, 4 insertions(+), 3453 deletions(-) delete mode 100644 CustomTools.meta delete mode 100644 CustomTools/RoslynRuntimeCompilation.meta delete mode 100644 MCPForUnity.meta delete mode 100644 README-zh.md.meta delete mode 100644 README.md.meta delete mode 100644 Server.meta delete mode 100644 Server/DOCKER_OVERVIEW.md.meta delete mode 100644 Server/Dockerfile.meta delete mode 100644 Server/README.md.meta delete mode 100644 Server/__init__.py.meta delete mode 100644 Server/pyproject.toml.meta delete mode 100644 Server/pyrightconfig.json.meta delete mode 100644 Server/src.meta delete mode 100644 Server/src/__init__.py.meta delete mode 100644 Server/src/core.meta delete mode 100644 Server/src/core/__init__.py.meta delete mode 100644 Server/src/core/config.py.meta delete mode 100644 Server/src/core/logging_decorator.py.meta delete mode 100644 Server/src/core/telemetry.py.meta delete mode 100644 Server/src/core/telemetry_decorator.py.meta delete mode 100644 Server/src/main.py.meta delete mode 100644 Server/src/mcpforunityserver.egg-info.meta delete mode 100644 Server/src/models.meta delete mode 100644 Server/src/models/__init__.py.meta delete mode 100644 Server/src/models/models.py.meta delete mode 100644 Server/src/models/unity_response.py.meta delete mode 100644 Server/src/services.meta delete mode 100644 Server/src/services/__init__.py.meta delete mode 100644 Server/src/services/custom_tool_service.py.meta delete mode 100644 Server/src/services/registry.meta delete mode 100644 Server/src/services/registry/__init__.py.meta delete mode 100644 Server/src/services/registry/resource_registry.py.meta delete mode 100644 Server/src/services/registry/tool_registry.py.meta delete mode 100644 Server/src/services/resources.meta delete mode 100644 Server/src/services/resources/__init__.py.meta delete mode 100644 Server/src/services/resources/active_tool.py.meta delete mode 100644 Server/src/services/resources/custom_tools.py.meta delete mode 100644 Server/src/services/resources/editor_state.py.meta delete mode 100644 Server/src/services/resources/gameobject.py.meta delete mode 100644 Server/src/services/resources/layers.py.meta delete mode 100644 Server/src/services/resources/menu_items.py.meta delete mode 100644 Server/src/services/resources/prefab_stage.py.meta delete mode 100644 Server/src/services/resources/project_info.py.meta delete mode 100644 Server/src/services/resources/selection.py.meta delete mode 100644 Server/src/services/resources/tags.py.meta delete mode 100644 Server/src/services/resources/tests.py.meta delete mode 100644 Server/src/services/resources/unity_instances.py.meta delete mode 100644 Server/src/services/resources/windows.py.meta delete mode 100644 Server/src/services/state.meta delete mode 100644 Server/src/services/state/external_changes_scanner.py.meta delete mode 100644 Server/src/services/tools.meta delete mode 100644 Server/src/services/tools/__init__.py.meta delete mode 100644 Server/src/services/tools/batch_execute.py.meta delete mode 100644 Server/src/services/tools/debug_request_context.py.meta delete mode 100644 Server/src/services/tools/execute_custom_tool.py.meta delete mode 100644 Server/src/services/tools/execute_menu_item.py.meta delete mode 100644 Server/src/services/tools/find_gameobjects.py.meta delete mode 100644 Server/src/services/tools/find_in_file.py.meta delete mode 100644 Server/src/services/tools/manage_asset.py.meta delete mode 100644 Server/src/services/tools/manage_components.py.meta delete mode 100644 Server/src/services/tools/manage_editor.py.meta delete mode 100644 Server/src/services/tools/manage_gameobject.py.meta delete mode 100644 Server/src/services/tools/manage_material.py.meta delete mode 100644 Server/src/services/tools/manage_prefabs.py.meta delete mode 100644 Server/src/services/tools/manage_scene.py.meta delete mode 100644 Server/src/services/tools/manage_script.py.meta delete mode 100644 Server/src/services/tools/manage_scriptable_object.py.meta delete mode 100644 Server/src/services/tools/manage_shader.py.meta delete mode 100644 Server/src/services/tools/manage_vfx.py.meta delete mode 100644 Server/src/services/tools/preflight.py.meta delete mode 100644 Server/src/services/tools/read_console.py.meta delete mode 100644 Server/src/services/tools/refresh_unity.py.meta delete mode 100644 Server/src/services/tools/run_tests.py.meta delete mode 100644 Server/src/services/tools/script_apply_edits.py.meta delete mode 100644 Server/src/services/tools/set_active_instance.py.meta delete mode 100644 Server/src/services/tools/utils.py.meta delete mode 100644 Server/src/transport.meta delete mode 100644 Server/src/transport/__init__.py.meta delete mode 100644 Server/src/transport/legacy.meta delete mode 100644 Server/src/transport/legacy/port_discovery.py.meta delete mode 100644 Server/src/transport/legacy/stdio_port_registry.py.meta delete mode 100644 Server/src/transport/legacy/unity_connection.py.meta delete mode 100644 Server/src/transport/models.py.meta delete mode 100644 Server/src/transport/plugin_hub.py.meta delete mode 100644 Server/src/transport/plugin_registry.py.meta delete mode 100644 Server/src/transport/unity_instance_middleware.py.meta delete mode 100644 Server/src/transport/unity_transport.py.meta delete mode 100644 Server/src/utils.meta delete mode 100644 Server/src/utils/module_discovery.py.meta delete mode 100644 Server/src/utils/reload_sentinel.py.meta delete mode 100644 Server/tests.meta delete mode 100644 Server/tests/__init__.py.meta delete mode 100644 Server/tests/integration.meta delete mode 100644 Server/tests/integration/__init__.py.meta delete mode 100644 Server/tests/integration/conftest.py.meta delete mode 100644 Server/tests/integration/test_debug_request_context_diagnostics.py.meta delete mode 100644 Server/tests/integration/test_domain_reload_resilience.py.meta delete mode 100644 Server/tests/integration/test_edit_normalization_and_noop.py.meta delete mode 100644 Server/tests/integration/test_edit_strict_and_warnings.py.meta delete mode 100644 Server/tests/integration/test_editor_state_v2_contract.py.meta delete mode 100644 Server/tests/integration/test_external_changes_scanner.py.meta delete mode 100644 Server/tests/integration/test_find_gameobjects.py.meta delete mode 100644 Server/tests/integration/test_find_in_file_minimal.py.meta delete mode 100644 Server/tests/integration/test_gameobject_resources.py.meta delete mode 100644 Server/tests/integration/test_get_sha.py.meta delete mode 100644 Server/tests/integration/test_helpers.py.meta delete mode 100644 Server/tests/integration/test_improved_anchor_matching.py.meta delete mode 100644 Server/tests/integration/test_instance_autoselect.py.meta delete mode 100644 Server/tests/integration/test_instance_routing_comprehensive.py.meta delete mode 100644 Server/tests/integration/test_instance_targeting_resolution.py.meta delete mode 100644 Server/tests/integration/test_json_parsing_simple.py.meta delete mode 100644 Server/tests/integration/test_logging_stdout.py.meta delete mode 100644 Server/tests/integration/test_manage_asset_json_parsing.py.meta delete mode 100644 Server/tests/integration/test_manage_asset_param_coercion.py.meta delete mode 100644 Server/tests/integration/test_manage_components.py.meta delete mode 100644 Server/tests/integration/test_manage_gameobject_param_coercion.py.meta delete mode 100644 Server/tests/integration/test_manage_scene_paging_params.py.meta delete mode 100644 Server/tests/integration/test_manage_script_uri.py.meta delete mode 100644 Server/tests/integration/test_manage_scriptable_object_tool.py.meta delete mode 100644 Server/tests/integration/test_read_console_truncate.py.meta delete mode 100644 Server/tests/integration/test_read_resource_minimal.py.meta delete mode 100644 Server/tests/integration/test_refresh_unity_registration.py.meta delete mode 100644 Server/tests/integration/test_refresh_unity_retry_recovery.py.meta delete mode 100644 Server/tests/integration/test_resources_api.py.meta delete mode 100644 Server/tests/integration/test_run_tests_async.py.meta delete mode 100644 Server/tests/integration/test_script_editing.py.meta delete mode 100644 Server/tests/integration/test_script_tools.py.meta delete mode 100644 Server/tests/integration/test_telemetry_endpoint_validation.py.meta delete mode 100644 Server/tests/integration/test_telemetry_queue_worker.py.meta delete mode 100644 Server/tests/integration/test_telemetry_subaction.py.meta delete mode 100644 Server/tests/integration/test_tool_signatures_paging.py.meta delete mode 100644 Server/tests/integration/test_transport_framing.py.meta delete mode 100644 Server/tests/integration/test_validate_script_summary.py.meta delete mode 100644 Server/tests/pytest.ini.meta delete mode 100644 Server/uv.lock.meta delete mode 100644 TestProjects.meta delete mode 100644 TestProjects/AssetStoreUploads.meta delete mode 100644 TestProjects/AssetStoreUploads/Assets.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/manifest.json.meta delete mode 100644 TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta delete mode 100644 TestProjects/AssetStoreUploads/ProjectSettings.meta delete mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta delete mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta delete mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta delete mode 100644 TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta delete mode 100644 TestProjects/UnityMCPTests.meta delete mode 100644 TestProjects/UnityMCPTests/Assets.meta delete mode 100644 TestProjects/UnityMCPTests/Packages.meta delete mode 100644 TestProjects/UnityMCPTests/Packages/manifest.json.meta delete mode 100644 TestProjects/UnityMCPTests/ProjectSettings.meta delete mode 100644 TestProjects/UnityMCPTests/ProjectSettings/Packages.meta delete mode 100644 TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta delete mode 100644 TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta delete mode 100644 TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta delete mode 100644 TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta delete mode 100644 claude_skill_unity.zip.meta delete mode 100644 deploy-dev.bat.meta delete mode 100644 docker-compose.yml.meta delete mode 100644 docs.meta delete mode 100644 docs/CURSOR_HELP.md.meta delete mode 100644 docs/CUSTOM_TOOLS.md.meta delete mode 100644 docs/MCP_CLIENT_CONFIGURATORS.md.meta delete mode 100644 docs/README-DEV-zh.md.meta delete mode 100644 docs/README-DEV.md.meta delete mode 100644 docs/TELEMETRY.md.meta delete mode 100644 docs/images.meta delete mode 100644 docs/images/advanced-setting.png.meta delete mode 100644 docs/images/building_scene.gif.meta delete mode 100644 docs/images/coplay-logo.png.meta delete mode 100644 docs/images/logo.png.meta delete mode 100644 docs/images/networking-architecture.png.meta delete mode 100644 docs/images/readme_ui.png.meta delete mode 100644 docs/images/unity-mcp-ui-v8.6.png.meta delete mode 100644 docs/images/v5_01_uninstall.png.meta delete mode 100644 docs/images/v5_02_install.png.meta delete mode 100644 docs/images/v5_03_open_mcp_window.png.meta delete mode 100644 docs/images/v5_04_rebuild_mcp_server.png.meta delete mode 100644 docs/images/v5_05_rebuild_success.png.meta delete mode 100644 docs/images/v6_2_create_python_tools_asset.png.meta delete mode 100644 docs/images/v6_2_python_tools_asset.png.meta delete mode 100644 docs/images/v6_new_ui_asset_store_version.png.meta delete mode 100644 docs/images/v6_new_ui_dark.png.meta delete mode 100644 docs/images/v6_new_ui_light.png.meta delete mode 100644 docs/v5_MIGRATION.md.meta delete mode 100644 docs/v6_NEW_UI_CHANGES.md.meta delete mode 100644 docs/v8_NEW_NETWORKING_SETUP.md.meta delete mode 100644 mcp_source.py.meta delete mode 100644 prune_tool_results.py.meta delete mode 100644 restore-dev.bat.meta delete mode 100644 scripts.meta delete mode 100644 scripts/validate-nlt-coverage.sh.meta delete mode 100644 test_unity_socket_framing.py.meta delete mode 100644 tools.meta delete mode 100644 tools/prepare_unity_asset_store_release.py.meta delete mode 100644 tools/stress_mcp.py.meta diff --git a/.gitignore b/.gitignore index 1ffda95f9..abb4d8b4c 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,7 @@ reports/ # Local testing harness scripts/local-test/ + +*.meta + +**/*.meta \ No newline at end of file diff --git a/CustomTools.meta b/CustomTools.meta deleted file mode 100644 index 15c0e2e9b..000000000 --- a/CustomTools.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 77119eb495f8bd34e97e027dfc10164d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/CustomTools/RoslynRuntimeCompilation.meta b/CustomTools/RoslynRuntimeCompilation.meta deleted file mode 100644 index ec3ccf2fb..000000000 --- a/CustomTools/RoslynRuntimeCompilation.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cb28c23ce26c4954f90a988b0fb8232b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/MCPForUnity.meta b/MCPForUnity.meta deleted file mode 100644 index b8bba153d..000000000 --- a/MCPForUnity.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0d2e5a49aaf8cd2429de11605995a74c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/README-zh.md.meta b/README-zh.md.meta deleted file mode 100644 index b241e048c..000000000 --- a/README-zh.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7ee419ac1dd966449a6635af11188445 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/README.md.meta b/README.md.meta deleted file mode 100644 index 2f71f10f1..000000000 --- a/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 22e770f7b5882c7479bb7133120bb971 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server.meta b/Server.meta deleted file mode 100644 index 4ef920302..000000000 --- a/Server.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b2b012d14c198e44eadc8c28c0da7876 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/DOCKER_OVERVIEW.md.meta b/Server/DOCKER_OVERVIEW.md.meta deleted file mode 100644 index 51c82b455..000000000 --- a/Server/DOCKER_OVERVIEW.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e637ae94b7783074c88738e9ea38718e -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/Dockerfile.meta b/Server/Dockerfile.meta deleted file mode 100644 index a07b294e8..000000000 --- a/Server/Dockerfile.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 98f232acd1be4c946a388d944ad87837 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/README.md.meta b/Server/README.md.meta deleted file mode 100644 index 8fa4bea66..000000000 --- a/Server/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f99295e86aef46742aa4541dfe8c5ada -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/__init__.py.meta b/Server/__init__.py.meta deleted file mode 100644 index 1b420dac5..000000000 --- a/Server/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 40efb7c3491369146b26c222d4258279 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/pyproject.toml.meta b/Server/pyproject.toml.meta deleted file mode 100644 index 23c3844ff..000000000 --- a/Server/pyproject.toml.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5249476a602f62c4cb465c78e769e119 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/pyrightconfig.json.meta b/Server/pyrightconfig.json.meta deleted file mode 100644 index 58d63b728..000000000 --- a/Server/pyrightconfig.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ec742965bbe2dd44f804c59dd84407fa -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src.meta b/Server/src.meta deleted file mode 100644 index bf2e8f313..000000000 --- a/Server/src.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f464e790de0083e478e2e7ab904aaac5 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/__init__.py.meta b/Server/src/__init__.py.meta deleted file mode 100644 index 34adddab3..000000000 --- a/Server/src/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 81ea0272634405542845ab080758c08b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/core.meta b/Server/src/core.meta deleted file mode 100644 index 4729e3cd2..000000000 --- a/Server/src/core.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 39bff2dd227e914418cca82e651e70e5 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/core/__init__.py.meta b/Server/src/core/__init__.py.meta deleted file mode 100644 index 6d5fda274..000000000 --- a/Server/src/core/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ae450420d0f9de74fa3dbf4199439547 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/core/config.py.meta b/Server/src/core/config.py.meta deleted file mode 100644 index 76b222c3c..000000000 --- a/Server/src/core/config.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0e33e98914fc1ca469e53306b1d37e1c -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/core/logging_decorator.py.meta b/Server/src/core/logging_decorator.py.meta deleted file mode 100644 index d551facc8..000000000 --- a/Server/src/core/logging_decorator.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e993bbd747b756848914704f3ae59a49 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/core/telemetry.py.meta b/Server/src/core/telemetry.py.meta deleted file mode 100644 index 3217b73fb..000000000 --- a/Server/src/core/telemetry.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 82c021e32497c9242830656e7f294f93 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/core/telemetry_decorator.py.meta b/Server/src/core/telemetry_decorator.py.meta deleted file mode 100644 index a7f1a1cb2..000000000 --- a/Server/src/core/telemetry_decorator.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0eef8a1c20884e642b1b9c0041d7a9ed -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/main.py.meta b/Server/src/main.py.meta deleted file mode 100644 index 395393ee7..000000000 --- a/Server/src/main.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b50f9566865be6242a1f919d8d82309f -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/mcpforunityserver.egg-info.meta b/Server/src/mcpforunityserver.egg-info.meta deleted file mode 100644 index c84ef947b..000000000 --- a/Server/src/mcpforunityserver.egg-info.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0d06746de9afd6a44b595a7ec18d4884 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/models.meta b/Server/src/models.meta deleted file mode 100644 index 61496e8d8..000000000 --- a/Server/src/models.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bcd618313eb241d47b7f2501e49bbe90 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/models/__init__.py.meta b/Server/src/models/__init__.py.meta deleted file mode 100644 index bafd6cff4..000000000 --- a/Server/src/models/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 78d969287a07afa46baa8cc15b6c38f4 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/models/models.py.meta b/Server/src/models/models.py.meta deleted file mode 100644 index 7dbecefc8..000000000 --- a/Server/src/models/models.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: af569acc9ee99ef46b187b6bbda568cf -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/models/unity_response.py.meta b/Server/src/models/unity_response.py.meta deleted file mode 100644 index b0660c6c3..000000000 --- a/Server/src/models/unity_response.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 9a1e7f68f806ef743be1b8113df9f1c6 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services.meta b/Server/src/services.meta deleted file mode 100644 index d58561093..000000000 --- a/Server/src/services.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cef3c50d7527f8643ae9c4bfacccdea8 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/__init__.py.meta b/Server/src/services/__init__.py.meta deleted file mode 100644 index 74bd0b38e..000000000 --- a/Server/src/services/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5bb0bfd5f53931b42af61b1bcf5ed0a4 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/custom_tool_service.py.meta b/Server/src/services/custom_tool_service.py.meta deleted file mode 100644 index c5fb64a90..000000000 --- a/Server/src/services/custom_tool_service.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a92813394c110014cba4b99609ea2671 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/registry.meta b/Server/src/services/registry.meta deleted file mode 100644 index 365dbabbe..000000000 --- a/Server/src/services/registry.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ce0efc970a25f5d46bb04a4def011c28 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/registry/__init__.py.meta b/Server/src/services/registry/__init__.py.meta deleted file mode 100644 index beddce3f0..000000000 --- a/Server/src/services/registry/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: dbb9c43a38438654fa75186177f9ca8c -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/registry/resource_registry.py.meta b/Server/src/services/registry/resource_registry.py.meta deleted file mode 100644 index b8f44100b..000000000 --- a/Server/src/services/registry/resource_registry.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 65579c33e0d1da3448dd3d21098ff052 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/registry/tool_registry.py.meta b/Server/src/services/registry/tool_registry.py.meta deleted file mode 100644 index 905a0470c..000000000 --- a/Server/src/services/registry/tool_registry.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 2665f8971919fc249aaa72b5abb22271 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources.meta b/Server/src/services/resources.meta deleted file mode 100644 index 7433decf3..000000000 --- a/Server/src/services/resources.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 41122f17012fb11489adacfe3727b21f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/__init__.py.meta b/Server/src/services/resources/__init__.py.meta deleted file mode 100644 index 17821ce5f..000000000 --- a/Server/src/services/resources/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: cac7644223502944ca6e77405f582169 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/active_tool.py.meta b/Server/src/services/resources/active_tool.py.meta deleted file mode 100644 index e3d359881..000000000 --- a/Server/src/services/resources/active_tool.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 2ae46c9c998c6b3468c29a6fd1374379 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/custom_tools.py.meta b/Server/src/services/resources/custom_tools.py.meta deleted file mode 100644 index 244229647..000000000 --- a/Server/src/services/resources/custom_tools.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: efaee24cbd6df8a498fa43fcd8ebbb69 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/editor_state.py.meta b/Server/src/services/resources/editor_state.py.meta deleted file mode 100644 index b607e171d..000000000 --- a/Server/src/services/resources/editor_state.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 34ff3e20c32932c4aa62d88e59e5f75f -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/gameobject.py.meta b/Server/src/services/resources/gameobject.py.meta deleted file mode 100644 index abaa2cf4e..000000000 --- a/Server/src/services/resources/gameobject.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: d2352c5730ed24944a93c279fc80f16b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/layers.py.meta b/Server/src/services/resources/layers.py.meta deleted file mode 100644 index 1b1885b40..000000000 --- a/Server/src/services/resources/layers.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0c176e1a999897342a46284ac65245fd -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/menu_items.py.meta b/Server/src/services/resources/menu_items.py.meta deleted file mode 100644 index 5a342daef..000000000 --- a/Server/src/services/resources/menu_items.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: cfb45e8d081d768429671db7f4fbbc30 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/prefab_stage.py.meta b/Server/src/services/resources/prefab_stage.py.meta deleted file mode 100644 index 2f81a461a..000000000 --- a/Server/src/services/resources/prefab_stage.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 94254ab181839034d8f4349a613ba862 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/project_info.py.meta b/Server/src/services/resources/project_info.py.meta deleted file mode 100644 index 8a748d049..000000000 --- a/Server/src/services/resources/project_info.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5326951abe940934c926ac4c3bbe34a1 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/selection.py.meta b/Server/src/services/resources/selection.py.meta deleted file mode 100644 index fa437cc8a..000000000 --- a/Server/src/services/resources/selection.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 962c6804fb29c5c429bf19476fdb2f20 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/tags.py.meta b/Server/src/services/resources/tags.py.meta deleted file mode 100644 index 95fc38389..000000000 --- a/Server/src/services/resources/tags.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b92b14d6764ccb0478555d42fea6d9d8 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/tests.py.meta b/Server/src/services/resources/tests.py.meta deleted file mode 100644 index 0ec6dba03..000000000 --- a/Server/src/services/resources/tests.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 97fa5345ee85e2640a7b8c8ed2f98b90 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/unity_instances.py.meta b/Server/src/services/resources/unity_instances.py.meta deleted file mode 100644 index e3cfda465..000000000 --- a/Server/src/services/resources/unity_instances.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0eb71ea954cbc14429ca78a4ac88ac14 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/resources/windows.py.meta b/Server/src/services/resources/windows.py.meta deleted file mode 100644 index 6a593ec01..000000000 --- a/Server/src/services/resources/windows.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8ddacca6a44d2d449bdf46fcf93adba4 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/state.meta b/Server/src/services/state.meta deleted file mode 100644 index 7e07e4c2c..000000000 --- a/Server/src/services/state.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f52ba560b50b2274aac05efcb9f1433a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/state/external_changes_scanner.py.meta b/Server/src/services/state/external_changes_scanner.py.meta deleted file mode 100644 index 77c562b31..000000000 --- a/Server/src/services/state/external_changes_scanner.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 222c99256eece3640ad06890823e6e07 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools.meta b/Server/src/services/tools.meta deleted file mode 100644 index f1f2328e2..000000000 --- a/Server/src/services/tools.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 44c48e9900d70404ebce0437f7f0e72f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/__init__.py.meta b/Server/src/services/tools/__init__.py.meta deleted file mode 100644 index a520c9687..000000000 --- a/Server/src/services/tools/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c5f53f694b279dd48911be214b48fe09 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/batch_execute.py.meta b/Server/src/services/tools/batch_execute.py.meta deleted file mode 100644 index bb1ce6b53..000000000 --- a/Server/src/services/tools/batch_execute.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: caffd99bf73e1754eba84830c7403f0b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/debug_request_context.py.meta b/Server/src/services/tools/debug_request_context.py.meta deleted file mode 100644 index 1208a0da3..000000000 --- a/Server/src/services/tools/debug_request_context.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f06210583487df04cab73e4947070bf5 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/execute_custom_tool.py.meta b/Server/src/services/tools/execute_custom_tool.py.meta deleted file mode 100644 index 22b20302f..000000000 --- a/Server/src/services/tools/execute_custom_tool.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 66101c93c5808ad4b84976a85245db8d -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/execute_menu_item.py.meta b/Server/src/services/tools/execute_menu_item.py.meta deleted file mode 100644 index 9eae8a841..000000000 --- a/Server/src/services/tools/execute_menu_item.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c1cbe79d893c18c41b90638e0e46339c -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/find_gameobjects.py.meta b/Server/src/services/tools/find_gameobjects.py.meta deleted file mode 100644 index 332ee699a..000000000 --- a/Server/src/services/tools/find_gameobjects.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b7d875dec66df784399a76ab510897cd -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/find_in_file.py.meta b/Server/src/services/tools/find_in_file.py.meta deleted file mode 100644 index 1ee822e93..000000000 --- a/Server/src/services/tools/find_in_file.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 90171f31bffff4543a50e7cd4c181cbc -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_asset.py.meta b/Server/src/services/tools/manage_asset.py.meta deleted file mode 100644 index c7bc99e0f..000000000 --- a/Server/src/services/tools/manage_asset.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 67fcf75cf05591d45ae0bcd27e8aed93 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_components.py.meta b/Server/src/services/tools/manage_components.py.meta deleted file mode 100644 index e9f80ad0b..000000000 --- a/Server/src/services/tools/manage_components.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7bdf6eeed3b58c24db395639e621b105 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_editor.py.meta b/Server/src/services/tools/manage_editor.py.meta deleted file mode 100644 index 9dfce3496..000000000 --- a/Server/src/services/tools/manage_editor.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 437a1624dc11ba54d869a15022596a03 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_gameobject.py.meta b/Server/src/services/tools/manage_gameobject.py.meta deleted file mode 100644 index f24389b8a..000000000 --- a/Server/src/services/tools/manage_gameobject.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ffbf4b2d4792418499c871bca6d6ad26 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_material.py.meta b/Server/src/services/tools/manage_material.py.meta deleted file mode 100644 index 7fc3c0791..000000000 --- a/Server/src/services/tools/manage_material.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 688e38c2457ec794199ac56a40559b9b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_prefabs.py.meta b/Server/src/services/tools/manage_prefabs.py.meta deleted file mode 100644 index 682cd070e..000000000 --- a/Server/src/services/tools/manage_prefabs.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6e712e8aac9a8954191ed50dc3eb68b3 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_scene.py.meta b/Server/src/services/tools/manage_scene.py.meta deleted file mode 100644 index 73689c52d..000000000 --- a/Server/src/services/tools/manage_scene.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a3a132bde6db56744912f55f7b2a0e08 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_script.py.meta b/Server/src/services/tools/manage_script.py.meta deleted file mode 100644 index 44571ae25..000000000 --- a/Server/src/services/tools/manage_script.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1f104cddffd93f44998948be5031ce39 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_scriptable_object.py.meta b/Server/src/services/tools/manage_scriptable_object.py.meta deleted file mode 100644 index 254fad805..000000000 --- a/Server/src/services/tools/manage_scriptable_object.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 69b0baab1ac58aa49abf3ee2558eedec -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_shader.py.meta b/Server/src/services/tools/manage_shader.py.meta deleted file mode 100644 index e2f7b7861..000000000 --- a/Server/src/services/tools/manage_shader.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 40b4724d8510941499bf1987f443c4e8 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/manage_vfx.py.meta b/Server/src/services/tools/manage_vfx.py.meta deleted file mode 100644 index 98736cf66..000000000 --- a/Server/src/services/tools/manage_vfx.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 748c1b09d1d872c4a97ede6331d0ccdc -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/preflight.py.meta b/Server/src/services/tools/preflight.py.meta deleted file mode 100644 index 986baaf55..000000000 --- a/Server/src/services/tools/preflight.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6a21777f1dcb9054eb220139a7e3420a -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/read_console.py.meta b/Server/src/services/tools/read_console.py.meta deleted file mode 100644 index 1830520d3..000000000 --- a/Server/src/services/tools/read_console.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 76618a99018a8ea4d9e5882cf1774899 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/refresh_unity.py.meta b/Server/src/services/tools/refresh_unity.py.meta deleted file mode 100644 index b64a3d8e0..000000000 --- a/Server/src/services/tools/refresh_unity.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: dbc4e2e0bab39d049afc6c093dd297dd -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/run_tests.py.meta b/Server/src/services/tools/run_tests.py.meta deleted file mode 100644 index 68f32401e..000000000 --- a/Server/src/services/tools/run_tests.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e78e9cdaa4badd6479868fbd97b2d72c -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/script_apply_edits.py.meta b/Server/src/services/tools/script_apply_edits.py.meta deleted file mode 100644 index 7e2197826..000000000 --- a/Server/src/services/tools/script_apply_edits.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3c4276cd4c0c5654c863fbedbcd6e4e3 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/set_active_instance.py.meta b/Server/src/services/tools/set_active_instance.py.meta deleted file mode 100644 index 5c4d45043..000000000 --- a/Server/src/services/tools/set_active_instance.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: eebaeac441a02654c97ee4bc8b2a8d1b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/services/tools/utils.py.meta b/Server/src/services/tools/utils.py.meta deleted file mode 100644 index d0cd9cede..000000000 --- a/Server/src/services/tools/utils.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 89f5ae66560cf09488dd80c253841057 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport.meta b/Server/src/transport.meta deleted file mode 100644 index ed61c8f3c..000000000 --- a/Server/src/transport.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d9a5563aa3841d240871b6955fb97058 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/__init__.py.meta b/Server/src/transport/__init__.py.meta deleted file mode 100644 index d018b05b9..000000000 --- a/Server/src/transport/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b255dd0281768af4ba49f0fc3e8b2f3b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/legacy.meta b/Server/src/transport/legacy.meta deleted file mode 100644 index 172d6c8be..000000000 --- a/Server/src/transport/legacy.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7554a33516319ea49bc5e10d7a01cd16 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/legacy/port_discovery.py.meta b/Server/src/transport/legacy/port_discovery.py.meta deleted file mode 100644 index fb4ad4807..000000000 --- a/Server/src/transport/legacy/port_discovery.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 619465c600774b04887aebb480da38b7 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/legacy/stdio_port_registry.py.meta b/Server/src/transport/legacy/stdio_port_registry.py.meta deleted file mode 100644 index 157a23c2d..000000000 --- a/Server/src/transport/legacy/stdio_port_registry.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f14d54d79a0355440a7e5ac4cb91cb0c -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/legacy/unity_connection.py.meta b/Server/src/transport/legacy/unity_connection.py.meta deleted file mode 100644 index 4a2798f3f..000000000 --- a/Server/src/transport/legacy/unity_connection.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 936a855b9daafed4b93791f783dad48a -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/models.py.meta b/Server/src/transport/models.py.meta deleted file mode 100644 index 7acf62038..000000000 --- a/Server/src/transport/models.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 56f323ff419f1e94780c5f83ea72e363 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/plugin_hub.py.meta b/Server/src/transport/plugin_hub.py.meta deleted file mode 100644 index 6e2426c57..000000000 --- a/Server/src/transport/plugin_hub.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8191732cc50582c468404fc739bf3b2e -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/plugin_registry.py.meta b/Server/src/transport/plugin_registry.py.meta deleted file mode 100644 index e6d0e9f67..000000000 --- a/Server/src/transport/plugin_registry.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e6c350ac6176ee54badf5db9439c432a -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/unity_instance_middleware.py.meta b/Server/src/transport/unity_instance_middleware.py.meta deleted file mode 100644 index 4cf4e1fa3..000000000 --- a/Server/src/transport/unity_instance_middleware.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 456dec3abb618ea40ac4b35e396a587d -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/transport/unity_transport.py.meta b/Server/src/transport/unity_transport.py.meta deleted file mode 100644 index f76365a7f..000000000 --- a/Server/src/transport/unity_transport.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f086a5cbe1422a14981fe47c83d88670 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/utils.meta b/Server/src/utils.meta deleted file mode 100644 index f48731ac8..000000000 --- a/Server/src/utils.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5d6f5bca6b22bd3468dbb3f0235cee67 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/utils/module_discovery.py.meta b/Server/src/utils/module_discovery.py.meta deleted file mode 100644 index 84adff64e..000000000 --- a/Server/src/utils/module_discovery.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 652f3ab8d3c99c74298b87d588c02f02 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/src/utils/reload_sentinel.py.meta b/Server/src/utils/reload_sentinel.py.meta deleted file mode 100644 index 03eb0dc7c..000000000 --- a/Server/src/utils/reload_sentinel.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: d8d62316caa283041906a9c769c23554 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests.meta b/Server/tests.meta deleted file mode 100644 index 10b8d58b8..000000000 --- a/Server/tests.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 73f3440d5e14b104bb14b6ed5322fe9e -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/__init__.py.meta b/Server/tests/__init__.py.meta deleted file mode 100644 index 19d8e82c4..000000000 --- a/Server/tests/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b6a435683a37bfb4c98690b72607a152 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration.meta b/Server/tests/integration.meta deleted file mode 100644 index 6fb54249b..000000000 --- a/Server/tests/integration.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 72d784ed2e7184043a93da74377ecfe1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/__init__.py.meta b/Server/tests/integration/__init__.py.meta deleted file mode 100644 index 74551c93e..000000000 --- a/Server/tests/integration/__init__.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: fc17eda1077966d4d97aa133383f687d -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/conftest.py.meta b/Server/tests/integration/conftest.py.meta deleted file mode 100644 index 0b6144b8f..000000000 --- a/Server/tests/integration/conftest.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8ac762753744ad44ba9e1800bf3b39a6 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_debug_request_context_diagnostics.py.meta b/Server/tests/integration/test_debug_request_context_diagnostics.py.meta deleted file mode 100644 index 0da6e60a1..000000000 --- a/Server/tests/integration/test_debug_request_context_diagnostics.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 225d1a276f26cd34594eea7b70b6af97 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_domain_reload_resilience.py.meta b/Server/tests/integration/test_domain_reload_resilience.py.meta deleted file mode 100644 index db8b2bf5c..000000000 --- a/Server/tests/integration/test_domain_reload_resilience.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6e9bae83b1dfb1c44b5b89d377b8e9bc -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_edit_normalization_and_noop.py.meta b/Server/tests/integration/test_edit_normalization_and_noop.py.meta deleted file mode 100644 index 62ee31784..000000000 --- a/Server/tests/integration/test_edit_normalization_and_noop.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6a6c220bd546d6141bc81caf5c5d5c0c -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_edit_strict_and_warnings.py.meta b/Server/tests/integration/test_edit_strict_and_warnings.py.meta deleted file mode 100644 index 83117f359..000000000 --- a/Server/tests/integration/test_edit_strict_and_warnings.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 68d819ebdd34b9b4d94cf2a724deaab8 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_editor_state_v2_contract.py.meta b/Server/tests/integration/test_editor_state_v2_contract.py.meta deleted file mode 100644 index 245bc46e8..000000000 --- a/Server/tests/integration/test_editor_state_v2_contract.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 80931e72bd2d4a641afc1c2e51af0f0c -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_external_changes_scanner.py.meta b/Server/tests/integration/test_external_changes_scanner.py.meta deleted file mode 100644 index 797dbfbb4..000000000 --- a/Server/tests/integration/test_external_changes_scanner.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0f8f3a867304c854aa3832ef822964f0 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_find_gameobjects.py.meta b/Server/tests/integration/test_find_gameobjects.py.meta deleted file mode 100644 index 18185429e..000000000 --- a/Server/tests/integration/test_find_gameobjects.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: dd1df5ab6fdec464493d139099f4ee72 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_find_in_file_minimal.py.meta b/Server/tests/integration/test_find_in_file_minimal.py.meta deleted file mode 100644 index 1298aee0e..000000000 --- a/Server/tests/integration/test_find_in_file_minimal.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 37376021dec04ce4fab4ab73b6339e18 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_gameobject_resources.py.meta b/Server/tests/integration/test_gameobject_resources.py.meta deleted file mode 100644 index 5e09eda82..000000000 --- a/Server/tests/integration/test_gameobject_resources.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 66dfd0872ba5e2e4da5ffabae751a6ff -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_get_sha.py.meta b/Server/tests/integration/test_get_sha.py.meta deleted file mode 100644 index 928e45099..000000000 --- a/Server/tests/integration/test_get_sha.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 2ddb4afbcf9c9c9449c412b9b10adfd0 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_helpers.py.meta b/Server/tests/integration/test_helpers.py.meta deleted file mode 100644 index b1cfcb4c0..000000000 --- a/Server/tests/integration/test_helpers.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1a2c73119a1c91f4ca90ccfd8848d0c7 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_improved_anchor_matching.py.meta b/Server/tests/integration/test_improved_anchor_matching.py.meta deleted file mode 100644 index 8d7e3476b..000000000 --- a/Server/tests/integration/test_improved_anchor_matching.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: bd611b066c1b0484b97f0a6a7d625c48 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_instance_autoselect.py.meta b/Server/tests/integration/test_instance_autoselect.py.meta deleted file mode 100644 index 716e18a0e..000000000 --- a/Server/tests/integration/test_instance_autoselect.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 06aa9fb33062a304ca844c4a005db296 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_instance_routing_comprehensive.py.meta b/Server/tests/integration/test_instance_routing_comprehensive.py.meta deleted file mode 100644 index 98bd990eb..000000000 --- a/Server/tests/integration/test_instance_routing_comprehensive.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 691f7d1fb9b83344fb3b9c6296f63e16 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_instance_targeting_resolution.py.meta b/Server/tests/integration/test_instance_targeting_resolution.py.meta deleted file mode 100644 index 5fd04e329..000000000 --- a/Server/tests/integration/test_instance_targeting_resolution.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 573f1751e435e57479cad68f5f40e87f -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_json_parsing_simple.py.meta b/Server/tests/integration/test_json_parsing_simple.py.meta deleted file mode 100644 index cec3c657c..000000000 --- a/Server/tests/integration/test_json_parsing_simple.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 49697388fd65a5d4fb1249aa20738c95 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_logging_stdout.py.meta b/Server/tests/integration/test_logging_stdout.py.meta deleted file mode 100644 index e798dd5c8..000000000 --- a/Server/tests/integration/test_logging_stdout.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1df170c7abf4ecc4f9273490bcc8d72a -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_manage_asset_json_parsing.py.meta b/Server/tests/integration/test_manage_asset_json_parsing.py.meta deleted file mode 100644 index 4c26f7712..000000000 --- a/Server/tests/integration/test_manage_asset_json_parsing.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: d16b3428ed90b514793830470bb536eb -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_manage_asset_param_coercion.py.meta b/Server/tests/integration/test_manage_asset_param_coercion.py.meta deleted file mode 100644 index 9f2f77729..000000000 --- a/Server/tests/integration/test_manage_asset_param_coercion.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: d045dff8ac41d7544a1cacc16c965f89 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_manage_components.py.meta b/Server/tests/integration/test_manage_components.py.meta deleted file mode 100644 index cedd147f0..000000000 --- a/Server/tests/integration/test_manage_components.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5fe7edc74b58b8545b5a9dfa668be8f6 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_manage_gameobject_param_coercion.py.meta b/Server/tests/integration/test_manage_gameobject_param_coercion.py.meta deleted file mode 100644 index 35e6ef1a4..000000000 --- a/Server/tests/integration/test_manage_gameobject_param_coercion.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c951b394891014740bfc9169e6f4a70b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_manage_scene_paging_params.py.meta b/Server/tests/integration/test_manage_scene_paging_params.py.meta deleted file mode 100644 index 04824a7ec..000000000 --- a/Server/tests/integration/test_manage_scene_paging_params.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 2806f394b02d5f640a42e8a5f479e302 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_manage_script_uri.py.meta b/Server/tests/integration/test_manage_script_uri.py.meta deleted file mode 100644 index 148314b9f..000000000 --- a/Server/tests/integration/test_manage_script_uri.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0c8b277e9e833194b8e73cba04d5106f -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_manage_scriptable_object_tool.py.meta b/Server/tests/integration/test_manage_scriptable_object_tool.py.meta deleted file mode 100644 index 6be23921e..000000000 --- a/Server/tests/integration/test_manage_scriptable_object_tool.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4aec37777cc49cb46a91d70cf659c723 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_read_console_truncate.py.meta b/Server/tests/integration/test_read_console_truncate.py.meta deleted file mode 100644 index 0f9eb9643..000000000 --- a/Server/tests/integration/test_read_console_truncate.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5fda2f179924d964cacc799835995688 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_read_resource_minimal.py.meta b/Server/tests/integration/test_read_resource_minimal.py.meta deleted file mode 100644 index e7835d2ee..000000000 --- a/Server/tests/integration/test_read_resource_minimal.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a2c68347f81c43d4e8ba0cd12e645f44 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_refresh_unity_registration.py.meta b/Server/tests/integration/test_refresh_unity_registration.py.meta deleted file mode 100644 index 6f42ff129..000000000 --- a/Server/tests/integration/test_refresh_unity_registration.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ebd90212a1ce6854cb1102eb6a9c79fe -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_refresh_unity_retry_recovery.py.meta b/Server/tests/integration/test_refresh_unity_retry_recovery.py.meta deleted file mode 100644 index 506a224f1..000000000 --- a/Server/tests/integration/test_refresh_unity_retry_recovery.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: fd63fc3435c8f444581f5e75c48340f8 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_resources_api.py.meta b/Server/tests/integration/test_resources_api.py.meta deleted file mode 100644 index 56517bada..000000000 --- a/Server/tests/integration/test_resources_api.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 2e13401eaa145dd4496736dd5c271a0e -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_run_tests_async.py.meta b/Server/tests/integration/test_run_tests_async.py.meta deleted file mode 100644 index e2bfbd1f6..000000000 --- a/Server/tests/integration/test_run_tests_async.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6501557977f3ba84292d88cc51ef8bc4 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_script_editing.py.meta b/Server/tests/integration/test_script_editing.py.meta deleted file mode 100644 index c802296a4..000000000 --- a/Server/tests/integration/test_script_editing.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 76fa6a23a7f972941abc6d3404c2e3df -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_script_tools.py.meta b/Server/tests/integration/test_script_tools.py.meta deleted file mode 100644 index c3f22ef1e..000000000 --- a/Server/tests/integration/test_script_tools.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: faed355daa66d8446b7483ca217a9b0b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_telemetry_endpoint_validation.py.meta b/Server/tests/integration/test_telemetry_endpoint_validation.py.meta deleted file mode 100644 index 545faacc9..000000000 --- a/Server/tests/integration/test_telemetry_endpoint_validation.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: fa4c7af843191e04fad10a339e3cbfb8 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_telemetry_queue_worker.py.meta b/Server/tests/integration/test_telemetry_queue_worker.py.meta deleted file mode 100644 index 60b7a68bc..000000000 --- a/Server/tests/integration/test_telemetry_queue_worker.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6756a2de965b0df41865a27401773ed3 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_telemetry_subaction.py.meta b/Server/tests/integration/test_telemetry_subaction.py.meta deleted file mode 100644 index 9c4772ecc..000000000 --- a/Server/tests/integration/test_telemetry_subaction.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 218a726002b29b94381018d7ac8b1012 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_tool_signatures_paging.py.meta b/Server/tests/integration/test_tool_signatures_paging.py.meta deleted file mode 100644 index e6eb3107b..000000000 --- a/Server/tests/integration/test_tool_signatures_paging.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8f56c0b63e011f54a83ced53726ae4de -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_transport_framing.py.meta b/Server/tests/integration/test_transport_framing.py.meta deleted file mode 100644 index 16489b4e9..000000000 --- a/Server/tests/integration/test_transport_framing.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: d9f90eba3847eba4196a72bc49d8f25a -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/integration/test_validate_script_summary.py.meta b/Server/tests/integration/test_validate_script_summary.py.meta deleted file mode 100644 index 85c672515..000000000 --- a/Server/tests/integration/test_validate_script_summary.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 300c629bf12a4b54398d2c45cb9fd301 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/tests/pytest.ini.meta b/Server/tests/pytest.ini.meta deleted file mode 100644 index da8ce2183..000000000 --- a/Server/tests/pytest.ini.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 74e7f5a79268a734992851fcdb0bee66 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Server/uv.lock.meta b/Server/uv.lock.meta deleted file mode 100644 index 5f71d4ec1..000000000 --- a/Server/uv.lock.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 454b5d1fe82dd634aaa32ae1d299f9bd -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects.meta b/TestProjects.meta deleted file mode 100644 index 2f14f3fdf..000000000 --- a/TestProjects.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 021a2ed85354b094b9c8ec2de93507f3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads.meta b/TestProjects/AssetStoreUploads.meta deleted file mode 100644 index 75ed4e300..000000000 --- a/TestProjects/AssetStoreUploads.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b0d5ca4ca6bb7d943a15724c6300a1df -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets.meta b/TestProjects/AssetStoreUploads/Assets.meta deleted file mode 100644 index 94e8ea640..000000000 --- a/TestProjects/AssetStoreUploads/Assets.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 47e8e17e1b0de3a4e8e3fe63ae7c7f59 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages.meta b/TestProjects/AssetStoreUploads/Packages.meta deleted file mode 100644 index 49270c71f..000000000 --- a/TestProjects/AssetStoreUploads/Packages.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 16e2c11c19f0fee4fb69ef5a6f418d9b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta deleted file mode 100644 index ac43fd7f3..000000000 --- a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 36d677e7e6b372648b771e2f873cb93d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/manifest.json.meta b/TestProjects/AssetStoreUploads/Packages/manifest.json.meta deleted file mode 100644 index d2ee1792b..000000000 --- a/TestProjects/AssetStoreUploads/Packages/manifest.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a0761e5f92276324aaec08f922c40f1f -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta b/TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta deleted file mode 100644 index fdf81f9ea..000000000 --- a/TestProjects/AssetStoreUploads/Packages/packages-lock.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c9942e867fc168d4f9a364af28d3d338 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings.meta b/TestProjects/AssetStoreUploads/ProjectSettings.meta deleted file mode 100644 index 8f22affc0..000000000 --- a/TestProjects/AssetStoreUploads/ProjectSettings.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 52996e512febf5942916921ed6e9b200 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta b/TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta deleted file mode 100644 index beb59b36c..000000000 --- a/TestProjects/AssetStoreUploads/ProjectSettings/BurstAotSettings_StandaloneWindows.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 27f6f627a87621441983a9a83a7a87e5 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta b/TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta deleted file mode 100644 index ebffcb104..000000000 --- a/TestProjects/AssetStoreUploads/ProjectSettings/CommonBurstAotSettings.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 77b080dcddd96f54fa1d214108f7f1e8 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta b/TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta deleted file mode 100644 index db00e6897..000000000 --- a/TestProjects/AssetStoreUploads/ProjectSettings/ProjectVersion.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f4d93c27cb5cc8c42b1b5d8ef4a66481 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta b/TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta deleted file mode 100644 index f0a6a46a0..000000000 --- a/TestProjects/AssetStoreUploads/ProjectSettings/SceneTemplateSettings.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7b11105935e17ca4fb39ede15e69d91f -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests.meta b/TestProjects/UnityMCPTests.meta deleted file mode 100644 index a3a33f21e..000000000 --- a/TestProjects/UnityMCPTests.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b20d876ce504eb54b95acd2d2374b127 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Assets.meta b/TestProjects/UnityMCPTests/Assets.meta deleted file mode 100644 index b3cba2c47..000000000 --- a/TestProjects/UnityMCPTests/Assets.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 087c1ee3d6344234eb0048c3106564ea -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Packages.meta b/TestProjects/UnityMCPTests/Packages.meta deleted file mode 100644 index 9f2fa7c92..000000000 --- a/TestProjects/UnityMCPTests/Packages.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7106f5ef5cf5a3d4fb7de8dc41320b74 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Packages/manifest.json.meta b/TestProjects/UnityMCPTests/Packages/manifest.json.meta deleted file mode 100644 index 4735e5624..000000000 --- a/TestProjects/UnityMCPTests/Packages/manifest.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 42ee50e328de6af469c1f3290b7e5670 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings.meta b/TestProjects/UnityMCPTests/ProjectSettings.meta deleted file mode 100644 index e15912fb1..000000000 --- a/TestProjects/UnityMCPTests/ProjectSettings.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 67e2b34151b7c104dbec6354ad3618bf -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/Packages.meta b/TestProjects/UnityMCPTests/ProjectSettings/Packages.meta deleted file mode 100644 index 753ff2c0d..000000000 --- a/TestProjects/UnityMCPTests/ProjectSettings/Packages.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 786d3ce7786502b4981f27f363f4b1e1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta deleted file mode 100644 index 113cbc66d..000000000 --- a/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a2a7d199a1087a144afd05ff183414da -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta deleted file mode 100644 index 9146b71d1..000000000 --- a/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 41726fe76ebd66a448f3f2b068ec2893 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta b/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta deleted file mode 100644 index 4817eb610..000000000 --- a/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6f209388ecef66048883fdc45a7d79e1 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta b/TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta deleted file mode 100644 index b32a83503..000000000 --- a/TestProjects/UnityMCPTests/ProjectSettings/SceneTemplateSettings.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 83c1d94e5535b0e49baa4c32c635d0ff -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/claude_skill_unity.zip.meta b/claude_skill_unity.zip.meta deleted file mode 100644 index d638878f5..000000000 --- a/claude_skill_unity.zip.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 17022afa0ee8d764bba127ae4be3b838 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/deploy-dev.bat.meta b/deploy-dev.bat.meta deleted file mode 100644 index 43f6f447f..000000000 --- a/deploy-dev.bat.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: aa78a93ce81ef3b49b535e6dfad7c188 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docker-compose.yml.meta b/docker-compose.yml.meta deleted file mode 100644 index 3ef09649a..000000000 --- a/docker-compose.yml.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 722628ac8c02f8e45ad1ee86a325e0d0 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs.meta b/docs.meta deleted file mode 100644 index 29e067d0b..000000000 --- a/docs.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 77162687c5b9309478a58141f238cff0 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/CURSOR_HELP.md.meta b/docs/CURSOR_HELP.md.meta deleted file mode 100644 index 9a5fb77ee..000000000 --- a/docs/CURSOR_HELP.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: eda97419642608047a689c1177610890 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/CUSTOM_TOOLS.md.meta b/docs/CUSTOM_TOOLS.md.meta deleted file mode 100644 index c26a17935..000000000 --- a/docs/CUSTOM_TOOLS.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ccbdf7106a5bc774890092e3cc4ab1fa -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/MCP_CLIENT_CONFIGURATORS.md.meta b/docs/MCP_CLIENT_CONFIGURATORS.md.meta deleted file mode 100644 index fa9626ccd..000000000 --- a/docs/MCP_CLIENT_CONFIGURATORS.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 773ec24de26ffd84d837c47307981cdd -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/README-DEV-zh.md.meta b/docs/README-DEV-zh.md.meta deleted file mode 100644 index baf666ab3..000000000 --- a/docs/README-DEV-zh.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: bc8058c8dd3d0b544b23a7ab595e368c -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/README-DEV.md.meta b/docs/README-DEV.md.meta deleted file mode 100644 index 3232d578f..000000000 --- a/docs/README-DEV.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 880aea42120fe4e4fb4c5f94dd4cdd3f -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/TELEMETRY.md.meta b/docs/TELEMETRY.md.meta deleted file mode 100644 index a26680c51..000000000 --- a/docs/TELEMETRY.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f3c4dcf66d2f5fd4bb676edbcc1fa208 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images.meta b/docs/images.meta deleted file mode 100644 index df3756ec5..000000000 --- a/docs/images.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c0acdabdddfdbfe48a52db3eb5941549 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/advanced-setting.png.meta b/docs/images/advanced-setting.png.meta deleted file mode 100644 index 22d96d25c..000000000 --- a/docs/images/advanced-setting.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 2764160244f83084a93302d15498128d -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/building_scene.gif.meta b/docs/images/building_scene.gif.meta deleted file mode 100644 index 58180cd0a..000000000 --- a/docs/images/building_scene.gif.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 7fa0f73db31697448b8645c0a4ba71b8 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/coplay-logo.png.meta b/docs/images/coplay-logo.png.meta deleted file mode 100644 index 8919d4c03..000000000 --- a/docs/images/coplay-logo.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: a39a9b142e147a24caeb72964423312c -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/logo.png.meta b/docs/images/logo.png.meta deleted file mode 100644 index 0c2d596e6..000000000 --- a/docs/images/logo.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 33dc77dcea2123b4e91a5c58ebb21867 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/networking-architecture.png.meta b/docs/images/networking-architecture.png.meta deleted file mode 100644 index 55b531de0..000000000 --- a/docs/images/networking-architecture.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: e76c69cddaa6aea42b5fcb181dda3a3a -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/readme_ui.png.meta b/docs/images/readme_ui.png.meta deleted file mode 100644 index 9f265f381..000000000 --- a/docs/images/readme_ui.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 60028841f2110eb43bbfc65e9143d8f1 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/unity-mcp-ui-v8.6.png.meta b/docs/images/unity-mcp-ui-v8.6.png.meta deleted file mode 100644 index 84de8bea0..000000000 --- a/docs/images/unity-mcp-ui-v8.6.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: b0b7ce5355f1c89488d95bd4b4b63ccf -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v5_01_uninstall.png.meta b/docs/images/v5_01_uninstall.png.meta deleted file mode 100644 index 3aa4fb65d..000000000 --- a/docs/images/v5_01_uninstall.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: ea8ffd0b8fa96c14694c9dcdb1e33377 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v5_02_install.png.meta b/docs/images/v5_02_install.png.meta deleted file mode 100644 index 3ad7e70f6..000000000 --- a/docs/images/v5_02_install.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 9294bbc548170684ab67156901372dfd -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v5_03_open_mcp_window.png.meta b/docs/images/v5_03_open_mcp_window.png.meta deleted file mode 100644 index 86b7527e2..000000000 --- a/docs/images/v5_03_open_mcp_window.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 8c959712b1238d042ba1f2d6ec441208 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v5_04_rebuild_mcp_server.png.meta b/docs/images/v5_04_rebuild_mcp_server.png.meta deleted file mode 100644 index 01dd0cea5..000000000 --- a/docs/images/v5_04_rebuild_mcp_server.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: f219139b6631eca4d8fc83b5c04ff2df -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v5_05_rebuild_success.png.meta b/docs/images/v5_05_rebuild_success.png.meta deleted file mode 100644 index b58930dbe..000000000 --- a/docs/images/v5_05_rebuild_success.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: a5305ff7d7f39384ebf07cb98f994b94 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v6_2_create_python_tools_asset.png.meta b/docs/images/v6_2_create_python_tools_asset.png.meta deleted file mode 100644 index 9f5c985b9..000000000 --- a/docs/images/v6_2_create_python_tools_asset.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: aa5fd3e2722995e4d9ea55b5db8c3056 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v6_2_python_tools_asset.png.meta b/docs/images/v6_2_python_tools_asset.png.meta deleted file mode 100644 index 85e3c8ecb..000000000 --- a/docs/images/v6_2_python_tools_asset.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 4053eeb0a34f11e4e9165d85598afe93 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v6_new_ui_asset_store_version.png.meta b/docs/images/v6_new_ui_asset_store_version.png.meta deleted file mode 100644 index 8b21e22f7..000000000 --- a/docs/images/v6_new_ui_asset_store_version.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 2d2b6c4eb29d0e346a126f58d2633366 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v6_new_ui_dark.png.meta b/docs/images/v6_new_ui_dark.png.meta deleted file mode 100644 index 049ce4b89..000000000 --- a/docs/images/v6_new_ui_dark.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: d8f160ed1e5569e4ab56ae71be2dd951 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/images/v6_new_ui_light.png.meta b/docs/images/v6_new_ui_light.png.meta deleted file mode 100644 index e8114911f..000000000 --- a/docs/images/v6_new_ui_light.png.meta +++ /dev/null @@ -1,127 +0,0 @@ -fileFormatVersion: 2 -guid: 6f7fa20b90de51b4e9832b379a240570 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/v5_MIGRATION.md.meta b/docs/v5_MIGRATION.md.meta deleted file mode 100644 index abff3af45..000000000 --- a/docs/v5_MIGRATION.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 68f0682d75bb6bd40927ad43889a1317 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/v6_NEW_UI_CHANGES.md.meta b/docs/v6_NEW_UI_CHANGES.md.meta deleted file mode 100644 index ce7b2f51a..000000000 --- a/docs/v6_NEW_UI_CHANGES.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 9bf383542a284b943923ff0861c15dc8 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/docs/v8_NEW_NETWORKING_SETUP.md.meta b/docs/v8_NEW_NETWORKING_SETUP.md.meta deleted file mode 100644 index ecd2fd798..000000000 --- a/docs/v8_NEW_NETWORKING_SETUP.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f26e6570e81ca604aa82678cb7847504 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/mcp_source.py.meta b/mcp_source.py.meta deleted file mode 100644 index b40d68766..000000000 --- a/mcp_source.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5effdbbfab676ca448dba87a904d1b60 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/prune_tool_results.py.meta b/prune_tool_results.py.meta deleted file mode 100644 index 96e41dc6b..000000000 --- a/prune_tool_results.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7a1782aa87883b74ab0373cfa5be7b13 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/restore-dev.bat.meta b/restore-dev.bat.meta deleted file mode 100644 index fb92f8649..000000000 --- a/restore-dev.bat.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 56859f68ea72ff54b8a2c93ef9f86c4b -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/scripts.meta b/scripts.meta deleted file mode 100644 index be553cd25..000000000 --- a/scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2d56e020953f5494895fbccbb042f031 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/scripts/validate-nlt-coverage.sh.meta b/scripts/validate-nlt-coverage.sh.meta deleted file mode 100644 index bc82394e8..000000000 --- a/scripts/validate-nlt-coverage.sh.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 772111267bbc4634c9e609ec2c3ef8c3 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/test_unity_socket_framing.py.meta b/test_unity_socket_framing.py.meta deleted file mode 100644 index e9e589533..000000000 --- a/test_unity_socket_framing.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 63b84137149ce644eac635fbb95798f0 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/tools.meta b/tools.meta deleted file mode 100644 index 5614312fe..000000000 --- a/tools.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bacbaf659b7efdc44bc44ff0dfc108b0 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/tools/prepare_unity_asset_store_release.py.meta b/tools/prepare_unity_asset_store_release.py.meta deleted file mode 100644 index 45108bee4..000000000 --- a/tools/prepare_unity_asset_store_release.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: bd846af6127c76748a48cceb93abeee1 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/tools/stress_mcp.py.meta b/tools/stress_mcp.py.meta deleted file mode 100644 index 9a0e1b770..000000000 --- a/tools/stress_mcp.py.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ff2b29403cc241f4cb1d185fb738d51f -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From 1832715aefdf94cd093103a7db1822a34dae85d8 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 13:45:29 +0800 Subject: [PATCH 08/23] Update .gitignore --- .gitignore | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitignore b/.gitignore index abb4d8b4c..1ffda95f9 100644 --- a/.gitignore +++ b/.gitignore @@ -58,7 +58,3 @@ reports/ # Local testing harness scripts/local-test/ - -*.meta - -**/*.meta \ No newline at end of file From 554ddd0bdad378af965a5afc9d4b263a639a6579 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 14:12:22 +0800 Subject: [PATCH 09/23] save .meta --- TestProjects/AssetStoreUploads/Assets/Readme.asset.meta | 8 ++++++++ .../Assets/Settings/SampleSceneProfile.asset.meta | 8 ++++++++ .../Assets/Settings/URP-Balanced-Renderer.asset.meta | 8 ++++++++ .../Assets/Settings/URP-Balanced.asset.meta | 8 ++++++++ .../Assets/Settings/URP-HighFidelity-Renderer.asset.meta | 8 ++++++++ .../Assets/Settings/URP-HighFidelity.asset.meta | 8 ++++++++ .../Assets/Settings/URP-Performant-Renderer.asset.meta | 8 ++++++++ .../Assets/Settings/URP-Performant.asset.meta | 8 ++++++++ .../UniversalRenderPipelineGlobalSettings.asset.meta | 8 ++++++++ .../Tests/Generic/Check Animation Clips.asset.meta | 8 ++++++++ .../Tests/Generic/Check Audio Clipping.asset.meta | 8 ++++++++ .../Validator/Tests/Generic/Check Colliders.asset.meta | 8 ++++++++ .../Tests/Generic/Check Compressed Files.asset.meta | 8 ++++++++ .../Tests/Generic/Check Empty Prefabs.asset.meta | 8 ++++++++ .../Tests/Generic/Check File Menu Names.asset.meta | 8 ++++++++ .../Editor/Validator/Tests/Generic/Check LODs.asset.meta | 8 ++++++++ .../Validator/Tests/Generic/Check Line Endings.asset.meta | 8 ++++++++ .../Validator/Tests/Generic/Check Mesh Prefabs.asset.meta | 8 ++++++++ .../Generic/Check Missing Components in Assets.asset.meta | 8 ++++++++ .../Generic/Check Missing Components in Scenes.asset.meta | 8 ++++++++ .../Tests/Generic/Check Model Import Logs.asset.meta | 8 ++++++++ .../Tests/Generic/Check Model Orientation.asset.meta | 8 ++++++++ .../Validator/Tests/Generic/Check Model Types.asset.meta | 8 ++++++++ .../Tests/Generic/Check Normal Map Textures.asset.meta | 8 ++++++++ .../Tests/Generic/Check Package Naming.asset.meta | 8 ++++++++ .../Tests/Generic/Check Particle Systems.asset.meta | 8 ++++++++ .../Validator/Tests/Generic/Check Path Lengths.asset.meta | 8 ++++++++ .../Tests/Generic/Check Prefab Transforms.asset.meta | 8 ++++++++ .../Tests/Generic/Check Script Compilation.asset.meta | 8 ++++++++ .../Tests/Generic/Check Shader Compilation.asset.meta | 8 ++++++++ .../Tests/Generic/Check Texture Dimensions.asset.meta | 8 ++++++++ .../Tests/Generic/Check Type Namespaces.asset.meta | 8 ++++++++ .../Tests/Generic/Remove Executable Files.asset.meta | 8 ++++++++ .../Validator/Tests/Generic/Remove JPG Files.asset.meta | 8 ++++++++ .../Tests/Generic/Remove JavaScript Files.asset.meta | 8 ++++++++ .../Tests/Generic/Remove Lossy Audio Files.asset.meta | 8 ++++++++ .../Tests/Generic/Remove Mixamo Files.asset.meta | 8 ++++++++ .../Tests/Generic/Remove SpeedTree Files.asset.meta | 8 ++++++++ .../Validator/Tests/Generic/Remove Video Files.asset.meta | 8 ++++++++ .../Tests/UnityPackage/Check Demo Scenes.asset.meta | 8 ++++++++ .../Tests/UnityPackage/Check Documentation.asset.meta | 8 ++++++++ .../Tests/UnityPackage/Check Package Size.asset.meta | 8 ++++++++ .../UnityPackage/Check Project Template Assets.asset.meta | 8 ++++++++ 43 files changed, 344 insertions(+) create mode 100644 TestProjects/AssetStoreUploads/Assets/Readme.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta create mode 100644 TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta diff --git a/TestProjects/AssetStoreUploads/Assets/Readme.asset.meta b/TestProjects/AssetStoreUploads/Assets/Readme.asset.meta new file mode 100644 index 000000000..ab3ad4535 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Readme.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8105016687592461f977c054a80ce2f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta new file mode 100644 index 000000000..f8cce646a --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Settings/SampleSceneProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a6560a915ef98420e9faacc1c7438823 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta new file mode 100644 index 000000000..8fa7f17dc --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced-Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e634585d5c4544dd297acaee93dc2beb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta new file mode 100644 index 000000000..f524db054 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Balanced.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e1260c1148f6143b28bae5ace5e9c5d1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta new file mode 100644 index 000000000..bcdff020b --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity-Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c40be3174f62c4acf8c1216858c64956 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta new file mode 100644 index 000000000..7416e17a3 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Settings/URP-HighFidelity.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7b7fd9122c28c4d15b667c7040e3b3fd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta new file mode 100644 index 000000000..912ff6009 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant-Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 707360a9c581a4bd7aa53bfeb1429f71 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta new file mode 100644 index 000000000..264c9c559 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/Settings/URP-Performant.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0e2fc18fe036412f8223b3b3d9ad574 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta b/TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta new file mode 100644 index 000000000..81b84f2ae --- /dev/null +++ b/TestProjects/AssetStoreUploads/Assets/UniversalRenderPipelineGlobalSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 18dc0cd2c080841dea60987a38ce93fa +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta new file mode 100644 index 000000000..e64790381 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Animation Clips.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0426dd01b5136a4ca1d42d312e12fad +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta new file mode 100644 index 000000000..f7b5dcf3d --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Audio Clipping.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 03c6cd398931b3e41b0784e8589e153f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta new file mode 100644 index 000000000..9b1b8d4ea --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Colliders.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28ab5af444cf3c849800ed0d8f4a3102 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta new file mode 100644 index 000000000..dbf116475 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Compressed Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53189e6e51235b14192c4d5b3145dd27 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta new file mode 100644 index 000000000..d2f3da2be --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Empty Prefabs.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08790ea0ed0fd274fb1df75ccc32d415 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta new file mode 100644 index 000000000..a5a922abb --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check File Menu Names.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eaf232919893db04b8e05e91f6815424 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta new file mode 100644 index 000000000..deb5c41ff --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check LODs.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad52ffa05767e9d4bb4d92093ad68b03 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta new file mode 100644 index 000000000..699185ff2 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Line Endings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e7b5480c1d8bda43ab4fa945939e243 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta new file mode 100644 index 000000000..cff122c48 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Mesh Prefabs.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 03b362b67028eb443b7ba8b84aedd5f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta new file mode 100644 index 000000000..6ba4103ab --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Assets.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a3d0b3827fc16347867bee335e8f4ea +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta new file mode 100644 index 000000000..42d6127f2 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Missing Components in Scenes.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc2cb4e6635aa334ea4a52e2e3ce57c8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta new file mode 100644 index 000000000..ba55c59e6 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Import Logs.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c889cdd91c2f41941a14363dad7a1a38 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta new file mode 100644 index 000000000..4f493136e --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Orientation.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45b2b11da67e8864aacc62d928524b4c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta new file mode 100644 index 000000000..c4aef0714 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Model Types.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ffef800a102b0e04cae1a3b98549ef1b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta new file mode 100644 index 000000000..66ff0da6b --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Normal Map Textures.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 241ad0174fcadb64da867011d196acbb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta new file mode 100644 index 000000000..f5e0feab8 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Package Naming.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 04098aa074d151b4a908dfa79dfddec3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta new file mode 100644 index 000000000..5404fd491 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Particle Systems.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 87da7eaed3cee0d4b8ada0b500e3a958 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta new file mode 100644 index 000000000..4ebd5acee --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Path Lengths.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21f8ec0602ffac045b1f4a93f8a9b555 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta new file mode 100644 index 000000000..713d9087b --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Prefab Transforms.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 700026f446833f649a3c63b33a90a295 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta new file mode 100644 index 000000000..3a026fb4d --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Script Compilation.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 339e21c955642a04289482aa923e10b6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta new file mode 100644 index 000000000..c9ebccf60 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Shader Compilation.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1450037453608204a989ff95dca62fae +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta new file mode 100644 index 000000000..d0318d49f --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Texture Dimensions.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c23253393b8e28846b8e02aeaee7e152 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta new file mode 100644 index 000000000..2aa250d34 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Check Type Namespaces.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd110ee16e8de4d48a602349ed7a0b25 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta new file mode 100644 index 000000000..b27033d7d --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Executable Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e996c53186de96e49a742d414648a809 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta new file mode 100644 index 000000000..45000c997 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JPG Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 781021ae3aa6570468e08d78e3195127 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta new file mode 100644 index 000000000..d41b9e650 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove JavaScript Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf01c18b66907f54c99517f6a877e3e0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta new file mode 100644 index 000000000..2026425ca --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Lossy Audio Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a48657926de5cfb47ac559a7108d03ee +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta new file mode 100644 index 000000000..84abdb1b3 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Mixamo Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a0a44055f786ec64f86a07a214d5f831 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta new file mode 100644 index 000000000..ffc10af27 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove SpeedTree Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 305bbe67f7c644d18bc8a5b2273aa6a4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta new file mode 100644 index 000000000..e62946cea --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/Generic/Remove Video Files.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 893a0df188c2026438be48eed39b301f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta new file mode 100644 index 000000000..d58914fe8 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Demo Scenes.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f108107be07f69045813d69eff580078 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta new file mode 100644 index 000000000..4ee63356a --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Documentation.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b03433f7977b29e4ca7e8d76393a6c26 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta new file mode 100644 index 000000000..63433dd52 --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Package Size.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 25721b2d7384e5b4f936cf3b33b80a02 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta new file mode 100644 index 000000000..a00554e8f --- /dev/null +++ b/TestProjects/AssetStoreUploads/Packages/com.unity.asset-store-tools/Editor/Validator/Tests/UnityPackage/Check Project Template Assets.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5392e9de0549574419ff76897d1e0fa1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: From fb5909d41339859f73758d86db9579f361a98314 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 17:38:14 +0800 Subject: [PATCH 10/23] refactor: unify uv/uvx naming and path detection across platforms - Rename TryValidateUvExecutable -> TryValidateUvxExecutable for consistency - Add cross-platform FindInPath() helper in ExecPath.cs - Remove platform-specific where/which implementations in favor of unified helper - Add Windows-specific DetectUv() override with enhanced uv/uvx detection - Add WinGet shim path support for Windows uvx installation - Update UI labels: "UV Path" -> "UVX Path" - Only show uvx path status when override is configured Co-Authored-By: Claude Opus 4.5 --- .../Clients/McpClientConfiguratorBase.cs | 2 +- .../LinuxPlatformDetector.cs | 31 +--- .../MacOSPlatformDetector.cs | 31 +--- .../PlatformDetectors/PlatformDetectorBase.cs | 10 +- .../WindowsPlatformDetector.cs | 133 ++++++++++++++---- MCPForUnity/Editor/Helpers/ExecPath.cs | 25 +++- .../Editor/Services/IPathResolverService.cs | 2 +- .../Editor/Services/PathResolverService.cs | 26 ++-- .../Components/Settings/McpSettingsSection.cs | 20 ++- .../Settings/McpSettingsSection.uxml | 2 +- 10 files changed, 172 insertions(+), 110 deletions(-) diff --git a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs index ed8d6a690..2cff1ab60 100644 --- a/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs +++ b/MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs @@ -42,7 +42,7 @@ protected string GetUvxPathOrError() string uvx = MCPServiceLocator.Paths.GetUvxPath(); if (string.IsNullOrEmpty(uvx)) { - throw new InvalidOperationException("uv not found. Install uv/uvx or set the override in Advanced Settings."); + throw new InvalidOperationException("uvx not found. Install uv/uvx or set the override in Advanced Settings."); } return uvx; } diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs index cd071b41e..8192a8ba9 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs @@ -196,10 +196,11 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); - if (output.StartsWith("uv ") || output.StartsWith("uvx ")) + // uv/uvx outputs "uv x.y.z" or "uvx x.y.z" + if (output.StartsWith("uvx ") || output.StartsWith("uv ")) { - // Extract version: "uvx 0.9.18" -> "0.9.18" - // Handle extra tokens: "uvx 0.9.18 extra" or "uvx 0.9.18 (build info)" + // Extract version: "uv 0.9.18" -> "0.9.18" + // Handle extra tokens: "uv 0.9.18 extra" or "uv 0.9.18 (build info)" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { @@ -248,28 +249,8 @@ private string[] GetPathAdditions() private bool TryFindInPath(string executable, out string fullPath) { - fullPath = null; - - try - { - string augmentedPath = BuildAugmentedPath(); - - if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath)) - return false; - - string output = stdout.Trim(); - if (!string.IsNullOrEmpty(output) && File.Exists(output)) - { - fullPath = output; - return true; - } - } - catch - { - // Ignore errors - } - - return false; + fullPath = ExecPath.FindInPath(executable, BuildAugmentedPath()); + return !string.IsNullOrEmpty(fullPath); } } } diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs index 20cb2c6d0..5ae8a1777 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs @@ -194,10 +194,11 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); - if (output.StartsWith("uv ") || output.StartsWith("uvx ")) + // uv/uvx outputs "uv x.y.z" or "uvx x.y.z" + if (output.StartsWith("uvx ") || output.StartsWith("uv ")) { - // Extract version: "uvx 0.9.18" -> "0.9.18" - // Handle extra tokens: "uvx 0.9.18 extra" or "uvx 0.9.18 (build info)" + // Extract version: "uv 0.9.18" -> "0.9.18" + // Handle extra tokens: "uv 0.9.18 extra" or "uv 0.9.18 (build info)" int spaceIndex = output.IndexOf(' '); if (spaceIndex >= 0) { @@ -246,28 +247,8 @@ private string[] GetPathAdditions() private bool TryFindInPath(string executable, out string fullPath) { - fullPath = null; - - try - { - string augmentedPath = BuildAugmentedPath(); - - if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath)) - return false; - - string output = stdout.Trim(); - if (!string.IsNullOrEmpty(output) && File.Exists(output)) - { - fullPath = output; - return true; - } - } - catch - { - // Ignore errors - } - - return false; + fullPath = ExecPath.FindInPath(executable, BuildAugmentedPath()); + return !string.IsNullOrEmpty(fullPath); } } } diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs index 77edd19c4..77bc93626 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs @@ -27,26 +27,26 @@ public virtual DependencyStatus DetectUv() try { // Get uv path from PathResolverService (respects override) - string uvPath = MCPServiceLocator.Paths.GetUvxPath(); + string uvxPath = MCPServiceLocator.Paths.GetUvxPath(); // Verify uv executable and get version - if (MCPServiceLocator.Paths.TryValidateUvExecutable(uvPath, out string version)) + if (MCPServiceLocator.Paths.TryValidateUvxExecutable(uvxPath, out string version)) { status.IsAvailable = true; status.Version = version; - status.Path = uvPath; + status.Path = uvxPath; status.Details = MCPServiceLocator.Paths.HasUvxPathOverride ? $"Found uv {version} (override path)" : $"Found uv {version} in system path"; return status; } - status.ErrorMessage = "uv not found"; + status.ErrorMessage = "uvx not found"; status.Details = "Install uv package manager or configure path override in Advanced Settings."; } catch (Exception ex) { - status.ErrorMessage = $"Error detecting uv: {ex.Message}"; + status.ErrorMessage = $"Error detecting uvx: {ex.Message}"; } return status; diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs index 16896319b..f7815eaef 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs @@ -1,8 +1,3 @@ -/* - //Windows currently does not override DetectUv(), relying entirely on the base class. This is correct because: - //The PathResolverService already includes Windows-specific paths. - //There are no additional Windows-specific detection requirements. -*/ using System; using System.Collections.Generic; using System.Diagnostics; @@ -12,6 +7,7 @@ using MCPForUnity.Editor.Constants; using MCPForUnity.Editor.Dependencies.Models; using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.Services; namespace MCPForUnity.Editor.Dependencies.PlatformDetectors { @@ -104,6 +100,105 @@ public override string GetInstallationRecommendations() 3. MCP Server: Will be installed automatically by MCP for Unity Bridge"; } + public override DependencyStatus DetectUv() + { + // First, honor overrides and cross-platform resolution via the base implementation + var status = base.DetectUv(); + if (status.IsAvailable) + { + return status; + } + + // If the user configured an override path, keep the base result (failure typically means the override path is invalid) + if (MCPServiceLocator.Paths.HasUvxPathOverride) + { + return status; + } + + try + { + string augmentedPath = BuildAugmentedPath(); + + // try to find uv + if (TryValidateUvWithPath("uv.exe", augmentedPath, out string uvVersion, out string uvPath)) + { + status.IsAvailable = true; + status.Version = uvVersion; + status.Path = uvPath; + status.Details = $"Found uv {uvVersion} at {uvPath}"; // 真实的路径反馈 + return status; + } + + // try to find uvx + if (TryValidateUvWithPath("uvx.exe", augmentedPath, out string uvxVersion, out string uvxPath)) + { + status.IsAvailable = true; + status.Version = uvxVersion; + status.Path = uvxPath; + status.Details = $"Found uvx {uvxVersion} at {uvxPath} (fallback)"; + return status; + } + + status.ErrorMessage = "uv not found in PATH"; + status.Details = "Install uv package manager and ensure it's added to PATH."; + } + catch (Exception ex) + { + status.ErrorMessage = $"Error detecting uv: {ex.Message}"; + } + + return status; + } + + private bool TryValidateUvWithPath(string command, string augmentedPath, out string version, out string fullPath) + { + version = null; + fullPath = null; + + try + { + // First, try to resolve the absolute path for better UI/logging display + string commandToRun = command; + if (TryFindInPath(command, out string resolvedPath)) + { + commandToRun = resolvedPath; + } + + // Use ExecPath.TryRun which properly handles async output reading and timeouts + if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, + 5000, augmentedPath)) + return false; + + string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); + + // uv/uvx outputs "uv x.y.z" or "uvx x.y.z" + if (output.StartsWith("uvx ") || output.StartsWith("uv ")) + { + // Extract version: "uv 0.9.18" -> "0.9.18" + int spaceIndex = output.IndexOf(' '); + if (spaceIndex >= 0) + { + var remainder = output.Substring(spaceIndex + 1).Trim(); + int nextSpace = remainder.IndexOf(' '); + int parenIndex = remainder.IndexOf('('); + int endIndex = Math.Min( + nextSpace >= 0 ? nextSpace : int.MaxValue, + parenIndex >= 0 ? parenIndex : int.MaxValue + ); + version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; + fullPath = commandToRun; + return true; + } + } + } + catch + { + // Ignore validation errors + } + + return false; + } + private bool TryFindPythonViaUv(out string version, out string fullPath) { version = null; @@ -112,8 +207,8 @@ private bool TryFindPythonViaUv(out string version, out string fullPath) try { string augmentedPath = BuildAugmentedPath(); - // Try to list installed python versions via uv - if (!ExecPath.TryRun("uv", "python list", null, out string stdout, out string stderr, 5000, augmentedPath)) + // Try to list installed python versions via uvx + if (!ExecPath.TryRun("uvx", "python list", null, out string stdout, out string stderr, 5000, augmentedPath)) return false; var lines = stdout.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); @@ -187,28 +282,8 @@ private bool TryValidatePython(string pythonPath, out string version, out string private bool TryFindInPath(string executable, out string fullPath) { - fullPath = null; - - try - { - string augmentedPath = BuildAugmentedPath(); - // Use 'where' command to find the executable in PATH - if (!ExecPath.TryRun("where", executable, null, out string stdout, out string stderr, 3000, augmentedPath)) - return false; - - var lines = stdout.Trim().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - if (lines.Length > 0) - { - fullPath = lines[0].Trim(); - return File.Exists(fullPath); - } - } - catch - { - // Ignore errors - } - - return false; + fullPath = ExecPath.FindInPath(executable, BuildAugmentedPath()); + return !string.IsNullOrEmpty(fullPath); } protected string BuildAugmentedPath() diff --git a/MCPForUnity/Editor/Helpers/ExecPath.cs b/MCPForUnity/Editor/Helpers/ExecPath.cs index fbb7cb3e5..5df0374d0 100644 --- a/MCPForUnity/Editor/Helpers/ExecPath.cs +++ b/MCPForUnity/Editor/Helpers/ExecPath.cs @@ -62,7 +62,7 @@ internal static string ResolveClaude() Path.Combine(localAppData, "npm", "claude.ps1"), }; foreach (string c in candidates) { if (File.Exists(c)) return c; } - string fromWhere = Where("claude.exe") ?? Where("claude.cmd") ?? Where("claude.ps1") ?? Where("claude"); + string fromWhere = FindInPathWindows("claude.exe") ?? FindInPathWindows("claude.cmd") ?? FindInPathWindows("claude.ps1") ?? FindInPathWindows("claude"); if (!string.IsNullOrEmpty(fromWhere)) return fromWhere; #endif return null; @@ -197,9 +197,9 @@ internal static bool TryRun( using var process = new Process { StartInfo = psi, EnableRaisingEvents = false }; - var so = new StringBuilder(); + var sb = new StringBuilder(); var se = new StringBuilder(); - process.OutputDataReceived += (_, e) => { if (e.Data != null) so.AppendLine(e.Data); }; + process.OutputDataReceived += (_, e) => { if (e.Data != null) sb.AppendLine(e.Data); }; process.ErrorDataReceived += (_, e) => { if (e.Data != null) se.AppendLine(e.Data); }; if (!process.Start()) return false; @@ -216,7 +216,7 @@ internal static bool TryRun( // Ensure async buffers are flushed process.WaitForExit(); - stdout = so.ToString(); + stdout = sb.ToString(); stderr = se.ToString(); return process.ExitCode == 0; } @@ -226,6 +226,21 @@ internal static bool TryRun( } } + /// + /// Cross-platform path lookup. Uses 'where' on Windows, 'which' on macOS/Linux. + /// Returns the full path if found, null otherwise. + /// + internal static string FindInPath(string executable, string extraPathPrepend = null) + { +#if UNITY_EDITOR_WIN + return FindInPathWindows(executable); +#elif UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX + return Which(executable, extraPathPrepend ?? string.Empty); +#else + return null; +#endif + } + #if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX private static string Which(string exe, string prependPath) { @@ -262,7 +277,7 @@ private static string Which(string exe, string prependPath) #endif #if UNITY_EDITOR_WIN - private static string Where(string exe) + private static string FindInPathWindows(string exe) { try { diff --git a/MCPForUnity/Editor/Services/IPathResolverService.cs b/MCPForUnity/Editor/Services/IPathResolverService.cs index a5d7cd190..0087aafb5 100644 --- a/MCPForUnity/Editor/Services/IPathResolverService.cs +++ b/MCPForUnity/Editor/Services/IPathResolverService.cs @@ -67,6 +67,6 @@ public interface IPathResolverService /// Absolute or relative path to the uv/uvx executable. /// Parsed version string if successful. /// True when the executable runs and returns a uv version string. - bool TryValidateUvExecutable(string uvPath, out string version); + bool TryValidateUvxExecutable(string uvPath, out string version); } } diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index f678afe6a..1fc26b4d3 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -26,7 +26,7 @@ public string GetUvxPath() { string overridePath = EditorPrefs.GetString(EditorPrefKeys.UvxPathOverride, string.Empty); // Validate the override - if invalid, don't fall back to discovery - if (TryValidateUvExecutable(overridePath, out string version)) + if (TryValidateUvxExecutable(overridePath, out string version)) { return overridePath; } @@ -130,6 +130,8 @@ private static IEnumerable EnumerateUvxCandidates(string commandName) if (!string.IsNullOrEmpty(localAppData)) { yield return Path.Combine(localAppData, "Programs", "uv", exeName); + // WinGet creates shim files in this location + yield return Path.Combine(localAppData, "Microsoft", "WinGet", "Links", exeName); } if (!string.IsNullOrEmpty(programFiles)) @@ -264,39 +266,39 @@ public void ClearClaudeCliPathOverride() /// /// Absolute or relative path to the uv/uvx executable. /// Parsed version string if successful. - /// True when the executable runs and returns a uv version string. - public bool TryValidateUvExecutable(string uvPath, out string version) + /// True when the executable runs and returns a uvx version string. + public bool TryValidateUvxExecutable(string uvxPath, out string version) { version = null; - if (string.IsNullOrEmpty(uvPath)) + if (string.IsNullOrEmpty(uvxPath)) return false; try { // Check if the path is just a command name (no directory separator) - bool isBareCommand = !uvPath.Contains('/') && !uvPath.Contains('\\'); + bool isBareCommand = !uvxPath.Contains('/') && !uvxPath.Contains('\\'); if (isBareCommand) { // For bare commands like "uvx" or "uv", use EnumerateCommandCandidates to find full path first - string fullPath = FindUvxExecutableInPath(uvPath); + string fullPath = FindUvxExecutableInPath(uvxPath); if (string.IsNullOrEmpty(fullPath)) return false; - uvPath = fullPath; + uvxPath = fullPath; } // Use ExecPath.TryRun which properly handles async output reading and timeouts - if (!ExecPath.TryRun(uvPath, "--version", null, out string stdout, out string stderr, 5000)) + if (!ExecPath.TryRun(uvxPath, "--version", null, out string stdout, out string stderr, 5000)) return false; // Check stdout first, then stderr (some tools output to stderr) string versionOutput = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim(); - // uvx outputs "uvx x.y.z" or "uv x.y.z", extract version number - if (versionOutput.StartsWith("uv ") || versionOutput.StartsWith("uvx ")) + // uv/uvx outputs "uv x.y.z" or "uvx x.y.z", extract version number + if (versionOutput.StartsWith("uvx ") || versionOutput.StartsWith("uv ")) { - // Extract version: "uvx 0.9.18 (hash date)" -> "0.9.18" + // Extract version: "uv 0.9.18 (hash date)" -> "0.9.18" int spaceIndex = versionOutput.IndexOf(' '); if (spaceIndex >= 0) { @@ -391,6 +393,8 @@ private static IEnumerable EnumerateCommandCandidates(string commandName if (!string.IsNullOrEmpty(localAppData)) { yield return Path.Combine(localAppData, "Programs", "uv", exeName); + // WinGet creates shim files in this location + yield return Path.Combine(localAppData, "Microsoft", "WinGet", "Links", exeName); } if (!string.IsNullOrEmpty(programFiles)) diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs index 69739b630..a77dfd0db 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs @@ -198,16 +198,22 @@ public void UpdatePathOverrides() uvxPathStatus.RemoveFromClassList("valid"); uvxPathStatus.RemoveFromClassList("invalid"); - string actualUvxPath = MCPServiceLocator.Paths.GetUvxPath(); - if (MCPServiceLocator.Paths.TryValidateUvExecutable(actualUvxPath, out string version)) + // 只在设置了 override 时显示状态 + if (hasOverride) { - uvxPathStatus.AddToClassList("valid"); - } - else - { - uvxPathStatus.AddToClassList("invalid"); + string overridePath = EditorPrefs.GetString(EditorPrefKeys.UvxPathOverride, string.Empty); + if (pathService.TryValidateUvxExecutable(overridePath, out string version)) + { + uvxPathStatus.AddToClassList("valid"); + } + else + { + uvxPathStatus.AddToClassList("invalid"); + } } + // if not override, Draw did not find status + gitUrlOverride.value = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, ""); devModeForceRefreshToggle.value = EditorPrefs.GetBool(EditorPrefKeys.DevModeForceServerRefresh, false); UpdateDeploymentSection(); diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml index 1f15748c6..685033fb0 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml +++ b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.uxml @@ -20,7 +20,7 @@ - + From 254125a2a4171fa2f4312fdd243ae5b863c081df Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 17:55:17 +0800 Subject: [PATCH 11/23] fix: improve validation light(uvxPathStatus) logic for UVX path overrides and system paths --- .../Components/Settings/McpSettingsSection.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs index a77dfd0db..a754a52b1 100644 --- a/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs +++ b/MCPForUnity/Editor/Windows/Components/Settings/McpSettingsSection.cs @@ -198,11 +198,24 @@ public void UpdatePathOverrides() uvxPathStatus.RemoveFromClassList("valid"); uvxPathStatus.RemoveFromClassList("invalid"); - // 只在设置了 override 时显示状态 if (hasOverride) { + // Override mode: validate the override path string overridePath = EditorPrefs.GetString(EditorPrefKeys.UvxPathOverride, string.Empty); - if (pathService.TryValidateUvxExecutable(overridePath, out string version)) + if (pathService.TryValidateUvxExecutable(overridePath, out _)) + { + uvxPathStatus.AddToClassList("valid"); + } + else + { + uvxPathStatus.AddToClassList("invalid"); + } + } + else + { + // PATH mode: validate system uvx + string systemUvxPath = pathService.GetUvxPath(); + if (!string.IsNullOrEmpty(systemUvxPath) && pathService.TryValidateUvxExecutable(systemUvxPath, out _)) { uvxPathStatus.AddToClassList("valid"); } @@ -211,8 +224,6 @@ public void UpdatePathOverrides() uvxPathStatus.AddToClassList("invalid"); } } - - // if not override, Draw did not find status gitUrlOverride.value = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, ""); devModeForceRefreshToggle.value = EditorPrefs.GetBool(EditorPrefKeys.DevModeForceServerRefresh, false); From f9ae5d51c97b6fd62435d8eaca4e742202b87aeb Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 19:03:30 +0800 Subject: [PATCH 12/23] refactor: streamline UV version validation and unify path detection methods across platform detectors --- .../LinuxPlatformDetector.cs | 54 +-------------- .../MacOSPlatformDetector.cs | 54 +-------------- .../PlatformDetectors/PlatformDetectorBase.cs | 50 ++++++++++++++ .../WindowsPlatformDetector.cs | 69 ++++--------------- .../Editor/Services/PathResolverService.cs | 66 +----------------- 5 files changed, 70 insertions(+), 223 deletions(-) diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs index 8192a8ba9..ff883a7e3 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs @@ -163,57 +163,7 @@ private bool TryValidatePython(string pythonPath, out string version, out string if (TryParseVersion(version, out var major, out var minor)) { - return major > 3 || (major >= 3 && minor >= 10); - } - } - } - catch - { - // Ignore validation errors - } - - return false; - } - - private bool TryValidateUvWithPath(string command, string augmentedPath, out string version, out string fullPath) - { - version = null; - fullPath = null; - - try - { - // First, try to resolve the absolute path for better UI/logging display - string commandToRun = command; - if (TryFindInPath(command, out string resolvedPath)) - { - commandToRun = resolvedPath; - } - - // Use ExecPath.TryRun which properly handles async output reading and timeouts - if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, - 5000, augmentedPath)) - return false; - - string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); - - // uv/uvx outputs "uv x.y.z" or "uvx x.y.z" - if (output.StartsWith("uvx ") || output.StartsWith("uv ")) - { - // Extract version: "uv 0.9.18" -> "0.9.18" - // Handle extra tokens: "uv 0.9.18 extra" or "uv 0.9.18 (build info)" - int spaceIndex = output.IndexOf(' '); - if (spaceIndex >= 0) - { - var remainder = output.Substring(spaceIndex + 1).Trim(); - int nextSpace = remainder.IndexOf(' '); - int parenIndex = remainder.IndexOf('('); - int endIndex = Math.Min( - nextSpace >= 0 ? nextSpace : int.MaxValue, - parenIndex >= 0 ? parenIndex : int.MaxValue - ); - version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; - fullPath = commandToRun; - return true; + return major > 3 || (major == 3 && minor >= 10); } } } @@ -247,7 +197,7 @@ private string[] GetPathAdditions() }; } - private bool TryFindInPath(string executable, out string fullPath) + protected override bool TryFindInPath(string executable, out string fullPath) { fullPath = ExecPath.FindInPath(executable, BuildAugmentedPath()); return !string.IsNullOrEmpty(fullPath); diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs index 5ae8a1777..229e7f88b 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs @@ -161,57 +161,7 @@ private bool TryValidatePython(string pythonPath, out string version, out string if (TryParseVersion(version, out var major, out var minor)) { - return major > 3 || (major >= 3 && minor >= 10); - } - } - } - catch - { - // Ignore validation errors - } - - return false; - } - - private bool TryValidateUvWithPath(string command, string augmentedPath, out string version, out string fullPath) - { - version = null; - fullPath = null; - - try - { - // First, try to resolve the absolute path for better UI/logging display - string commandToRun = command; - if (TryFindInPath(command, out string resolvedPath)) - { - commandToRun = resolvedPath; - } - - // Use ExecPath.TryRun which properly handles async output reading and timeouts - if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, - 5000, augmentedPath)) - return false; - - string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); - - // uv/uvx outputs "uv x.y.z" or "uvx x.y.z" - if (output.StartsWith("uvx ") || output.StartsWith("uv ")) - { - // Extract version: "uv 0.9.18" -> "0.9.18" - // Handle extra tokens: "uv 0.9.18 extra" or "uv 0.9.18 (build info)" - int spaceIndex = output.IndexOf(' '); - if (spaceIndex >= 0) - { - var remainder = output.Substring(spaceIndex + 1).Trim(); - int nextSpace = remainder.IndexOf(' '); - int parenIndex = remainder.IndexOf('('); - int endIndex = Math.Min( - nextSpace >= 0 ? nextSpace : int.MaxValue, - parenIndex >= 0 ? parenIndex : int.MaxValue - ); - version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; - fullPath = commandToRun; - return true; + return major > 3 || (major == 3 && minor >= 10); } } } @@ -245,7 +195,7 @@ private string[] GetPathAdditions() }; } - private bool TryFindInPath(string executable, out string fullPath) + protected override bool TryFindInPath(string executable, out string fullPath) { fullPath = ExecPath.FindInPath(executable, BuildAugmentedPath()); return !string.IsNullOrEmpty(fullPath); diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs index 77bc93626..fcbb0457d 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/PlatformDetectorBase.cs @@ -1,5 +1,6 @@ using System; using MCPForUnity.Editor.Dependencies.Models; +using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Services; namespace MCPForUnity.Editor.Dependencies.PlatformDetectors @@ -72,5 +73,54 @@ protected bool TryParseVersion(string version, out int major, out int minor) return false; } + // In PlatformDetectorBase.cs + protected bool TryValidateUvWithPath(string command, string augmentedPath, out string version, out string fullPath) + { + version = null; + fullPath = null; + + try + { + string commandToRun = command; + if (TryFindInPath(command, out string resolvedPath)) + { + commandToRun = resolvedPath; + } + + if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, + 5000, augmentedPath)) + return false; + + string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); + + if (output.StartsWith("uvx ") || output.StartsWith("uv ")) + { + int spaceIndex = output.IndexOf(' '); + if (spaceIndex >= 0) + { + var remainder = output.Substring(spaceIndex + 1).Trim(); + int nextSpace = remainder.IndexOf(' '); + int parenIndex = remainder.IndexOf('('); + int endIndex = Math.Min( + nextSpace >= 0 ? nextSpace : int.MaxValue, + parenIndex >= 0 ? parenIndex : int.MaxValue + ); + version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; + fullPath = commandToRun; + return true; + } + } + } + catch + { + // Ignore validation errors + } + + return false; + } + + + // Add abstract method for subclasses to implement + protected abstract bool TryFindInPath(string executable, out string fullPath); } } diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs index f7815eaef..fdf4dde49 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs @@ -125,7 +125,7 @@ public override DependencyStatus DetectUv() status.IsAvailable = true; status.Version = uvVersion; status.Path = uvPath; - status.Details = $"Found uv {uvVersion} at {uvPath}"; // 真实的路径反馈 + status.Details = $"Found uv {uvVersion} at {uvPath}"; return status; } @@ -150,54 +150,6 @@ public override DependencyStatus DetectUv() return status; } - private bool TryValidateUvWithPath(string command, string augmentedPath, out string version, out string fullPath) - { - version = null; - fullPath = null; - - try - { - // First, try to resolve the absolute path for better UI/logging display - string commandToRun = command; - if (TryFindInPath(command, out string resolvedPath)) - { - commandToRun = resolvedPath; - } - - // Use ExecPath.TryRun which properly handles async output reading and timeouts - if (!ExecPath.TryRun(commandToRun, "--version", null, out string stdout, out string stderr, - 5000, augmentedPath)) - return false; - - string output = string.IsNullOrWhiteSpace(stdout) ? stderr.Trim() : stdout.Trim(); - - // uv/uvx outputs "uv x.y.z" or "uvx x.y.z" - if (output.StartsWith("uvx ") || output.StartsWith("uv ")) - { - // Extract version: "uv 0.9.18" -> "0.9.18" - int spaceIndex = output.IndexOf(' '); - if (spaceIndex >= 0) - { - var remainder = output.Substring(spaceIndex + 1).Trim(); - int nextSpace = remainder.IndexOf(' '); - int parenIndex = remainder.IndexOf('('); - int endIndex = Math.Min( - nextSpace >= 0 ? nextSpace : int.MaxValue, - parenIndex >= 0 ? parenIndex : int.MaxValue - ); - version = endIndex < int.MaxValue ? remainder.Substring(0, endIndex).Trim() : remainder; - fullPath = commandToRun; - return true; - } - } - } - catch - { - // Ignore validation errors - } - - return false; - } private bool TryFindPythonViaUv(out string version, out string fullPath) { @@ -268,7 +220,7 @@ private bool TryValidatePython(string pythonPath, out string version, out string if (TryParseVersion(version, out var major, out var minor)) { - return major > 3 || (major >= 3 && minor >= 10); + return major > 3 || (major == 3 && minor >= 10); } } } @@ -280,7 +232,7 @@ private bool TryValidatePython(string pythonPath, out string version, out string return false; } - private bool TryFindInPath(string executable, out string fullPath) + protected override bool TryFindInPath(string executable, out string fullPath) { fullPath = ExecPath.FindInPath(executable, BuildAugmentedPath()); return !string.IsNullOrEmpty(fullPath); @@ -319,12 +271,19 @@ private string[] GetPathAdditions() // Python common paths if (!string.IsNullOrEmpty(localAppData)) additions.Add(Path.Combine(localAppData, "Programs", "Python")); + // Instead of hardcoded versions, enumerate existing directories if (!string.IsNullOrEmpty(programFiles)) { - additions.Add(Path.Combine(programFiles, "Python313")); - additions.Add(Path.Combine(programFiles, "Python312")); - additions.Add(Path.Combine(programFiles, "Python311")); - additions.Add(Path.Combine(programFiles, "Python310")); + try + { + var pythonDirs = Directory.GetDirectories(programFiles, "Python3*") + .OrderByDescending(d => d); // Newest first + foreach (var dir in pythonDirs) + { + additions.Add(dir); + } + } + catch { /* Ignore if directory doesn't exist */ } } // User scripts diff --git a/MCPForUnity/Editor/Services/PathResolverService.cs b/MCPForUnity/Editor/Services/PathResolverService.cs index 1fc26b4d3..ea20136a4 100644 --- a/MCPForUnity/Editor/Services/PathResolverService.cs +++ b/MCPForUnity/Editor/Services/PathResolverService.cs @@ -60,7 +60,7 @@ private static string ResolveUvxFromSystem() foreach (string commandName in commandNames) { - foreach (string candidate in EnumerateUvxCandidates(commandName)) + foreach (string candidate in EnumerateCommandCandidates(commandName)) { if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate)) { @@ -77,69 +77,7 @@ private static string ResolveUvxFromSystem() return null; } - /// - /// Enumerates candidate paths for uv/uvx executables. - /// - private static IEnumerable EnumerateUvxCandidates(string commandName) - { - string exeName = commandName; - - // Priority 1: User-configured PATH (most common scenario from official install scripts) - string pathEnv = Environment.GetEnvironmentVariable("PATH"); - if (!string.IsNullOrEmpty(pathEnv)) - { - foreach (string rawDir in pathEnv.Split(Path.PathSeparator)) - { - if (string.IsNullOrWhiteSpace(rawDir)) continue; - string dir = rawDir.Trim(); - yield return Path.Combine(dir, exeName); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && commandName.EndsWith(".exe")) - { - // Some PATH entries may already contain the file without extension - yield return Path.Combine(dir, commandName.Replace(".exe", "")); - } - } - } - - // Priority 2: User directories - string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - if (!string.IsNullOrEmpty(home)) - { - yield return Path.Combine(home, ".local", "bin", exeName); - yield return Path.Combine(home, ".cargo", "bin", exeName); - } - - // Priority 3: System directories (platform-specific) - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - yield return "/opt/homebrew/bin/" + exeName; - yield return "/usr/local/bin/" + exeName; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - yield return "/usr/local/bin/" + exeName; - yield return "/usr/bin/" + exeName; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - // Priority 4: Windows-specific program directories - string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); - if (!string.IsNullOrEmpty(localAppData)) - { - yield return Path.Combine(localAppData, "Programs", "uv", exeName); - // WinGet creates shim files in this location - yield return Path.Combine(localAppData, "Microsoft", "WinGet", "Links", exeName); - } - - if (!string.IsNullOrEmpty(programFiles)) - { - yield return Path.Combine(programFiles, "uv", exeName); - } - } - } public string GetClaudeCliPath() { @@ -264,7 +202,7 @@ public void ClearClaudeCliPathOverride() /// /// Validates the provided uv executable by running "--version" and parsing the output. /// - /// Absolute or relative path to the uv/uvx executable. + /// Absolute or relative path to the uv/uvx executable. /// Parsed version string if successful. /// True when the executable runs and returns a uvx version string. public bool TryValidateUvxExecutable(string uvxPath, out string version) From 84cb9c6d77af72e289931b983d070a20ca6e47c3 Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 20:50:15 +0800 Subject: [PATCH 13/23] fix: add type handling for Claude Code client in config JSON builder --- MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs b/MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs index ebc82fe3f..676d25677 100644 --- a/MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs +++ b/MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs @@ -77,6 +77,11 @@ private static void PopulateUnityNode(JObject unity, string uvPath, McpClient cl { unity["type"] = "http"; } + // Also add type for Claude Code (uses mcpServers layout but needs type field) + else if (client?.name == "Claude Code") + { + unity["type"] = "http"; + } } else { @@ -110,8 +115,8 @@ private static void PopulateUnityNode(JObject unity, string uvPath, McpClient cl } } - // Remove type for non-VSCode clients - if (!isVSCode && unity["type"] != null) + // Remove type for non-VSCode clients (except Claude Code which needs it) + if (!isVSCode && client?.name != "Claude Code" && unity["type"] != null) { unity.Remove("type"); } From ee330775b5d1e3a7f8c0e2a8d718c51464593f7d Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Mon, 12 Jan 2026 21:10:02 +0800 Subject: [PATCH 14/23] fix: correct command from 'uvx' to 'uv' for Python version listing in WindowsPlatformDetector --- .../Dependencies/PlatformDetectors/WindowsPlatformDetector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs index fdf4dde49..1ce4acf75 100644 --- a/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs +++ b/MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs @@ -160,7 +160,7 @@ private bool TryFindPythonViaUv(out string version, out string fullPath) { string augmentedPath = BuildAugmentedPath(); // Try to list installed python versions via uvx - if (!ExecPath.TryRun("uvx", "python list", null, out string stdout, out string stderr, 5000, augmentedPath)) + if (!ExecPath.TryRun("uv", "python list", null, out string stdout, out string stderr, 5000, augmentedPath)) return false; var lines = stdout.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); From b0eb2747968fb29f60b78db0f200092220cc0e3e Mon Sep 17 00:00:00 2001 From: whatevertogo <1879483647@qq.com> Date: Fri, 16 Jan 2026 16:02:53 +0800 Subject: [PATCH 15/23] feat: Add ActionTrace system for editor event tracking and replay Implement a comprehensive ActionTrace system that captures, stores, and queries Unity editor events for debugging, analysis, and undo/replay capabilities. **Core Features:** - Event capture layer with hooks for Unity editor events - Context tracking with stack and timeline support - Event store with in-memory persistence and query capabilities - Semantic analysis (categorization, scoring, intent inference) - VCS integration for version control context - Editor window with UI for visualizing events - MCP tools for remote query and control **Components Added:** - Capture: ActionTraceEventEmitter, EventFilter, PropertyChangeTracker, UnityEventHooks - Context: ContextStack, ContextTimeline, OperationContext, ContextMapping - Core: EventStore, EditorEvent, EventTypes, ActionTraceSettings, GlobalIdHelper - Query: ActionTraceQuery, EventSummarizer, TransactionAggregator - Semantics: DefaultCategorizer, DefaultEventScorer, DefaultIntentInferrer - UI: ActionTraceEditorWindow with UXML/USS styling - MCP Tools: get_action_trace, get_action_trace_settings, add_action_trace_note, undo_to_sequence **Server-side:** - Python models and resources for ActionTrace - MCP tools for querying events, managing settings, and undoing to sequence Co-Authored-By: Claude Opus 4.5 --- .../Capture/ActionTraceEventEmitter.cs | 443 +++++++++ .../Editor/ActionTrace/Capture/EventFilter.cs | 261 ++++++ .../Capture/PropertyChangeTracker.cs | 397 ++++++++ .../ActionTrace/Capture/SamplingMiddleware.cs | 352 +++++++ .../Capture/SelectionPropertyTracker.cs | 320 +++++++ .../ActionTrace/Capture/UndoGroupManager.cs | 187 ++++ .../ActionTrace/Capture/UnityEventHooks.cs | 308 +++++++ .../ActionTrace/Context/ContextMapping.cs | 60 ++ .../ActionTrace/Context/ContextStack.cs | 263 ++++++ .../ActionTrace/Context/ContextTimeline.cs | 77 ++ .../ActionTrace/Context/OperationContext.cs | 142 +++ .../ActionTrace/Core/ActionTraceSettings.cs | 210 +++++ .../Editor/ActionTrace/Core/EditorEvent.cs | 396 ++++++++ .../Editor/ActionTrace/Core/EventStore.cs | 869 ++++++++++++++++++ .../Editor/ActionTrace/Core/EventTypes.cs | 55 ++ .../Editor/ActionTrace/Core/GlobalIdHelper.cs | 274 ++++++ .../Descriptors/ComponentEventDescriptor.cs | 187 ++++ .../Descriptors/IEventDescriptor.cs | 87 ++ .../ActionTrace/Helpers/ActionTraceHelper.cs | 185 ++++ .../Integration/ManageAssetBridge.cs | 87 ++ .../ActionTrace/Query/ActionTraceQuery.cs | 316 +++++++ .../ActionTrace/Query/EventSummarizer.cs | 257 ++++++ .../Query/TransactionAggregator.cs | 290 ++++++ .../Semantics/DefaultCategorizer.cs | 27 + .../Semantics/DefaultEventScorer.cs | 122 +++ .../Semantics/DefaultIntentInferrer.cs | 160 ++++ .../Semantics/IEventCategorizer.cs | 17 + .../ActionTrace/Semantics/IEventScorer.cs | 20 + .../ActionTrace/Semantics/IIntentInferrer.cs | 22 + .../ActionTrace/VCS/VcsContextProvider.cs | 335 +++++++ .../Editor/Helpers/AssetPathUtility.cs | 2 + .../Editor/MenuItems/MCPForUnityMenu.cs | 6 + .../ActionTrace/ActionTraceViewResource.cs | 549 +++++++++++ .../Transport/Transports/StdioBridgeHost.cs | 144 ++- .../Editor/Tools/ActionTraceSettingsTool.cs | 64 ++ .../Editor/Tools/AddTimelineNoteTool.cs | 172 ++++ .../Editor/Tools/GetActionTraceTool.cs | 86 ++ MCPForUnity/Editor/Tools/ManageAsset.cs | 44 +- .../Editor/Tools/UndoToSequenceTool.cs | 159 ++++ .../Editor/Tools/UndoToSequenceTool.cs.meta | 11 + .../Editor/Windows/ActionTraceEditorWindow.cs | 361 ++++++++ .../Windows/ActionTraceEditorWindow.cs.meta | 11 + .../Windows/ActionTraceEditorWindow.uss | 236 +++++ .../Windows/ActionTraceEditorWindow.uss.meta | 11 + .../Windows/ActionTraceEditorWindow.uxml | 38 + .../Windows/ActionTraceEditorWindow.uxml.meta | 10 + .../Editor/Windows/MCPSetupWindow.uxml.meta | 2 +- Server/src/models/action_trace.py | 125 +++ Server/src/services/resources/action_trace.py | 282 ++++++ .../services/tools/add_action_trace_note.py | 188 ++++ Server/src/services/tools/get_action_trace.py | 114 +++ .../tools/get_action_trace_settings.py | 54 ++ Server/src/services/tools/undo_to_sequence.py | 99 ++ 53 files changed, 9485 insertions(+), 9 deletions(-) create mode 100644 MCPForUnity/Editor/ActionTrace/Capture/ActionTraceEventEmitter.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Capture/EventFilter.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Capture/PropertyChangeTracker.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Capture/SamplingMiddleware.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Capture/SelectionPropertyTracker.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Capture/UndoGroupManager.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Capture/UnityEventHooks.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Context/ContextMapping.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Context/ContextStack.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Context/ContextTimeline.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Context/OperationContext.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Core/ActionTraceSettings.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Core/EditorEvent.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Core/EventStore.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Core/EventTypes.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Core/GlobalIdHelper.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Descriptors/ComponentEventDescriptor.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Descriptors/IEventDescriptor.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Helpers/ActionTraceHelper.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Integration/ManageAssetBridge.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Query/ActionTraceQuery.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Query/EventSummarizer.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Query/TransactionAggregator.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Semantics/DefaultCategorizer.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Semantics/DefaultEventScorer.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Semantics/DefaultIntentInferrer.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Semantics/IEventCategorizer.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Semantics/IEventScorer.cs create mode 100644 MCPForUnity/Editor/ActionTrace/Semantics/IIntentInferrer.cs create mode 100644 MCPForUnity/Editor/ActionTrace/VCS/VcsContextProvider.cs create mode 100644 MCPForUnity/Editor/Resources/ActionTrace/ActionTraceViewResource.cs create mode 100644 MCPForUnity/Editor/Tools/ActionTraceSettingsTool.cs create mode 100644 MCPForUnity/Editor/Tools/AddTimelineNoteTool.cs create mode 100644 MCPForUnity/Editor/Tools/GetActionTraceTool.cs create mode 100644 MCPForUnity/Editor/Tools/UndoToSequenceTool.cs create mode 100644 MCPForUnity/Editor/Tools/UndoToSequenceTool.cs.meta create mode 100644 MCPForUnity/Editor/Windows/ActionTraceEditorWindow.cs create mode 100644 MCPForUnity/Editor/Windows/ActionTraceEditorWindow.cs.meta create mode 100644 MCPForUnity/Editor/Windows/ActionTraceEditorWindow.uss create mode 100644 MCPForUnity/Editor/Windows/ActionTraceEditorWindow.uss.meta create mode 100644 MCPForUnity/Editor/Windows/ActionTraceEditorWindow.uxml create mode 100644 MCPForUnity/Editor/Windows/ActionTraceEditorWindow.uxml.meta create mode 100644 Server/src/models/action_trace.py create mode 100644 Server/src/services/resources/action_trace.py create mode 100644 Server/src/services/tools/add_action_trace_note.py create mode 100644 Server/src/services/tools/get_action_trace.py create mode 100644 Server/src/services/tools/get_action_trace_settings.py create mode 100644 Server/src/services/tools/undo_to_sequence.py diff --git a/MCPForUnity/Editor/ActionTrace/Capture/ActionTraceEventEmitter.cs b/MCPForUnity/Editor/ActionTrace/Capture/ActionTraceEventEmitter.cs new file mode 100644 index 000000000..a656630a5 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Capture/ActionTraceEventEmitter.cs @@ -0,0 +1,443 @@ +using System; +using System.Collections.Generic; +using MCPForUnity.Editor.ActionTrace.Core; +using UnityEngine; + +namespace MCPForUnity.Editor.ActionTrace.Capture +{ + /// + /// Centralized event emission layer for the ActionTrace system. + /// This middle layer decouples the Capture layer (Unity callbacks) from the Data layer (EventStore). + /// + /// Benefits: + /// - EventType constants are managed in one place + /// - Payload schemas are standardized + /// - Event naming changes only require updates here + /// - Capture layer code becomes simpler and more focused + /// + /// Usage: + /// ActionTraceEventEmitter.EmitComponentAdded(component); + /// ActionTraceEventEmitter.EmitAssetImported(assetPath, assetType); + /// + public static class ActionTraceEventEmitter + { + /// + /// Emit a component added event. + /// + public static void EmitComponentAdded(Component component) + { + if (component == null) + { + Debug.LogWarning("[ActionTraceEventEmitter] Attempted to emit ComponentAdded with null component"); + return; + } + + var payload = new Dictionary + { + ["component_type"] = component.GetType().Name, + ["game_object"] = component.gameObject?.name ?? "Unknown" + }; + + EmitEvent(EventTypes.ComponentAdded, component.GetInstanceID().ToString(), payload); + } + + /// + /// Emit a component removed event. + /// + public static void EmitComponentRemoved(Component component) + { + if (component == null) + { + Debug.LogWarning("[ActionTraceEventEmitter] Attempted to emit ComponentRemoved with null component"); + return; + } + + var payload = new Dictionary + { + ["component_type"] = component.GetType().Name, + ["game_object"] = component.gameObject?.name ?? "Unknown" + }; + + EmitEvent(EventTypes.ComponentRemoved, component.GetInstanceID().ToString(), payload); + } + + /// + /// Emit a GameObject created event. + /// + public static void EmitGameObjectCreated(GameObject gameObject) + { + if (gameObject == null) + { + Debug.LogWarning("[ActionTraceEventEmitter] Attempted to emit GameObjectCreated with null GameObject"); + return; + } + + var payload = new Dictionary + { + ["name"] = gameObject.name, + ["instance_id"] = gameObject.GetInstanceID() + }; + + EmitEvent(EventTypes.GameObjectCreated, gameObject.GetInstanceID().ToString(), payload); + } + + /// + /// Emit a GameObject destroyed event. + /// + public static void EmitGameObjectDestroyed(int instanceId, string name) + { + var payload = new Dictionary + { + ["name"] = name, + ["instance_id"] = instanceId + }; + + EmitEvent(EventTypes.GameObjectDestroyed, instanceId.ToString(), payload); + } + + /// + /// Emit a hierarchy changed event. + /// + public static void EmitHierarchyChanged() + { + var payload = new Dictionary + { + ["timestamp"] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }; + + EmitEvent(EventTypes.HierarchyChanged, "Scene", payload); + } + + /// + /// Emit a play mode state changed event. + /// + public static void EmitPlayModeChanged(string state) + { + var payload = new Dictionary + { + ["state"] = state + }; + + EmitEvent(EventTypes.PlayModeChanged, "Editor", payload); + } + + /// + /// Emit a scene saving event. + /// + public static void EmitSceneSaving(string sceneName, string path) + { + var payload = new Dictionary + { + ["scene_name"] = sceneName, + ["path"] = path + }; + + EmitEvent(EventTypes.SceneSaving, sceneName, payload); + } + + /// + /// Emit a scene saved event. + /// + public static void EmitSceneSaved(string sceneName, string path) + { + var payload = new Dictionary + { + ["scene_name"] = sceneName, + ["path"] = path + }; + + EmitEvent(EventTypes.SceneSaved, sceneName, payload); + } + + /// + /// Emit a scene opened event. + /// + public static void EmitSceneOpened(string sceneName, string path, string mode) + { + var payload = new Dictionary + { + ["scene_name"] = sceneName, + ["path"] = path, + ["mode"] = mode + }; + + EmitEvent(EventTypes.SceneOpened, sceneName, payload); + } + + /// + /// Emit a new scene created event. + /// + public static void EmitNewSceneCreated() + { + var payload = new Dictionary + { + ["timestamp"] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }; + + EmitEvent(EventTypes.NewSceneCreated, "Scene", payload); + } + + /// + /// Emit an asset imported event. + /// + public static void EmitAssetImported(string assetPath, string assetType = null) + { + if (string.IsNullOrEmpty(assetPath)) + { + Debug.LogWarning("[ActionTraceEventEmitter] Attempted to emit AssetImported with null or empty path"); + return; + } + + var payload = new Dictionary + { + ["path"] = assetPath, + ["extension"] = System.IO.Path.GetExtension(assetPath) + }; + + if (!string.IsNullOrEmpty(assetType)) + { + payload["asset_type"] = assetType; + } + else + { + // Auto-detect asset type + payload["asset_type"] = DetectAssetType(assetPath); + } + + EmitEvent(EventTypes.AssetImported, assetPath, payload); + } + + /// + /// Emit an asset deleted event. + /// + public static void EmitAssetDeleted(string assetPath) + { + if (string.IsNullOrEmpty(assetPath)) + { + Debug.LogWarning("[ActionTraceEventEmitter] Attempted to emit AssetDeleted with null or empty path"); + return; + } + + var payload = new Dictionary + { + ["path"] = assetPath, + ["extension"] = System.IO.Path.GetExtension(assetPath) + }; + + EmitEvent(EventTypes.AssetDeleted, assetPath, payload); + } + + /// + /// Emit an asset moved event. + /// + public static void EmitAssetMoved(string fromPath, string toPath) + { + if (string.IsNullOrEmpty(toPath)) + { + Debug.LogWarning("[ActionTraceEventEmitter] Attempted to emit AssetMoved with null or empty destination path"); + return; + } + + var payload = new Dictionary + { + ["from_path"] = fromPath ?? string.Empty, + ["to_path"] = toPath, + ["extension"] = System.IO.Path.GetExtension(toPath) + }; + + EmitEvent(EventTypes.AssetMoved, toPath, payload); + } + + /// + /// Emit a script compiled event. + /// + public static void EmitScriptCompiled(int scriptCount, double durationMs) + { + var payload = new Dictionary + { + ["script_count"] = scriptCount, + ["duration_ms"] = durationMs + }; + + EmitEvent(EventTypes.ScriptCompiled, "Scripts", payload); + } + + /// + /// Emit a script compilation failed event. + /// + public static void EmitScriptCompilationFailed(int errorCount, string[] errors) + { + var payload = new Dictionary + { + ["error_count"] = errorCount, + ["errors"] = errors ?? Array.Empty() + }; + + EmitEvent(EventTypes.ScriptCompilationFailed, "Scripts", payload); + } + + /// + /// Emit a build started event. + /// + public static void EmitBuildStarted(string platform, string buildPath) + { + var payload = new Dictionary + { + ["platform"] = platform, + ["build_path"] = buildPath, + ["timestamp"] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }; + + EmitEvent(EventTypes.BuildStarted, "Build", payload); + } + + /// + /// Emit a build completed event. + /// + public static void EmitBuildCompleted(string platform, string buildPath, double durationMs, long sizeBytes) + { + var payload = new Dictionary + { + ["platform"] = platform, + ["build_path"] = buildPath, + ["duration_ms"] = durationMs, + ["size_bytes"] = sizeBytes + }; + + EmitEvent(EventTypes.BuildCompleted, "Build", payload); + } + + /// + /// Emit a build failed event. + /// + public static void EmitBuildFailed(string platform, string errorMessage) + { + var payload = new Dictionary + { + ["platform"] = platform, + ["error_message"] = errorMessage + }; + + EmitEvent(EventTypes.BuildFailed, "Build", payload); + } + + // ======================================================================== + // Asset Modification Events (for ManageAsset integration) + // ======================================================================== + + /// + /// Emit an asset modified event via MCP tool (manage_asset). + /// + public static void EmitAssetModified(string assetPath, string assetType, IReadOnlyDictionary changes) + { + if (string.IsNullOrEmpty(assetPath)) + { + Debug.LogWarning("[ActionTraceEventEmitter] AssetModified with null path"); + return; + } + + var payload = new Dictionary + { + ["path"] = assetPath, + ["asset_type"] = assetType ?? "Unknown", + ["changes"] = changes ?? new Dictionary(), + ["source"] = "mcp_tool" // Indicates this change came from an MCP tool call + }; + + EmitEvent(EventTypes.AssetModified, assetPath, payload); + } + + /// + /// Emit an asset created event via MCP tool (manage_asset). + /// + public static void EmitAssetCreated(string assetPath, string assetType) + { + if (string.IsNullOrEmpty(assetPath)) + { + Debug.LogWarning("[ActionTraceEventEmitter] AssetCreated with null path"); + return; + } + + var payload = new Dictionary + { + ["path"] = assetPath, + ["asset_type"] = assetType ?? "Unknown", + ["source"] = "mcp_tool" + }; + + EmitEvent(EventTypes.AssetCreated, assetPath, payload); + } + + /// + /// Emit an asset deleted event via MCP tool (manage_asset). + /// + public static void EmitAssetDeleted(string assetPath, string assetType) + { + if (string.IsNullOrEmpty(assetPath)) + { + Debug.LogWarning("[ActionTraceEventEmitter] AssetDeleted with null path"); + return; + } + + var payload = new Dictionary + { + ["path"] = assetPath, + ["asset_type"] = assetType ?? "Unknown", + ["source"] = "mcp_tool" + }; + + EmitEvent(EventTypes.AssetDeleted, assetPath, payload); + } + + /// + /// Core event emission method. + /// All events flow through this method, allowing for centralized error handling and logging. + /// + private static void EmitEvent(string eventType, string targetId, Dictionary payload) + { + try + { + var evt = new EditorEvent( + sequence: 0, // Will be assigned by EventStore.Record + timestampUnixMs: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + type: eventType, + targetId: targetId, + payload: payload + ); + + EventStore.Record(evt); + } + catch (Exception ex) + { + Debug.LogWarning($"[ActionTraceEventEmitter] Failed to emit {eventType} event: {ex.Message}"); + } + } + + /// + /// Detect asset type from file extension. + /// + private static string DetectAssetType(string assetPath) + { + if (string.IsNullOrEmpty(assetPath)) + return "unknown"; + + var extension = System.IO.Path.GetExtension(assetPath).ToLower(); + + return extension switch + { + ".cs" => "script", + ".unity" => "scene", + ".prefab" => "prefab", + ".mat" => "material", + ".png" or ".jpg" or ".jpeg" or ".psd" or ".tga" or ".exr" => "texture", + ".wav" or ".mp3" or ".ogg" or ".aif" => "audio", + ".fbx" or ".obj" => "model", + ".anim" => "animation", + ".controller" => "animator_controller", + ".shader" => "shader", + ".xml" or ".json" or ".yaml" => "data", + _ => "unknown" + }; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Capture/EventFilter.cs b/MCPForUnity/Editor/ActionTrace/Capture/EventFilter.cs new file mode 100644 index 000000000..b752fd277 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Capture/EventFilter.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace MCPForUnity.Editor.ActionTrace.Capture +{ + /// + /// First line of defense: Capture-layer blacklist to filter out system junk. + /// + /// Philosophy: Blacklist at capture layer = "Record everything EXCEPT known garbage" + /// - Preserves serendipity: AI can see unexpected but important changes + /// - Protects memory: Prevents EventStore from filling with 29000 junk entries + /// + /// Filtered patterns: + /// - Python cache: __pycache__, *.pyc + /// - Unity internals: Library/, Temp/, obj/, .csproj files + /// - Temporary files: *.tmp, ~$*, .DS_Store + /// - Build artifacts: *.meta (for non-essential assets) + /// + /// Usage: Call EventFilter.IsJunkPath(path) before recording events. + /// + public static class EventFilter + { + // ========== Blacklist Patterns ========== + + /// + /// Directory prefixes that are always filtered (fast path check). + /// Checked before regex for performance. + /// + private static readonly HashSet JunkDirectoryPrefixes = new(StringComparer.OrdinalIgnoreCase) + { + "Library/", + "Temp/", + "obj/", + "Logs/", + "UserSettings/", + "__pycache__/", + ".git/", + ".vs/", + "bin/", + "debug/" + }; + + /// + /// File extension blacklist (fast path check). + /// Extensions with leading dot (e.g., ".pyc") + /// + private static readonly HashSet JunkExtensions = new(StringComparer.OrdinalIgnoreCase) + { + // Python cache + ".pyc", + ".pyo", + ".pyd", + + // Temporary files + ".tmp", + ".temp", + ".cache", + ".bak", + ".swp", + "~$", + + // OS-specific + ".DS_Store", + "Thumbs.db", + "desktop.ini", + + // Build artifacts (Unity-specific) + ".csproj", + ".sln", + ".suo", + ".user", + ".pidb", + ".booproj" + }; + + /// + /// Regex patterns for complex junk path matching. + /// Used when prefix/extension checks aren't enough. + /// + private static readonly List JunkPatterns = new() + { + // Python cache directories (any nested __pycache__) + new Regex(@"__pycache__", RegexOptions.Compiled), + + // IDE temp files (editor recovery files) + new Regex(@"~\$.*", RegexOptions.Compiled), + + // Unity Library subdirectories (deep nested junk) + new Regex(@"Library/[^/]+/.*", RegexOptions.Compiled), + + // Build artifacts with specific patterns + new Regex(@".*\.Assembly-CSharp[^/]*\.dll$", RegexOptions.Compiled), + new Regex(@".*\.Unity\.Editor\.dll$", RegexOptions.Compiled), + + // Temp directories anywhere in path + new Regex(@".*/Temp/.*", RegexOptions.Compiled | RegexOptions.IgnoreCase) + }; + + // ========== Public API ========== + + /// + /// Determines if a given path should be filtered as junk. + /// + /// Uses a tiered checking strategy for performance: + /// 1. Fast prefix check (string StartsWith) + /// 2. Fast extension check (string EndsWith) + /// 3. Regex pattern match (only if needed) + /// + /// Returns: true if the path should be filtered out, false otherwise. + /// + public static bool IsJunkPath(string path) + { + if (string.IsNullOrEmpty(path)) + return false; + + // Fast path 1: Directory prefix check + foreach (var prefix in JunkDirectoryPrefixes) + { + if (path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + return true; + } + + // Fast path 2: File extension check + foreach (var ext in JunkExtensions) + { + if (path.EndsWith(ext, StringComparison.OrdinalIgnoreCase)) + return true; + } + + // Slow path: Regex pattern match + foreach (var pattern in JunkPatterns) + { + if (pattern.IsMatch(path)) + return true; + } + + return false; + } + + /// + /// Checks if an asset path should generate an event. + /// This is a wrapper around IsJunkPath with additional logic for assets. + /// + /// Asset-specific filtering: + /// - .meta files are filtered UNLESS they're for prefabs/scenes (important assets) + /// - Resources folder assets are never filtered + /// + public static bool ShouldTrackAsset(string assetPath) + { + if (string.IsNullOrEmpty(assetPath)) + return true; // Default to tracking for safety + + // Check base junk filter + if (IsJunkPath(assetPath)) + return false; + + // Special handling for .meta files + if (assetPath.EndsWith(".meta", StringComparison.OrdinalIgnoreCase)) + { + // Track .meta for important asset types + string basePath = assetPath.Substring(0, assetPath.Length - 5); // Remove ".meta" + + // Track if it's a prefab or scene + if (basePath.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase) || + basePath.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Skip .meta for everything else + return false; + } + + // Never filter assets in Resources folder (user-accessible at runtime) + if (assetPath.Contains("/Resources/", StringComparison.OrdinalIgnoreCase)) + return true; + + return true; // Default: track the asset + } + + /// + /// Checks if a GameObject name should be filtered. + /// Unity creates many internal GameObjects that are rarely interesting. + /// + /// Filtered patterns: + /// - "Collider" + number (generated colliders) + /// - "GameObject" + number (unnamed objects) + /// - Unity editor internals + /// + public static bool IsJunkGameObject(string name) + { + if (string.IsNullOrEmpty(name)) + return false; + + // Unity-generated colliders + if (Regex.IsMatch(name, @"^Collider\d+$", RegexOptions.IgnoreCase)) + return true; + + // Unnamed GameObjects + if (Regex.IsMatch(name, @"^GameObject\d+$", RegexOptions.IgnoreCase)) + return true; + + // Editor-only objects + if (name.StartsWith("EditorOnly", StringComparison.OrdinalIgnoreCase)) + return true; + + return false; + } + + // ========== Runtime Configuration ========== + + /// + /// Adds a custom junk directory prefix at runtime. + /// Useful for project-specific filtering rules. + /// + public static void AddJunkDirectoryPrefix(string prefix) + { + if (!string.IsNullOrEmpty(prefix)) + JunkDirectoryPrefixes.Add(prefix); + } + + /// + /// Adds a custom junk file extension at runtime. + /// + public static void AddJunkExtension(string extension) + { + if (!string.IsNullOrEmpty(extension)) + { + string ext = extension.StartsWith(".") ? extension : $".{extension}"; + JunkExtensions.Add(ext); + } + } + + /// + /// Adds a custom regex pattern for junk path matching. + /// + public static void AddJunkPattern(string regexPattern) + { + if (!string.IsNullOrEmpty(regexPattern)) + { + JunkPatterns.Add(new Regex(regexPattern, RegexOptions.Compiled)); + } + } + + // ========== Diagnostic Info ========== + + /// + /// Gets diagnostic information about the filter configuration. + /// Useful for debugging and ensuring filters are working as expected. + /// + public static string GetDiagnosticInfo() + { + return $"EventFilter Configuration:\n" + + $" - Directory Prefixes: {JunkDirectoryPrefixes.Count}\n" + + $" - Junk Extensions: {JunkExtensions.Count}\n" + + $" - Regex Patterns: {JunkPatterns.Count}\n" + + $" - Total Checks: 3-tier (prefix → extension → regex)"; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Capture/PropertyChangeTracker.cs b/MCPForUnity/Editor/ActionTrace/Capture/PropertyChangeTracker.cs new file mode 100644 index 000000000..2306d06e8 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Capture/PropertyChangeTracker.cs @@ -0,0 +1,397 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using Newtonsoft.Json; +using MCPForUnity.Editor.ActionTrace.Core; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Helpers; + +namespace MCPForUnity.Editor.ActionTrace.Capture +{ + /// + /// High-performance property change tracker with debouncing. + /// + /// Captures Unity property modifications via Undo.postprocessModifications, + /// applies debouncing to merge rapid changes (e.g., Slider drag), and records + /// PropertyModified events to the ActionTrace EventStore. + /// + /// Key features: + /// - Uses EditorApplication.update for consistent periodic flushing + /// - Object pooling to reduce GC pressure + /// - Cache size limits to prevent unbounded memory growth + /// - Cross-session stable IDs via GlobalIdHelper + /// + /// Reuses existing Helpers: + /// - GlobalIdHelper.ToGlobalIdString() for stable object IDs + /// - UnityJsonSerializer.Instance for Unity type serialization + /// + public static class PropertyChangeTracker + { + // Configuration + private const long DebounceWindowMs = 500; // Debounce window in milliseconds + private const int MaxPendingEntries = 256; // Max pending changes before forced flush + + // State + private static readonly Dictionary _pendingChanges = new(); + private static readonly Stack _objectPool = new(); + private static readonly HashSet _removedKeys = new(); + private static double _lastFlushTime; + + /// + /// Initializes the property tracker and subscribes to Unity callbacks. + /// + static PropertyChangeTracker() + { + Undo.postprocessModifications += mods => ProcessModifications(mods); + ScheduleNextFlush(); + } + + /// + /// Schedules a delayed flush check using delayCall. + /// This is more efficient than per-frame update checks, as it only runs when needed. + /// + private static void ScheduleNextFlush() + { + EditorApplication.delayCall += () => + { + var currentTime = EditorApplication.timeSinceStartup * 1000; + + if (currentTime - _lastFlushTime >= DebounceWindowMs) + { + FlushPendingChanges(); + _lastFlushTime = currentTime; + } + + // Reschedule for next check + ScheduleNextFlush(); + }; + } + + /// + /// Called by Unity when properties are modified via Undo system. + /// This includes Inspector changes, Scene view manipulations, etc. + /// Returns the modifications unchanged to allow Undo system to continue. + /// + private static UndoPropertyModification[] ProcessModifications(UndoPropertyModification[] modifications) + { + if (modifications == null || modifications.Length == 0) + return modifications; + + foreach (var undoMod in modifications) + { + // UndoPropertyModification contains the PropertyModification and value changes + // Try to extract target and property path + var target = GetTargetFromUndoMod(undoMod); + if (target == null) + continue; + + var propertyPath = GetPropertyPathFromUndoMod(undoMod); + if (string.IsNullOrEmpty(propertyPath)) + continue; + + // Filter out Unity internal properties + if (propertyPath.StartsWith("m_Script") || + propertyPath.StartsWith("m_EditorClassIdentifier") || + propertyPath.StartsWith("m_ObjectHideFlags")) + { + continue; + } + + // Generate stable unique key + string globalId = GlobalIdHelper.ToGlobalIdString(target); + if (string.IsNullOrEmpty(globalId)) + continue; + + string uniqueKey = $"{globalId}:{propertyPath}"; + + // Get the current value (not the path) + var currentValue = GetCurrentValueFromUndoMod(undoMod); + + // Check if we already have a pending change for this property + if (_pendingChanges.TryGetValue(uniqueKey, out var pending)) + { + // Update existing pending change + // Note: Must reassign to dictionary since PendingPropertyChange is a struct + pending.EndValue = FormatPropertyValue(currentValue); + pending.ChangeCount++; + pending.LastUpdateMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + _pendingChanges[uniqueKey] = pending; + } + else + { + // Enforce cache limit to prevent unbounded growth + if (_pendingChanges.Count >= MaxPendingEntries) + { + // Force flush before adding new entry + FlushPendingChanges(); + } + + // Create new pending change (use object pool if available) + var change = AcquirePendingChange(); + change.GlobalId = globalId; + change.TargetName = target.name; + change.ComponentType = target.GetType().Name; + change.PropertyPath = propertyPath; + // Record the start value from the previous value reported by Undo system + var prev = GetPreviousValueFromUndoMod(undoMod); + change.StartValue = FormatPropertyValue(prev); + change.EndValue = FormatPropertyValue(currentValue); + change.PropertyType = GetPropertyTypeName(currentValue); + change.ChangeCount = 1; + change.LastUpdateMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + + _pendingChanges[uniqueKey] = change; + } + } + + return modifications; + } + + #region UndoPropertyModification Helpers (via UndoReflectionHelper) + + /// + /// Extracts the previous value from an UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static object GetPreviousValueFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetPreviousValue(undoMod); + } + + /// + /// Extracts the target object from an UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static UnityEngine.Object GetTargetFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetTarget(undoMod); + } + + /// + /// Extracts the property path from an UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static string GetPropertyPathFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetPropertyPath(undoMod); + } + + /// + /// Extracts the current value from an UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static object GetCurrentValueFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetCurrentValue(undoMod); + } + + #endregion + + /// + /// Formats a property value for JSON storage. + /// + /// Reuses existing Helpers: + /// - UnityJsonSerializer.Instance for Vector3, Color, Quaternion, etc. + /// + private static string FormatPropertyValue(object value) + { + if (value == null) + return "null"; + + try + { + // Use UnityJsonSerializer for proper Unity type serialization + using (var writer = new System.IO.StringWriter()) + { + UnityJsonSerializer.Instance.Serialize(writer, value); + return writer.ToString(); + } + } + catch (Exception) + { + // Fallback to ToString() if serialization fails + return value.ToString(); + } + } + + /// + /// Gets the type name of a property value for the event payload. + /// + private static string GetPropertyTypeName(object value) + { + if (value == null) + return "null"; + + Type type = value.GetType(); + + // Use friendly names for common Unity types + if (type == typeof(float) || type == typeof(int) || type == typeof(double)) + return "Number"; + if (type == typeof(bool)) + return "Boolean"; + if (type == typeof(string)) + return "String"; + if (type == typeof(Vector2) || type == typeof(Vector3) || type == typeof(Vector4)) + return type.Name; + if (type == typeof(Quaternion)) + return "Quaternion"; + if (type == typeof(Color)) + return "Color"; + if (type == typeof(Rect)) + return "Rect"; + + return type.Name; + } + + /// + /// Flushes all pending property changes that have exceeded the debounce window. + /// Called periodically via EditorApplication.update. + /// + private static void FlushPendingChanges() + { + if (_pendingChanges.Count == 0) + return; + + long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + + foreach (var kvp in _pendingChanges) + { + // Check if entry has expired (no updates for DebounceWindowMs) + if (nowMs - kvp.Value.LastUpdateMs >= DebounceWindowMs) + { + // Record the PropertyModified event + RecordPropertyModifiedEvent(kvp.Value); + + // Return to object pool + ReturnPendingChange(kvp.Value); + + // Mark for removal + _removedKeys.Add(kvp.Key); + } + } + + // Batch remove expired entries + foreach (var key in _removedKeys) + { + _pendingChanges.Remove(key); + } + _removedKeys.Clear(); + } + + /// + /// Records a PropertyModified event to the ActionTrace EventStore. + /// + private static void RecordPropertyModifiedEvent(in PendingPropertyChange change) + { + var payload = new Dictionary + { + ["target_name"] = change.TargetName, + ["component_type"] = change.ComponentType, + ["property_path"] = change.PropertyPath, + ["start_value"] = change.StartValue, + ["end_value"] = change.EndValue, + ["value_type"] = change.PropertyType, + ["change_count"] = change.ChangeCount + }; + + var evt = new EditorEvent( + sequence: 0, // Will be assigned by EventStore.Record() + timestampUnixMs: change.LastUpdateMs, + type: EventTypes.PropertyModified, + targetId: change.GlobalId, + payload: payload + ); + + EventStore.Record(evt); + } + + /// + /// Acquires a PendingPropertyChange from the object pool. + /// Creates a new instance if pool is empty. + /// + private static PendingPropertyChange AcquirePendingChange() + { + if (_objectPool.Count > 0) + { + var change = _objectPool.Pop(); + // Reset is handled by ReturnPendingChange before pushing back + return change; + } + return new PendingPropertyChange(); + } + + /// + /// Returns a PendingPropertyChange to the object pool after clearing its data. + /// + private static void ReturnPendingChange(in PendingPropertyChange change) + { + // Create a copy to clear (structs are value types) + var cleared = change; + cleared.Reset(); + _objectPool.Push(cleared); + } + + /// + /// Forces an immediate flush of all pending changes. + /// Useful for shutdown or before critical operations. + /// + public static void ForceFlush() + { + FlushPendingChanges(); + } + + /// + /// Gets the current count of pending changes. + /// Useful for debugging and monitoring. + /// + public static int PendingCount => _pendingChanges.Count; + + /// + /// Clears all pending changes without recording them. + /// Useful for testing or error recovery. + /// + public static void ClearPending() + { + foreach (var kvp in _pendingChanges) + { + ReturnPendingChange(kvp.Value); + } + _pendingChanges.Clear(); + } + } + + /// + /// Represents a property change that is pending debounce. + /// Uses a struct to reduce GC pressure (stored on stack when possible). + /// + public struct PendingPropertyChange + { + public string GlobalId; // Cross-session stable object ID + public string TargetName; // Object name (e.g., "Main Camera") + public string ComponentType; // Component type (e.g., "Light") + public string PropertyPath; // Serialized property path (e.g., "m_Intensity") + public string StartValue; // JSON formatted start value + public string EndValue; // JSON formatted end value + public string PropertyType; // Type name of the property value + public int ChangeCount; // Number of changes merged (for Slider drag) + public long LastUpdateMs; // Last update timestamp for debouncing + + /// + /// Resets all fields to default values. + /// Called before returning the struct to the object pool. + /// + public void Reset() + { + GlobalId = null; + TargetName = null; + ComponentType = null; + PropertyPath = null; + StartValue = null; + EndValue = null; + PropertyType = null; + ChangeCount = 0; + LastUpdateMs = 0; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Capture/SamplingMiddleware.cs b/MCPForUnity/Editor/ActionTrace/Capture/SamplingMiddleware.cs new file mode 100644 index 000000000..cd4d2817d --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Capture/SamplingMiddleware.cs @@ -0,0 +1,352 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Capture +{ + /// + /// Smart sampling middleware to prevent event floods in high-frequency scenarios. + /// + /// Protects the ActionTrace from event storms (e.g., rapid Slider dragging, + /// continuous Hierarchy changes) by applying configurable sampling strategies. + /// + /// Sampling modes: + /// - None: No filtering, record all events + /// - Throttle: Only record the first event within the window + /// - Debounce: Only record the last event within the window + /// - DebounceByKey: Only record the last event per unique key within the window + /// + /// Reuses existing infrastructure: + /// - GlobalIdHelper.ToGlobalIdString() for stable keys + /// - EditorEvent payload for event metadata + /// + public static class SamplingMiddleware + { + // Configuration + private const int MaxSampleCache = 128; // Max pending samples before forced cleanup + private const long CleanupAgeMs = 2000; // Cleanup samples older than 2 seconds + + // State + // Thread-safe dictionary to prevent race conditions in multi-threaded scenarios + private static readonly ConcurrentDictionary _pendingSamples = new(); + private static readonly List _expiredKeys = new(); + private static long _lastCleanupTime; + + /// + /// Determines whether an event should be recorded based on configured sampling strategies. + /// Returns true if the event should be recorded, false if it should be filtered out. + /// + /// This method is called by event emitters before recording to EventStore. + /// Implements a three-stage filtering pipeline: + /// 1. Blacklist (EventFilter) - filters system junk + /// 2. Sampling strategy - merges duplicate events + /// 3. Cache management - prevents unbounded growth + /// + public static bool ShouldRecord(EditorEvent evt) + { + if (evt == null) + return false; + + // ========== Stage 1: Blacklist Filtering (L1) ========== + // Check if this event's target is known junk before any other processing + if (evt.Type == EventTypes.AssetImported || + evt.Type == EventTypes.AssetMoved || + evt.Type == EventTypes.AssetDeleted) + { + // For asset events, check the path (stored in TargetId or payload) + string assetPath = evt.TargetId; + if (string.IsNullOrEmpty(assetPath) && evt.Payload.TryGetValue("path", out var pathVal)) + { + assetPath = pathVal?.ToString(); + } + + if (!string.IsNullOrEmpty(assetPath) && !EventFilter.ShouldTrackAsset(assetPath)) + { + return false; // Filtered by blacklist + } + } + + // ========== Stage 2: Sampling Strategy Check (L2) ========== + // No sampling strategy configured - record all events + if (!SamplingConfig.Strategies.TryGetValue(evt.Type, out var strategy)) + return true; + + // Strategy is None - record all events of this type + if (strategy.Mode == SamplingMode.None) + return true; + + // Generate the sampling key based on mode + string key = GenerateSamplingKey(evt, strategy.Mode); + + if (string.IsNullOrEmpty(key)) + return true; + + long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + + // Periodic cleanup of expired samples (runs every ~1 second) + if (nowMs - _lastCleanupTime > 1000) + { + CleanupExpiredSamples(nowMs); + _lastCleanupTime = nowMs; + } + + // Check if we have a pending sample for this key + if (_pendingSamples.TryGetValue(key, out var pending)) + { + // Sample is still within the window + if (nowMs - pending.TimestampMs <= strategy.WindowMs) + { + switch (strategy.Mode) + { + case SamplingMode.Throttle: + // Throttle: Drop all events after the first in the window + return false; + + case SamplingMode.Debounce: + case SamplingMode.DebounceByKey: + // Debounce: Keep only the last event in the window + // Note: Must update the dictionary entry since PendingSample is a struct + _pendingSamples[key] = new PendingSample + { + Event = evt, + TimestampMs = nowMs + }; + return false; + } + } + + // Window expired - remove old entry + _pendingSamples.TryRemove(key, out _); + } + + // Enforce cache limit to prevent unbounded growth + if (_pendingSamples.Count >= MaxSampleCache) + { + CleanupExpiredSamples(nowMs); + + // If still over limit after cleanup, force remove oldest entry + if (_pendingSamples.Count >= MaxSampleCache) + { + var oldest = _pendingSamples.OrderBy(kvp => kvp.Value.TimestampMs).FirstOrDefault(); + if (!string.IsNullOrEmpty(oldest.Key)) + { + _pendingSamples.TryRemove(oldest.Key, out _); + } + } + } + + // Add new pending sample + _pendingSamples[key] = new PendingSample + { + Event = evt, + TimestampMs = nowMs + }; + + return true; + } + + /// + /// Generates the sampling key based on the sampling mode. + /// - Throttle/Debounce: Key by event type only + /// - DebounceByKey: Key by event type + target (GlobalId) + /// + private static string GenerateSamplingKey(EditorEvent evt, SamplingMode mode) + { + // For DebounceByKey, include TargetId to distinguish different objects + if (mode == SamplingMode.DebounceByKey) + { + return $"{evt.Type}:{evt.TargetId}"; + } + + // For Throttle and Debounce, key by type only + return evt.Type; + } + + /// + /// Removes expired samples from the cache. + /// Samples older than CleanupAgeMs are removed. + /// + private static void CleanupExpiredSamples(long nowMs) + { + _expiredKeys.Clear(); + + foreach (var kvp in _pendingSamples) + { + if (nowMs - kvp.Value.TimestampMs > CleanupAgeMs) + { + _expiredKeys.Add(kvp.Key); + } + } + + foreach (var key in _expiredKeys) + { + _pendingSamples.TryRemove(key, out _); + } + } + + /// + /// Forces an immediate flush of all pending samples. + /// Returns the events that were pending (useful for shutdown). + /// + public static List FlushPending() + { + var result = _pendingSamples.Values.Select(p => p.Event).ToList(); + _pendingSamples.Clear(); + return result; + } + + /// + /// Gets the current count of pending samples. + /// Useful for debugging and monitoring. + /// + public static int PendingCount => _pendingSamples.Count; + + /// + /// Diagnostic helper: returns a snapshot of pending sampling keys. + /// Safe to call from editor threads; best-effort snapshot. + /// + public static IReadOnlyList GetPendingKeysSnapshot() + { + return _pendingSamples.Keys.ToList(); + } + + /// + /// Clears all pending samples without recording them. + /// Useful for testing or error recovery. + /// + public static void ClearPending() + { + _pendingSamples.Clear(); + } + } + + /// + /// Configurable sampling strategy for a specific event type. + /// + public class SamplingStrategy + { + /// + /// The sampling mode to apply. + /// + public SamplingMode Mode { get; set; } + + /// + /// Time window in milliseconds. + /// - Throttle: Only first event within this window is recorded + /// - Debounce/DebounceByKey: Only last event within this window is recorded + /// + public long WindowMs { get; set; } + + public SamplingStrategy(SamplingMode mode = SamplingMode.None, long windowMs = 1000) + { + Mode = mode; + WindowMs = windowMs; + } + } + + /// + /// Sampling mode determines how events are filtered. + /// + public enum SamplingMode + { + /// No filtering - record all events + None, + + /// Throttle - only record the first event within the window + Throttle, + + /// Debounce - only record the last event within the window (per type) + Debounce, + + /// DebounceByKey - only record the last event per key within the window + DebounceByKey + } + + /// + /// Static configuration for sampling strategies. + /// Event types can be registered with their desired sampling behavior. + /// + public static class SamplingConfig + { + /// + /// Default sampling strategies for common event types. + /// Configured to prevent event floods while preserving important data. + /// + public static readonly Dictionary Strategies = new() + { + // Hierarchy changes: Throttle to 1 event per second + { + EventTypes.HierarchyChanged, + new SamplingStrategy(SamplingMode.Throttle, 1000) + }, + + // PropertyModified handling removed here to avoid double-debounce when + // PropertyChangeTracker already implements a dedicated debounce window. + // If desired, SamplingConfig.SetStrategy(EventTypes.PropertyModified, ...) can + // be used at runtime to re-enable middleware-level sampling. + + // Component/GameObject events: No sampling (always record) + // ComponentAdded, ComponentRemoved, GameObjectCreated, GameObjectDestroyed + // are intentionally not in this dictionary, so they default to None + + // Play mode changes: No sampling (record all) + // PlayModeChanged is not in this dictionary + + // Scene events: No sampling (record all) + // SceneSaving, SceneSaved, SceneOpened, NewSceneCreated are not in this dictionary + + // Build events: No sampling (record all) + // BuildStarted, BuildCompleted, BuildFailed are not in this dictionary + }; + + /// + /// Adds or updates a sampling strategy for an event type. + /// + public static void SetStrategy(string eventType, SamplingMode mode, long windowMs = 1000) + { + Strategies[eventType] = new SamplingStrategy(mode, windowMs); + } + + /// + /// Removes the sampling strategy for an event type (reverts to None). + /// + public static void RemoveStrategy(string eventType) + { + Strategies.Remove(eventType); + } + + /// + /// Gets the sampling strategy for an event type, or null if not configured. + /// + public static SamplingStrategy GetStrategy(string eventType) + { + return Strategies.TryGetValue(eventType, out var strategy) ? strategy : null; + } + + /// + /// Checks if an event type has a sampling strategy configured. + /// + public static bool HasStrategy(string eventType) + { + return Strategies.ContainsKey(eventType); + } + } + + /// + /// Represents a pending sample that is being filtered. + /// + public struct PendingSample + { + /// + /// The event being held for potential recording. + /// + public EditorEvent Event; + + /// + /// Timestamp when this sample was last updated. + /// + public long TimestampMs; + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Capture/SelectionPropertyTracker.cs b/MCPForUnity/Editor/ActionTrace/Capture/SelectionPropertyTracker.cs new file mode 100644 index 000000000..7810ce620 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Capture/SelectionPropertyTracker.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using Newtonsoft.Json; +using MCPForUnity.Editor.ActionTrace.Core; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Helpers; + +namespace MCPForUnity.Editor.ActionTrace.Capture +{ + /// + /// Tracks property modifications made to the currently selected object. + /// + /// Combines Selection.selectionChanged with Undo.postprocessModifications + /// to provide rich context about which object's properties are being modified. + /// + /// Key features: + /// - Detects if property modification targets the currently selected object + /// - Records SelectionPropertyModified events with selection context + /// - Reuses existing helpers (GlobalIdHelper, UnityJsonSerializer) + /// - Lightweight event-based design (no polling) + /// + [InitializeOnLoad] + public static class SelectionPropertyTracker + { + // Current selection state + private static string _currentSelectionGlobalId; + private static string _currentSelectionName; + private static string _currentSelectionType; + private static string _currentSelectionPath; + + static SelectionPropertyTracker() + { + // Initialize with current selection + UpdateSelectionState(); + + // Monitor selection changes + Selection.selectionChanged += OnSelectionChanged; + + // Monitor property modifications + Undo.postprocessModifications += OnPropertyModified; + + McpLog.Debug("[SelectionPropertyTracker] Initialized"); + } + + /// + /// Updates the cached selection state when selection changes. + /// + private static void OnSelectionChanged() + { + UpdateSelectionState(); + } + + /// + /// Updates the cached selection state from current Selection.activeObject. + /// + private static void UpdateSelectionState() + { + var activeObject = Selection.activeObject; + if (activeObject == null) + { + _currentSelectionGlobalId = null; + _currentSelectionName = null; + _currentSelectionType = null; + _currentSelectionPath = null; + return; + } + + _currentSelectionGlobalId = GlobalIdHelper.ToGlobalIdString(activeObject); + _currentSelectionName = activeObject.name; + _currentSelectionType = activeObject.GetType().Name; + + // Get path for GameObject/Component selections + if (activeObject is GameObject go) + { + _currentSelectionPath = GetGameObjectPath(go); + } + else if (activeObject is Component comp) + { + _currentSelectionPath = GetGameObjectPath(comp.gameObject); + } + else + { + _currentSelectionPath = AssetDatabase.GetAssetPath(activeObject); + } + } + + /// + /// Called by Unity when properties are modified via Undo system. + /// Checks if the modification targets the currently selected object. + /// + private static UndoPropertyModification[] OnPropertyModified(UndoPropertyModification[] modifications) + { + if (modifications == null || modifications.Length == 0) + return modifications; + + McpLog.Debug($"[SelectionPropertyTracker] OnPropertyModified: {modifications.Length} mods, selectionId={_currentSelectionGlobalId}"); + + // Skip if no valid selection + if (string.IsNullOrEmpty(_currentSelectionGlobalId)) + return modifications; + + foreach (var undoMod in modifications) + { + var target = GetTargetFromUndoMod(undoMod); + if (target == null) + { + continue; + } + + // Check if this modification targets the currently selected object or its components + string targetGlobalId = GlobalIdHelper.ToGlobalIdString(target); + bool isMatch = IsTargetMatchSelection(target, targetGlobalId); + // McpLog.Debug($"[SelectionPropertyTracker] targetId={targetGlobalId}, selectionId={_currentSelectionGlobalId}, match={isMatch}"); + if (!isMatch) + continue; + + var propertyPath = GetPropertyPathFromUndoMod(undoMod); + if (string.IsNullOrEmpty(propertyPath)) + continue; + + // Filter out Unity internal properties + if (IsInternalProperty(propertyPath)) + continue; + + // Record the SelectionPropertyModified event + // McpLog.Debug($"[SelectionPropertyTracker] MATCH! Recording event for {target.name}.{propertyPath}"); + RecordSelectionPropertyModified(undoMod, target, propertyPath); + } + + return modifications; + } + + /// + /// Records a SelectionPropertyModified event to the ActionTrace EventStore. + /// + private static void RecordSelectionPropertyModified(UndoPropertyModification undoMod, UnityEngine.Object target, string propertyPath) + { + var currentValue = GetCurrentValueFromUndoMod(undoMod); + var prevValue = GetPreviousValueFromUndoMod(undoMod); + + var payload = new Dictionary + { + ["target_name"] = target.name, + ["component_type"] = target.GetType().Name, + ["property_path"] = propertyPath, + ["start_value"] = FormatPropertyValue(prevValue), + ["end_value"] = FormatPropertyValue(currentValue), + ["value_type"] = GetPropertyTypeName(currentValue), + ["selection_context"] = new Dictionary + { + ["selection_name"] = _currentSelectionName, + ["selection_type"] = _currentSelectionType, + ["selection_path"] = _currentSelectionPath ?? string.Empty + } + }; + + var evt = new EditorEvent( + sequence: 0, + timestampUnixMs: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + type: EventTypes.SelectionPropertyModified, + targetId: _currentSelectionGlobalId, + payload: payload + ); + + EventStore.Record(evt); + } + + #region UndoPropertyModification Helpers (via UndoReflectionHelper) + + /// + /// Extracts the target object from UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static UnityEngine.Object GetTargetFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetTarget(undoMod); + } + + /// + /// Extracts the property path from UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static string GetPropertyPathFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetPropertyPath(undoMod); + } + + /// + /// Extracts the current value from UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static object GetCurrentValueFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetCurrentValue(undoMod); + } + + /// + /// Extracts the previous value from UndoPropertyModification. + /// Uses shared UndoReflectionHelper for reflection logic. + /// + private static object GetPreviousValueFromUndoMod(UndoPropertyModification undoMod) + { + return UndoReflectionHelper.GetPreviousValue(undoMod); + } + + #endregion + + /// + /// Checks if the modified target matches the current selection. + /// Handles both direct GameObject matches and Component-on-selected-GameObject matches. + /// + private static bool IsTargetMatchSelection(UnityEngine.Object target, string targetGlobalId) + { + // Direct match + if (targetGlobalId == _currentSelectionGlobalId) + return true; + + // If target is a Component, check if its owner GameObject matches the selection + if (target is Component comp) + { + string gameObjectId = GlobalIdHelper.ToGlobalIdString(comp.gameObject); + if (gameObjectId == _currentSelectionGlobalId) + return true; + } + + return false; + } + + #region Property Formatting Helpers + + /// + /// Checks if a property is a Unity internal property that should be ignored. + /// + private static bool IsInternalProperty(string propertyPath) + { + if (string.IsNullOrEmpty(propertyPath)) + return false; + + return propertyPath.StartsWith("m_Script") || + propertyPath.StartsWith("m_EditorClassIdentifier") || + propertyPath.StartsWith("m_ObjectHideFlags"); + } + + /// + /// Formats a property value for JSON storage. + /// Reuses UnityJsonSerializer.Instance for proper Unity type serialization. + /// + private static string FormatPropertyValue(object value) + { + if (value == null) + return "null"; + + try + { + using (var writer = new System.IO.StringWriter()) + { + UnityJsonSerializer.Instance.Serialize(writer, value); + return writer.ToString(); + } + } + catch (Exception) + { + return value.ToString(); + } + } + + /// + /// Gets the type name of a property value for the event payload. + /// + private static string GetPropertyTypeName(object value) + { + if (value == null) + return "null"; + + Type type = value.GetType(); + + if (type == typeof(float) || type == typeof(int) || type == typeof(double)) + return "Number"; + if (type == typeof(bool)) + return "Boolean"; + if (type == typeof(string)) + return "String"; + if (type == typeof(Vector2) || type == typeof(Vector3) || type == typeof(Vector4)) + return type.Name; + if (type == typeof(Quaternion)) + return "Quaternion"; + if (type == typeof(Color)) + return "Color"; + if (type == typeof(Rect)) + return "Rect"; + + return type.Name; + } + + /// + /// Gets the full Hierarchy path for a GameObject. + /// Example: "Level1/Player/Arm/Hand" + /// + private static string GetGameObjectPath(GameObject obj) + { + if (obj == null) + return "Unknown"; + + var path = obj.name; + var parent = obj.transform.parent; + + while (parent != null) + { + path = $"{parent.name}/{path}"; + parent = parent.parent; + } + + return path; + } + + #endregion + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Capture/UndoGroupManager.cs b/MCPForUnity/Editor/ActionTrace/Capture/UndoGroupManager.cs new file mode 100644 index 000000000..3523722b7 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Capture/UndoGroupManager.cs @@ -0,0 +1,187 @@ +using System; +using UnityEditor; +using MCPForUnity.Editor.ActionTrace.Helpers; + +namespace MCPForUnity.Editor.ActionTrace.Capture +{ + /// + /// Manages Unity Undo grouping for AI tool calls. + /// + /// Purpose: + /// - Groups multiple Undo operations into a single logical transaction + /// - Enables one Ctrl+Z to undo an entire AI tool call + /// - Works with TransactionAggregator to provide atomic operation semantics + /// + /// Usage (from ActionTrace-enhancements.md line 320-336): + /// UndoGroupManager.BeginToolCall("manage_gameobject", "abc123"); + /// // ... perform operations ... + /// UndoGroupManager.EndToolCall(); + /// + /// Integration with add_ActionTrace_note: + /// - When AI adds a note with is_transaction_end=true, + /// automatically collapses Undo operations since BeginToolCall + /// + /// Architecture notes: + /// - This is an optional enhancement for better UX + /// - Does not affect ActionTrace event recording + /// - Independent of OperationContext (tracks Undo state, not tool context) + /// + public static class UndoGroupManager + { + // State tracking + private static string _currentToolName; + private static string _currentToolCallId; + private static int _currentUndoGroupStart = -1; + private static bool _isInToolCall = false; + + /// + /// Starts a new Undo group for a tool call. + /// + /// Call this at the beginning of an AI tool operation. + /// All subsequent Undo operations will be grouped under this name. + /// + /// Parameters: + /// toolName: Name of the tool (e.g., "manage_gameobject") + /// toolCallId: Unique identifier for this tool call (UUID) + /// + /// Example: + /// UndoGroupManager.BeginToolCall("manage_gameobject", "abc-123-def"); + /// + public static void BeginToolCall(string toolName, string toolCallId) + { + if (string.IsNullOrEmpty(toolName)) + { + UnityEngine.Debug.LogWarning("[UndoGroupManager] BeginToolCall called with null toolName"); + toolName = "AI Operation"; + } + + // Set the current Undo group name + // This name will appear in the Undo history (e.g., "Ctrl+Z AI: Create Player") + Undo.SetCurrentGroupName($"AI: {ActionTraceHelper.FormatToolName(toolName)}"); + + // Record the group start position for later collapsing + _currentUndoGroupStart = Undo.GetCurrentGroup(); + _currentToolName = toolName; + _currentToolCallId = toolCallId; + _isInToolCall = true; + + UnityEngine.Debug.Log($"[UndoGroupManager] BeginToolCall: {toolName} (group {_currentUndoGroupStart})"); + } + + /// + /// Ends the current Undo group and collapses all operations. + /// + /// Call this at the end of an AI tool operation. + /// All Undo operations since BeginToolCall will be merged into one. + /// + /// Example: + /// UndoGroupManager.EndToolCall(); + /// + /// After this, user can press Ctrl+Z once to undo the entire tool call. + /// + public static void EndToolCall() + { + if (!_isInToolCall) + { + UnityEngine.Debug.LogWarning("[UndoGroupManager] EndToolCall called without matching BeginToolCall"); + return; + } + + if (_currentUndoGroupStart >= 0) + { + // Collapse all Undo operations since BeginToolCall into one group + Undo.CollapseUndoOperations(_currentUndoGroupStart); + + UnityEngine.Debug.Log($"[UndoGroupManager] EndToolCall: {_currentToolName} (collapsed from group {_currentUndoGroupStart})"); + } + + // Reset state + _currentToolName = null; + _currentToolCallId = null; + _currentUndoGroupStart = -1; + _isInToolCall = false; + } + + /// + /// Checks if currently in a tool call. + /// + public static bool IsInToolCall => _isInToolCall; + + /// + /// Gets the current tool name (if in a tool call). + /// Returns null if not in a tool call. + /// + public static string CurrentToolName => _currentToolName; + + /// + /// Gets the current tool call ID (if in a tool call). + /// Returns null if not in a tool call. + /// + public static string CurrentToolCallId => _currentToolCallId; + + /// + /// Gets the current Undo group start position. + /// Returns -1 if not in a tool call. + /// + public static int CurrentUndoGroupStart => _currentUndoGroupStart; + + /// + /// Clears the current tool call state without collapsing. + /// + /// Use this for error recovery when a tool call fails partway through. + /// Does NOT collapse Undo operations (unlike EndToolCall). + /// + public static void AbortToolCall() + { + if (!_isInToolCall) + return; + + UnityEngine.Debug.LogWarning($"[UndoGroupManager] AbortToolCall: {_currentToolName} (group {_currentUndoGroupStart})"); + + // Reset state without collapsing + _currentToolName = null; + _currentToolCallId = null; + _currentUndoGroupStart = -1; + _isInToolCall = false; + } + + /// + /// Integration with add_ActionTrace_note. + /// + /// When AI adds a note with is_transaction_end=true, + /// automatically end the current Undo group. + /// + /// This allows the AI to mark completion of a logical transaction. + /// + /// Parameters: + /// note: The note text (will be used as Undo group name if in tool call) + /// isTransactionEnd: If true, calls EndToolCall() + /// + /// Returns: + /// The Undo group name that was set (or current group name if not ending) + /// + public static string HandleActionTraceNote(string note, bool isTransactionEnd) + { + string groupName; + + if (_isInToolCall) + { + // Use the AI note as the final Undo group name + groupName = $"AI: {note}"; + Undo.SetCurrentGroupName(groupName); + + if (isTransactionEnd) + { + EndToolCall(); + } + + return groupName; + } + + // Not in a tool call - just set the Undo name + groupName = $"AI: {note}"; + Undo.SetCurrentGroupName(groupName); + return groupName; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Capture/UnityEventHooks.cs b/MCPForUnity/Editor/ActionTrace/Capture/UnityEventHooks.cs new file mode 100644 index 000000000..113cd4c53 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Capture/UnityEventHooks.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections.Generic; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Core; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace MCPForUnity.Editor.ActionTrace.Capture +{ + /// + /// Captures Unity editor events and records them to the EventStore. + /// Uses debouncing to avoid spamming for rapid successive changes. + /// Updated to use EventType constants for type safety. + /// + [InitializeOnLoad] + public static class UnityEventHooks + { + private static DateTime _lastHierarchyChange; + private static readonly object _lock = new(); + + static UnityEventHooks() + { + // Monitor GameObject/component creation + ObjectFactory.componentWasAdded += OnComponentAdded; + + // Monitor hierarchy changes (with debouncing) + EditorApplication.hierarchyChanged += OnHierarchyChanged; + + // Monitor selection changes (P2.3: Selection Tracking) + Selection.selectionChanged += OnSelectionChanged; + + // Monitor play mode state changes + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + + // Monitor scene saving - use EditorSceneManager, not EditorApplication + EditorSceneManager.sceneSaving += OnSceneSaving; + + // Monitor scene opening - use EditorSceneManager, not EditorApplication + EditorSceneManager.sceneOpened += OnSceneOpened; + } + + private static void OnComponentAdded(Component component) + { + if (component == null) return; + + var payload = new Dictionary + { + ["component_type"] = component.GetType().Name, + ["game_object"] = component.gameObject?.name ?? "Unknown" + }; + + RecordEvent(EventTypes.ComponentAdded, component.GetInstanceID().ToString(), payload); + } + + /// + /// Handles Selection changes (P2.3: Selection Tracking). + /// Records what the user is currently focusing on for AI context awareness. + /// + private static void OnSelectionChanged() + { + if (Selection.activeObject == null) + return; + + var payload = new Dictionary + { + ["name"] = Selection.activeObject.name, + ["type"] = Selection.activeObject.GetType().Name, + ["instance_id"] = Selection.activeObject.GetInstanceID() + }; + + // Add path for GameObject/Component selections + if (Selection.activeObject is GameObject go) + { + payload["path"] = GetGameObjectPath(go); + } + else if (Selection.activeObject is Component comp) + { + payload["path"] = GetGameObjectPath(comp.gameObject); + payload["component_type"] = comp.GetType().Name; + } + + RecordEvent(EventTypes.SelectionChanged, Selection.activeObject.GetInstanceID().ToString(), payload); + } + + /// + /// Gets the full Hierarchy path for a GameObject. + /// Example: "Level1/Player/Arm/Hand" + /// + private static string GetGameObjectPath(GameObject obj) + { + if (obj == null) + return "Unknown"; + + var path = obj.name; + var parent = obj.transform.parent; + + while (parent != null) + { + path = $"{parent.name}/{path}"; + parent = parent.parent; + } + + return path; + } + + private static void OnHierarchyChanged() + { + var now = DateTime.Now; + lock (_lock) + { + // Debounce: ignore changes within 200ms of the last one + if ((now - _lastHierarchyChange).TotalMilliseconds < 200) + { + return; + } + _lastHierarchyChange = now; + } + + RecordEvent(EventTypes.HierarchyChanged, "Scene", new Dictionary()); + } + + private static void OnPlayModeStateChanged(PlayModeStateChange state) + { + var payload = new Dictionary + { + ["state"] = state.ToString() + }; + + RecordEvent(EventTypes.PlayModeChanged, "Editor", payload); + } + + private static void OnSceneSaving(Scene scene, string path) + { + var payload = new Dictionary + { + ["scene_name"] = scene.name, + ["path"] = path + }; + + RecordEvent(EventTypes.SceneSaving, scene.name, payload); + } + + private static void OnSceneOpened(Scene scene, OpenSceneMode mode) + { + var payload = new Dictionary + { + ["scene_name"] = scene.name, + ["path"] = scene.path, + ["mode"] = mode.ToString() + }; + + RecordEvent(EventTypes.SceneOpened, scene.name, payload); + } + + private static void RecordEvent(string type, string targetId, Dictionary payload) + { + try + { + // Inject VCS context into all recorded events + var vcsContext = VCS.VcsContextProvider.GetCurrentContext(); + payload["vcs_context"] = vcsContext.ToDictionary(); + + // Inject Undo Group ID for undo_to_sequence functionality (P2.4) + int currentUndoGroup = Undo.GetCurrentGroup(); + payload["undo_group"] = currentUndoGroup; + + var evt = new EditorEvent( + sequence: 0, // Will be assigned by EventStore.Record + timestampUnixMs: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + type: type, + targetId: targetId, + payload: payload + ); + + // Apply sampling middleware to protect from event floods. + // If sampling filters this event, do not record it here. + if (SamplingMiddleware.ShouldRecord(evt)) + { + Core.EventStore.Record(evt); + } + } + catch (Exception ex) + { + McpLog.Warn($"[UnityEventHooks] Failed to record event: {ex.Message}"); + } + } + } + + /// + /// Asset postprocessor for tracking asset changes. + /// Uses Unity's AssetPostprocessor callback pattern, not event subscription. + /// Updated to use EventType constants for type safety. + /// + internal sealed class AssetChangePostprocessor : AssetPostprocessor + { + private static void OnPostprocessAllAssets( + string[] importedAssets, + string[] deletedAssets, + string[] movedAssets, + string[] movedFromAssetPaths) + { + // ========== Imported Assets ========== + foreach (var assetPath in importedAssets) + { + if (string.IsNullOrEmpty(assetPath)) continue; + + // L1 Blacklist: Skip junk assets before creating events + if (!EventFilter.ShouldTrackAsset(assetPath)) + continue; + + var payload = new Dictionary + { + ["path"] = assetPath, + ["extension"] = System.IO.Path.GetExtension(assetPath) + }; + + // Determine asset type + if (assetPath.EndsWith(".cs")) + { + payload["asset_type"] = "script"; + } + else if (assetPath.EndsWith(".unity")) + { + payload["asset_type"] = "scene"; + } + else if (assetPath.EndsWith(".prefab")) + { + payload["asset_type"] = "prefab"; + } + else if (assetPath.EndsWith(".mat")) + { + payload["asset_type"] = "material"; + } + + RecordEvent(EventTypes.AssetImported, assetPath, payload); + } + + // ========== Deleted Assets ========== + foreach (var assetPath in deletedAssets) + { + if (string.IsNullOrEmpty(assetPath)) continue; + + // L1 Blacklist: Skip junk assets + if (!EventFilter.ShouldTrackAsset(assetPath)) + continue; + + var payload = new Dictionary + { + ["path"] = assetPath + }; + + RecordEvent(EventTypes.AssetDeleted, assetPath, payload); + } + + // ========== Moved Assets ========== + for (int i = 0; i < movedAssets.Length; i++) + { + if (string.IsNullOrEmpty(movedAssets[i])) continue; + + var fromPath = i < movedFromAssetPaths.Length ? movedFromAssetPaths[i] : ""; + + // L1 Blacklist: Skip junk assets + if (!EventFilter.ShouldTrackAsset(movedAssets[i])) + continue; + + var payload = new Dictionary + { + ["to_path"] = movedAssets[i], + ["from_path"] = fromPath + }; + + RecordEvent(EventTypes.AssetMoved, movedAssets[i], payload); + } + } + + private static void RecordEvent(string type, string targetId, Dictionary payload) + { + try + { + // Inject VCS context into all recorded events + var vcsContext = VCS.VcsContextProvider.GetCurrentContext(); + payload["vcs_context"] = vcsContext.ToDictionary(); + + // Inject Undo Group ID for undo_to_sequence functionality (P2.4) + int currentUndoGroup = Undo.GetCurrentGroup(); + payload["undo_group"] = currentUndoGroup; + + var evt = new EditorEvent( + sequence: 0, + timestampUnixMs: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + type: type, + targetId: targetId, + payload: payload + ); + + // AssetPostprocessor callbacks run on main thread but outside update loop. + // Use delayCall to defer recording to main thread update, avoiding thread warnings. + UnityEditor.EditorApplication.delayCall += () => Core.EventStore.Record(evt); + } + catch (Exception ex) + { + Debug.LogWarning($"[AssetChangePostprocessor] Failed to record event: {ex.Message}"); + } + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Context/ContextMapping.cs b/MCPForUnity/Editor/ActionTrace/Context/ContextMapping.cs new file mode 100644 index 000000000..f79698943 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Context/ContextMapping.cs @@ -0,0 +1,60 @@ +using System; + +namespace MCPForUnity.Editor.ActionTrace.Context +{ + /// + /// Side-Table mapping between events and contexts. + /// This keeps the "bedrock" event layer pure while allowing context association. + /// Events remain immutable - context is stored separately. + /// + /// Design principle: + /// - EditorEvent = immutable facts (what happened) + /// - ContextMapping = mutable metadata (who did it, why) + /// + public sealed class ContextMapping : IEquatable + { + /// + /// The sequence number of the associated EditorEvent. + /// + public long EventSequence { get; } + + /// + /// The unique identifier of the OperationContext. + /// + public Guid ContextId { get; } + + public ContextMapping(long eventSequence, Guid contextId) + { + EventSequence = eventSequence; + ContextId = contextId; + } + + public bool Equals(ContextMapping other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return EventSequence == other.EventSequence + && ContextId.Equals(other.ContextId); + } + + public override bool Equals(object obj) + { + return Equals(obj as ContextMapping); + } + + public override int GetHashCode() + { + return HashCode.Combine(EventSequence, ContextId); + } + + public static bool operator ==(ContextMapping left, ContextMapping right) + { + return Equals(left, right); + } + + public static bool operator !=(ContextMapping left, ContextMapping right) + { + return !Equals(left, right); + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Context/ContextStack.cs b/MCPForUnity/Editor/ActionTrace/Context/ContextStack.cs new file mode 100644 index 000000000..72acc56ea --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Context/ContextStack.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using MCPForUnity.Editor.Helpers; + +namespace MCPForUnity.Editor.ActionTrace.Context +{ + /// + /// Thread-local operation context stack for tracking operation source. + /// This is a "light marker" system - it doesn't control flow, + /// it only annotates operations with their source context. + /// + /// Design principle: + /// - Stack is lightweight (just references) + /// - No blocking operations + /// - Fast push/pop for using() pattern + /// - Thread-safe via ThreadStatic (each thread has its own stack) + /// + /// Threading model: + /// - Each thread maintains its own isolated context stack + /// - Unity Editor callbacks (delayCall, AssetPostprocessor) may run on different threads + /// - Context does not leak across thread boundaries + /// - Debug mode logs thread ID for diagnostics + /// + /// TODO-A Better clear strategy + public static class ContextStack + { + [ThreadStatic] + private static Stack _stack; + + [ThreadStatic] + private static int _threadId; // For debug diagnostics + + /// + /// Get the current operation context (if any). + /// Returns null if no context is active. + /// + public static OperationContext Current + { + get + { + var stack = GetStack(); + return stack.Count > 0 ? stack.Peek() : null; + } + } + + /// + /// Get the depth of the context stack. + /// + public static int Depth + { + get + { + return GetStack().Count; + } + } + + /// + /// Get the thread-local stack, initializing if necessary. + /// + private static Stack GetStack() + { + if (_stack == null) + { + _stack = new Stack(); + _threadId = Thread.CurrentThread.ManagedThreadId; + +#if DEBUG + McpLog.Info( + $"[ContextStack] Initialized new stack for thread {_threadId}"); +#endif + } + return _stack; + } + + /// + /// Push a context onto the stack. + /// Returns a disposable that will pop the context when disposed. + /// + public static IDisposable Push(OperationContext context) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + var stack = GetStack(); + stack.Push(context); + +#if DEBUG + UnityEngine.Debug.Log( + $"[ContextStack] Push context {context.ContextId} on thread {_threadId}, depth: {stack.Count}"); +#endif + + return new ContextDisposable(context); + } + + /// + /// Pop the top context from the stack. + /// Validates that the popped context matches the expected one. + /// + public static bool Pop(OperationContext expectedContext) + { + var stack = GetStack(); + if (stack.Count == 0) + { +#if DEBUG + UnityEngine.Debug.LogWarning( + $"[ContextStack] Pop on empty stack (thread {_threadId}, expected {expectedContext?.ContextId})"); +#endif + return false; + } + + var top = stack.Peek(); + if (top.Equals(expectedContext)) + { + stack.Pop(); + +#if DEBUG + UnityEngine.Debug.Log( + $"[ContextStack] Pop context {expectedContext.ContextId} on thread {_threadId}, remaining depth: {stack.Count}"); +#endif + + return true; + } + + // Stack mismatch - this indicates a programming error + // Improvement: Only remove mismatched context, preserve valid ones + var currentThreadId = Thread.CurrentThread.ManagedThreadId; + var stackSnapshot = string.Join(", ", stack.Select(c => c.ContextId.ToString().Substring(0, 8))); + + // Try to find and remove the mismatched context + var tempStack = new Stack(); + bool found = false; + + while (stack.Count > 0) + { + var item = stack.Pop(); + if (item.Equals(expectedContext)) + { + found = true; + break; + } + tempStack.Push(item); + } + + // Restore valid contexts + while (tempStack.Count > 0) + { + stack.Push(tempStack.Pop()); + } + + if (!found) + { + UnityEngine.Debug.LogWarning( + $"[ContextStack] Expected context {expectedContext.ContextId} not found on thread {currentThreadId}\n" + + $" Stack snapshot: [{stackSnapshot}]\n" + + $" No changes made to stack."); + } + + return found; + } + + /// + /// Mark the current operation as an AI operation. + /// Returns a disposable for automatic cleanup. + /// + /// Usage: + /// using (ContextStack.MarkAsAiOperation("claude-opus")) + /// { + /// // All events recorded here are tagged as AI + /// } + /// + public static IDisposable MarkAsAiOperation(string agentId, string sessionId = null) + { + var context = OperationContextFactory.CreateAiContext(agentId, sessionId); + return Push(context); + } + + /// + /// Mark the current operation as a human operation. + /// Returns a disposable for automatic cleanup. + /// + public static IDisposable MarkAsHumanOperation(string sessionId = null) + { + var context = OperationContextFactory.CreateHumanContext(sessionId); + return Push(context); + } + + /// + /// Mark the current operation as a system operation. + /// Returns a disposable for automatic cleanup. + /// + public static IDisposable MarkAsSystemOperation(string sessionId = null) + { + var context = OperationContextFactory.CreateSystemContext(sessionId); + return Push(context); + } + + /// + /// Check if the current context is from an AI source. + /// + public static bool IsAiOperation + { + get + { + var current = Current; + return current != null && current.Source == OperationSource.AI; + } + } + + /// + /// Get the current agent ID (if AI operation). + /// + public static string CurrentAgentId + { + get + { + var current = Current; + return current?.Source == OperationSource.AI ? current.AgentId : null; + } + } + + /// + /// Clear the entire stack (for error recovery). + /// Thread-safe: only clears the current thread's stack. + /// + public static void Clear() + { + var stack = GetStack(); + stack.Clear(); + +#if DEBUG + UnityEngine.Debug.Log( + $"[ContextStack] Cleared stack on thread {Thread.CurrentThread.ManagedThreadId}"); +#endif + } + + /// + /// Disposable that pops the context when disposed. + /// Validates the context matches to prevent stack corruption. + /// + private sealed class ContextDisposable : IDisposable + { + private readonly OperationContext _context; + private bool _disposed; + + public ContextDisposable(OperationContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public void Dispose() + { + if (_disposed) + return; + + Pop(_context); + _disposed = true; + } + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Context/ContextTimeline.cs b/MCPForUnity/Editor/ActionTrace/Context/ContextTimeline.cs new file mode 100644 index 000000000..349c1bedf --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Context/ContextTimeline.cs @@ -0,0 +1,77 @@ +using UnityEditor; +using MCPForUnity.Editor.ActionTrace.Core; +using System; +using MCPForUnity.Editor.Helpers; + +namespace MCPForUnity.Editor.ActionTrace.Context +{ + /// + /// Automatically associates events with the current context. + /// Subscribes to EventStore.EventRecorded and creates mappings. + /// + /// This is the "glue" that connects the event layer to the context layer. + /// Events are immutable - context is attached via side-table mapping. + /// + /// Threading safety: + /// - EventStore.EventRecorded is raised via delayCall (next editor update) + /// - This callback runs on main thread, safe to call AddContextMapping + /// - AddContextMapping is thread-safe (uses _queryLock internally) + /// + [InitializeOnLoad] + public static class ContextTrace + { + static ContextTrace() + { + // Subscribe to event recording + // EventStore already uses delayCall, so this won't cause re-entrancy + Core.EventStore.EventRecorded += OnEventRecorded; + } + + /// + /// Called when an event is recorded. + /// Associates the event with the current context (if any). + /// + private static void OnEventRecorded(EditorEvent @event) + { + try + { + var currentContext = ContextStack.Current; + if (currentContext != null) + { + // Create the mapping + var mapping = new ContextMapping( + eventSequence: @event.Sequence, + contextId: currentContext.ContextId + ); + + // Store in EventStore's side-table + Core.EventStore.AddContextMapping(mapping); + } + } + catch (System.Exception ex) + { + McpLog.Warn( + $"[ContextTrace] Failed to create context mapping: {ex.Message}"); + } + } + + /// + /// Manually associate an event with a context. + /// Use this for batch operations or deferred association. + /// + public static void Associate(long eventSequence, Guid contextId) + { + var mapping = new ContextMapping(eventSequence, contextId); + Core.EventStore.AddContextMapping(mapping); + } + + /// + /// Remove all mappings for a specific context. + /// Useful for cleanup after a batch operation. + /// + public static void DisassociateContext(Guid contextId) + { + Core.EventStore.RemoveContextMappings(contextId); + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Context/OperationContext.cs b/MCPForUnity/Editor/ActionTrace/Context/OperationContext.cs new file mode 100644 index 000000000..50be3ab14 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Context/OperationContext.cs @@ -0,0 +1,142 @@ +using System; + +namespace MCPForUnity.Editor.ActionTrace.Context +{ + /// + /// Operation source type. + /// Human: Manual editor operation + /// AI: AI-assisted operation (Claude, Cursor, etc.) + /// System: Automated system operation + /// + public enum OperationSource + { + Human, + AI, + System + } + + /// + /// Immutable context metadata for an operation. + /// This is a "light marker" - minimal data that doesn't interfere with event storage. + /// Associated with events via Side-Table (ContextMapping), not embedded in EditorEvent. + /// + public sealed class OperationContext : IEquatable + { + /// + /// Unique identifier for this context instance. + /// + public Guid ContextId { get; } + + /// + /// Source of the operation (Human, AI, or System). + /// + public OperationSource Source { get; } + + /// + /// Agent identifier (e.g., "claude-opus", "cursor", "vscode-copilot"). + /// Null for Human/System operations. + /// + public string AgentId { get; } + + /// + /// Operation start time in UTC milliseconds since Unix epoch. + /// + public long StartTimeUnixMs { get; } + + /// + /// Optional user/session identifier for correlation. + /// + public string SessionId { get; } + + public OperationContext( + Guid contextId, + OperationSource source, + string agentId = null, + long startTimeUnixMs = 0, + string sessionId = null) + { + ContextId = contextId; + Source = source; + AgentId = agentId; + StartTimeUnixMs = startTimeUnixMs > 0 + ? startTimeUnixMs + : DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + SessionId = sessionId; + } + + public bool Equals(OperationContext other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return ContextId.Equals(other.ContextId); + } + + public override bool Equals(object obj) + { + return Equals(obj as OperationContext); + } + + public override int GetHashCode() + { + return ContextId.GetHashCode(); + } + + public static bool operator ==(OperationContext left, OperationContext right) + { + return Equals(left, right); + } + + public static bool operator !=(OperationContext left, OperationContext right) + { + return !Equals(left, right); + } + } + + /// + /// Factory for creating common context types. + /// + public static class OperationContextFactory + { + /// + /// Create a context for an AI operation. + /// + public static OperationContext CreateAiContext(string agentId, string sessionId = null) + { + return new OperationContext( + Guid.NewGuid(), + OperationSource.AI, + agentId, + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + sessionId + ); + } + + /// + /// Create a context for a human operation. + /// + public static OperationContext CreateHumanContext(string sessionId = null) + { + return new OperationContext( + Guid.NewGuid(), + OperationSource.Human, + null, + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + sessionId + ); + } + + /// + /// Create a context for a system operation. + /// + public static OperationContext CreateSystemContext(string sessionId = null) + { + return new OperationContext( + Guid.NewGuid(), + OperationSource.System, + null, + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + sessionId + ); + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Core/ActionTraceSettings.cs b/MCPForUnity/Editor/ActionTrace/Core/ActionTraceSettings.cs new file mode 100644 index 000000000..54c392418 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Core/ActionTraceSettings.cs @@ -0,0 +1,210 @@ +using System; +using UnityEngine; +using UnityEditor; + +namespace MCPForUnity.Editor.ActionTrace.Core +{ + /// + /// Persistent settings for the ActionTrace system. + /// These settings control event filtering behavior at the store level, + /// not just UI display - events below the threshold may not be recorded. + /// + public class ActionTraceSettings : ScriptableObject + { + private const string SettingsPath = "Assets/ActionTraceSettings.asset"; + + private static ActionTraceSettings _instance; + + /// + /// Gets or creates the singleton settings instance. + /// + public static ActionTraceSettings Instance + { + get + { + if (_instance == null) + { + _instance = LoadSettings(); + if (_instance == null) + { + _instance = CreateSettings(); + } + } + return _instance; + } + } + + /// + /// Minimum importance threshold for recording events. + /// Events with importance below this value will be ignored at the store level. + /// Range: 0.0 (all events) to 1.0 (only critical events) + /// + public float MinImportanceForRecording = 0.4f; + + /// + /// Event merging time window in milliseconds. + /// High-frequency events within this window will be merged. + /// + public int MergeWindowMs = 100; + + /// + /// Maximum number of events to keep in the store. + /// + public int MaxEvents = 1000; + + /// + /// Number of "hot" events to keep with full payload. + /// Older events are dehydrated (payload = null). + /// + public int HotEventCount = 100; + + /// + /// Enable event merging for high-frequency events. + /// + public bool EnableEventMerging = true; + + /// + /// Event types to track (empty = all types). + /// Specific event types can be disabled here. + /// + public string[] DisabledEventTypes = Array.Empty(); + + /// + /// Time window for transaction aggregation in milliseconds. + /// Events within this window are grouped into a single logical transaction. + /// Used by TransactionAggregator when no ToolCallId information exists. + /// + public int TransactionWindowMs = 2000; + + /// + /// Reloads settings from disk. + /// Call this after manually modifying the settings asset. + /// + public static void Reload() + { + _instance = LoadSettings(); + } + + private static ActionTraceSettings LoadSettings() + { + return AssetDatabase.LoadAssetAtPath(SettingsPath); + } + + private static ActionTraceSettings CreateSettings() + { + var settings = CreateInstance(); + AssetDatabase.CreateAsset(settings, SettingsPath); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + Debug.Log($"[ActionTraceSettings] Created new settings at {SettingsPath}"); + return settings; + } + + /// + /// Saves the current settings to disk. + /// + public void Save() + { + EditorUtility.SetDirty(this); + AssetDatabase.SaveAssets(); + Debug.Log("[ActionTraceSettings] Settings saved"); + } + + /// + /// Shows the settings inspector window. + /// + public static void ShowSettingsWindow() + { + Selection.activeObject = Instance; + EditorApplication.ExecuteMenuItem("Window/General/Inspector"); + } + } + + /// + /// Custom editor for ActionTraceSettings. + /// Provides a clean UI for modifying ActionTrace settings. + /// + [CustomEditor(typeof(ActionTraceSettings))] + public class ActionTraceSettingsEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + GUILayout.Label("ActionTrace Settings", EditorStyles.boldLabel); + EditorGUILayout.HelpBox( + "These settings control event recording behavior at the store level.\n" + + "Changes affect which events are captured, not just UI display.", + MessageType.Info); + EditorGUILayout.Space(); + + SerializedObject so = serializedObject; + so.Update(); + + EditorGUILayout.LabelField("Event Filtering", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(so.FindProperty(nameof(ActionTraceSettings.MinImportanceForRecording)), + new GUIContent("Min Importance for Recording", + "Events below this importance will NOT be recorded. 0.0 = all events, 0.4 = medium+, 0.7 = high+")); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Event Merging", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(so.FindProperty(nameof(ActionTraceSettings.EnableEventMerging)), + new GUIContent("Enable Event Merging", "Merge high-frequency events within time window")); + EditorGUILayout.PropertyField(so.FindProperty(nameof(ActionTraceSettings.MergeWindowMs)), + new GUIContent("Merge Window (ms)", "Time window for event merging")); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Storage Limits", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(so.FindProperty(nameof(ActionTraceSettings.MaxEvents)), + new GUIContent("Max Events", "Maximum number of events to store")); + EditorGUILayout.PropertyField(so.FindProperty(nameof(ActionTraceSettings.HotEventCount)), + new GUIContent("Hot Events Count", "Keep full payload for latest N events")); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Transaction Aggregation", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(so.FindProperty(nameof(ActionTraceSettings.TransactionWindowMs)), + new GUIContent("Transaction Window (ms)", "Time window for grouping events into logical transactions")); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Quick Presets", EditorStyles.boldLabel); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("All Events (Debug)")) + { + SetImportance(0f); + } + if (GUILayout.Button("Low+")) + { + SetImportance(0f); + } + if (GUILayout.Button("Medium+")) + { + SetImportance(0.4f); + } + if (GUILayout.Button("High+")) + { + SetImportance(0.7f); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + + so.ApplyModifiedProperties(); + + if (GUI.changed) + { + (target as ActionTraceSettings)?.Save(); + } + } + + private void SetImportance(float value) + { + SerializedProperty prop = serializedObject.FindProperty(nameof(ActionTraceSettings.MinImportanceForRecording)); + prop.floatValue = value; + serializedObject.ApplyModifiedProperties(); + (target as ActionTraceSettings)?.Save(); + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Core/EditorEvent.cs b/MCPForUnity/Editor/ActionTrace/Core/EditorEvent.cs new file mode 100644 index 000000000..9670cdfc2 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Core/EditorEvent.cs @@ -0,0 +1,396 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using MCPForUnity.Editor.Helpers; +using Newtonsoft.Json; + +namespace MCPForUnity.Editor.ActionTrace.Core +{ + /// + /// Immutable class representing a single editor event. + /// This is the "bedrock" layer - once written, never modified. + /// + /// Memory optimization (Pruning): + /// - Payload can be null for old events (automatically dehydrated by EventStore) + /// - PrecomputedSummary is always available, even when Payload is null + /// - This reduces memory from ~10KB to ~100 bytes per old event + /// + /// Payload serialization constraints: + /// - Only JSON-serializable types are allowed: string, number (int/long/float/double/decimal), + /// bool, null, array of these types, or Dictionary with these value types. + /// - Unsupported types (UnityEngine.Object, MonoBehaviour, etc.) are logged and skipped. + /// + public sealed class EditorEvent : IEquatable + { + // Limits to protect memory usage for payloads + private const int MaxStringLength = 512; // truncate long strings + private const int MaxCollectionItems = 64; // max items to keep in arrays/lists + private const int MaxSanitizeDepth = 4; // prevent deep recursion + + /// + /// Monotonically increasing sequence number for ordering. + /// JSON property name: "sequence" + /// + [JsonProperty("sequence")] + public long Sequence { get; } + + /// + /// UTC timestamp in milliseconds since Unix epoch. + /// JSON property name: "timestamp_unix_ms" + /// + [JsonProperty("timestamp_unix_ms")] + public long TimestampUnixMs { get; } + + /// + /// Event type identifier (e.g., "GameObjectCreated", "ComponentAdded"). + /// JSON property name: "type" + /// + [JsonProperty("type")] + public string Type { get; } + + /// + /// Target identifier (instance ID, asset GUID, or file path). + /// JSON property name: "target_id" + /// + [JsonProperty("target_id")] + public string TargetId { get; } + + /// + /// Event payload containing additional context data. + /// All values are guaranteed to be JSON-serializable. + /// + /// Can be null for old events (after dehydration). + /// Use PrecomputedSummary instead when Payload is null. + /// JSON property name: "payload" + /// + [JsonProperty("payload")] + public IReadOnlyDictionary Payload { get; } + + /// + /// Precomputed summary for this event. + /// Always available, even when Payload has been dehydrated (null). + /// JSON property name: "precomputed_summary" + /// + [JsonProperty("precomputed_summary")] + public string PrecomputedSummary { get; private set; } + + /// + /// Whether this event's payload has been dehydrated (trimmed to save memory). + /// JSON property name: "is_dehydrated" + /// + [JsonProperty("is_dehydrated")] + public bool IsDehydrated { get; private set; } + + public EditorEvent( + long sequence, + long timestampUnixMs, + string type, + string targetId, + IReadOnlyDictionary payload) + { + Sequence = sequence; + TimestampUnixMs = timestampUnixMs; + Type = type ?? throw new ArgumentNullException(nameof(type)); + TargetId = targetId ?? throw new ArgumentNullException(nameof(targetId)); + + // Validate and sanitize payload to ensure JSON-serializable types + if (payload == null) + { + Payload = null; + PrecomputedSummary = null; + IsDehydrated = false; + } + else + { + Payload = SanitizePayload(payload, type); + PrecomputedSummary = null; // Will be computed on first access or dehydration + IsDehydrated = false; + } + } + + /// + /// Constructor for creating a dehydrated (trimmed) event. + /// Used internally by EventStore for memory optimization. + /// + private EditorEvent( + long sequence, + long timestampUnixMs, + string type, + string targetId, + string precomputedSummary) + { + Sequence = sequence; + TimestampUnixMs = timestampUnixMs; + Type = type; + TargetId = targetId; + Payload = null; // Dehydrated - no payload + PrecomputedSummary = precomputedSummary; + IsDehydrated = true; + } + + /// + /// Dehydrate this event to save memory. + /// - Generates PrecomputedSummary from Payload + /// - Sets Payload to null (releasing large objects) + /// - Marks event as IsDehydrated + /// + /// Call this when event becomes "cold" (old but still needed for history). + /// + public EditorEvent Dehydrate() + { + if (IsDehydrated) + return this; // Already dehydrated + + // Generate summary if not already computed + var summary = PrecomputedSummary ?? ComputeSummary(); + + // Return new dehydrated event (immutable pattern) + return new EditorEvent( + Sequence, + TimestampUnixMs, + Type, + TargetId, + summary + ); + } + + /// + /// Get the precomputed summary, computing it if necessary. + /// This is lazy-evaluated to avoid unnecessary computation. + /// + public string GetSummary() + { + if (PrecomputedSummary != null) + return PrecomputedSummary; + + // Compute and cache (this mutates the object, but it's just a string field) + PrecomputedSummary = ComputeSummary(); + return PrecomputedSummary; + } + + /// + /// Compute the summary for this event. + /// This is called by GetSummary() or Dehydrate(). + /// Delegates to EventSummarizer for rich summaries. + /// + private string ComputeSummary() + { + return MCPForUnity.Editor.ActionTrace.Query.EventSummarizer.Summarize(this); + } + + /// + /// Validate and sanitize payload values to ensure JSON serializability. + /// Converts values to safe types and logs warnings for unsupported types. + /// + private static Dictionary SanitizePayload( + IReadOnlyDictionary payload, + string eventType) + { + var sanitized = new Dictionary(); + + foreach (var kvp in payload) + { + var value = SanitizeValue(kvp.Value, kvp.Key, eventType, 0); + if (value != null || kvp.Value == null) + { + // Only add if not filtered out (null values are allowed) + sanitized[kvp.Key] = value; + } + } + + return sanitized; + } + + /// + /// Recursively validate and sanitize a single value. + /// Returns null for unsupported types (which will be filtered out). + /// + private static object SanitizeValue(object value, string key, string eventType, int depth) + { + if (value == null) + return null; + + if (depth > MaxSanitizeDepth) + { + // Depth exceeded: return placeholder to avoid deep structures + return ""; + } + + // Primitive JSON-serializable types + if (value is string s) + { + if (s.Length > MaxStringLength) + return s.Substring(0, MaxStringLength) + "..."; + return s; + } + if (value is bool) + return value; + + // Numeric types - convert to consistent types + if (value is int i) return i; + if (value is long l) return l; + if (value is float f) return f; + if (value is double d) return d; + if (value is decimal m) return m; + if (value is uint ui) return ui; + if (value is ulong ul) return ul; + if (value is short sh) return sh; + if (value is ushort ush) return ush; + if (value is byte b) return b; + if (value is sbyte sb) return sb; + if (value is char c) return c.ToString(); // Char as string + + // Arrays - handle native arrays (int[], string[], etc.) + if (value.GetType().IsArray) + { + return SanitizeArray((Array)value, key, eventType, depth + 1); + } + + // Generic collections - use non-generic interface for broader compatibility + // This handles List, IEnumerable, HashSet, etc. with any element type + if (value is IEnumerable enumerable && !(value is string) && !(value is IDictionary)) + { + return SanitizeEnumerable(enumerable, key, eventType, depth + 1); + } + + // Dictionaries - use non-generic interface for broader compatibility + // This handles Dictionary with any value type + if (value is IDictionary dict) + { + return SanitizeDictionary(dict, key, eventType, depth + 1); + } + + // Unsupported type - log warning and filter out + McpLog.Warn( + $"[EditorEvent] Unsupported payload type '{value.GetType().Name}' " + + $"for key '{key}' in event '{eventType}'. Value will be excluded from payload. " + + $"Supported types: string, number, bool, null, array, List, Dictionary."); + + return null; // Filter out unsupported types + } + + /// + /// Sanitize a native array. + /// + private static object SanitizeArray(Array array, string key, string eventType, int depth) + { + var list = new List(Math.Min(array.Length, MaxCollectionItems)); + int count = 0; + foreach (var item in array) + { + if (count++ >= MaxCollectionItems) + { + list.Add(""); + break; + } + var sanitized = SanitizeValue(item, key, eventType, depth); + if (sanitized != null || item == null) + { + list.Add(sanitized); + } + } + return list; + } + + /// + /// Sanitize a generic IEnumerable (List, IEnumerable, etc.) + /// Uses non-generic interface to handle any element type. + /// + private static object SanitizeEnumerable(IEnumerable enumerable, string key, string eventType, int depth) + { + var list = new List(MaxCollectionItems); + int count = 0; + foreach (var item in enumerable) + { + if (count++ >= MaxCollectionItems) + { + list.Add(""); + break; + } + var sanitized = SanitizeValue(item, key, eventType, depth); + if (sanitized != null || item == null) + { + list.Add(sanitized); + } + } + return list; + } + + /// + /// Sanitize a generic IDictionary (Dictionary, etc.) + /// Uses non-generic interface to handle any key/value types. + /// Only string keys are supported; other key types are skipped with warning. + /// + private static object SanitizeDictionary(IDictionary dict, string key, string eventType, int depth) + { + var result = new Dictionary(Math.Min(dict.Count, MaxCollectionItems)); + int count = 0; + foreach (DictionaryEntry entry in dict) + { + if (count++ >= MaxCollectionItems) + { + result[""] = "more_items"; + break; + } + + // Only support string keys + if (entry.Key is string stringKey) + { + var sanitizedValue = SanitizeValue(entry.Value, stringKey, eventType, depth); + if (sanitizedValue != null || entry.Value == null) + { + result[stringKey] = sanitizedValue; + } + } + else + { + McpLog.Warn( + $"[EditorEvent] Dictionary key type '{entry.Key?.GetType().Name}' " + + $"is not supported. Only string keys are supported. Key will be skipped."); + } + } + + return result; + } + + // ======================================================================== + // FORBIDDEN FIELDS - Do NOT add these properties to EditorEvent: + // - Importance: Calculate at query time, not stored + // - Source/AI/Human flags: Use Context layer (ContextMapping side-table) + // - SessionId: Use Context layer + // - _ctx: Use Context layer + // These are intentionally omitted to keep the event layer pure. + // ======================================================================== + + public bool Equals(EditorEvent other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Sequence == other.Sequence + && TimestampUnixMs == other.TimestampUnixMs + && Type == other.Type + && TargetId == other.TargetId; + } + + public override bool Equals(object obj) + { + return Equals(obj as EditorEvent); + } + + public override int GetHashCode() + { + return HashCode.Combine(Sequence, TimestampUnixMs, Type, TargetId); + } + + public static bool operator ==(EditorEvent left, EditorEvent right) + { + return Equals(left, right); + } + + public static bool operator !=(EditorEvent left, EditorEvent right) + { + return !Equals(left, right); + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Core/EventStore.cs b/MCPForUnity/Editor/ActionTrace/Core/EventStore.cs new file mode 100644 index 000000000..f14236f86 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Core/EventStore.cs @@ -0,0 +1,869 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Context; +using MCPForUnity.Editor.ActionTrace.Semantics; +using UnityEditor; + +namespace MCPForUnity.Editor.ActionTrace.Core +{ + /// + /// Thread-safe event store for editor events. + /// + /// Threading model: + /// - Writes: Main thread only (enforced by Debug.Assert in DEBUG builds) + /// - Reads: Any thread, uses lock for snapshot pattern + /// - Sequence generation: Uses Interlocked.Increment for atomicity + /// + /// Persistence: Uses McpJobStateStore for domain reload survival. + /// Save strategy: Deferred persistence with dirty flag + delayCall coalescing. + /// + /// Memory optimization (Pruning): + /// - Hot events (latest 100): Full payload retained + /// - Cold events (older than 100): Automatically dehydrated (payload = null) + /// - This reduces memory from ~10MB to <1MB for 1000 events + /// + /// Event merging (Deduplication): + /// - High-frequency events (PropertyModified, SelectionPropertyModified, HierarchyChanged) + /// are merged within a short time window to reduce noise + /// - Same event type + same target + same property path within merge window = single event + /// + /// Settings: Controlled by ActionTraceSettings asset. + /// + public static class EventStore + { + private const int MaxContextMappings = 2000; + private const string StateKey = "timeline_events"; + + // Event types that are eligible for merging (high-frequency, noisy events) + private static readonly HashSet MergeableEventTypes = new() + { + EventTypes.PropertyModified, + EventTypes.SelectionPropertyModified, + EventTypes.HierarchyChanged, + EventTypes.SelectionChanged + }; + + // Schema version for migration support + // Increment when breaking changes are made to the storage format + private const int CurrentSchemaVersion = 4; // Incremented for settings integration + + private static readonly List _events = new(); + private static readonly List _contextMappings = new(); + private static readonly object _queryLock = new(); + private static long _sequenceCounter; + private static bool _isLoaded; + private static bool _isDirty; // Dirty flag for deferred persistence + private static bool _saveScheduled; // Prevents duplicate delayCall registrations + + // Batch notification: accumulate pending events and notify in single delayCall + private static readonly List _pendingNotifications = new(); + private static bool _notifyScheduled; + + // Event merging state (tracks last event for merge detection) + private static EditorEvent _lastRecordedEvent; + private static long _lastRecordedTime; + + // Main thread detection: Use Unity's EditorApplication.isUpdating for runtime checks. + // This is more robust than capturing a thread ID at static initialization time, + // as it works correctly after domain reload and doesn't rely on managed thread IDs. + // The MainThreadId field is kept for legacy/debugging purposes only. + private static readonly int MainThreadId = Thread.CurrentThread.ManagedThreadId; + + /// + /// Event raised when a new event is recorded. + /// Used by ContextTrace to create associations. + /// + public static event Action EventRecorded; + + static EventStore() + { + LoadFromStorage(); + } + + + + /// + /// Record a new event. Must be called from main thread. + /// + /// Returns: + /// - New sequence number for newly recorded events + /// - Existing sequence number when events are merged (same type/target/property within merge window) + /// - -1 when event is rejected by importance filter + /// + /// To detect merging, check if the returned sequence matches a previously recorded event, + /// or inspect the event's payload for the "merge_count" field (present when merge_count > 0). + /// + /// Thread safety: Write operations are protected by _queryLock for defensive + /// programming, even though Record is expected to be called from main thread only. + /// + /// Event merging: High-frequency events within MergeWindowMs that have the same + /// type, target, and property path will be merged into the previous event instead + /// of creating a new entry. This reduces noise from actions like dragging sliders. + /// + /// Importance filtering: Events below ActionTraceSettings.MinImportanceForRecording + /// are silently rejected at the store level (not just UI filtering). + /// + public static long Record(EditorEvent @event) + { + // Apply importance filter at store level + // This prevents low-importance events from being recorded at all + var settings = ActionTraceSettings.Instance; + if (settings != null) + { + float importance = DefaultEventScorer.Instance.Score(@event); + if (importance < settings.MinImportanceForRecording) + { + // Event rejected due to low importance + return -1; + } + } + + // Note: EditorApplication.isUpdating check removed because it was too strict. + // Many valid callbacks (delayCall, AssetPostprocessor, hierarchyChanged) run + // on the main thread but outside the update loop. The lock(_queryLock) provides + // actual thread safety for the critical section. + + // Use Interlocked.Increment for thread-safe sequence generation + // Even though we assert main thread, this provides defense-in-depth + long newSequence = Interlocked.Increment(ref _sequenceCounter); + + var evtWithSequence = new EditorEvent( + sequence: newSequence, + timestampUnixMs: @event.TimestampUnixMs, + type: @event.Type, + targetId: @event.TargetId, + payload: @event.Payload + ); + + // Store reference for merge detection + _lastRecordedEvent = evtWithSequence; + _lastRecordedTime = @event.TimestampUnixMs; + + // Capture settings limits before lock + int hotEventCount = settings?.HotEventCount ?? 100; + int maxEvents = settings?.MaxEvents ?? 1000; + + // Write lock: protect _events and _contextMappings mutations + lock (_queryLock) + { + // Check if event merging is enabled and this event should be merged + // Must check inside lock since _lastRecordedEvent may be modified by other threads + if (settings?.EnableEventMerging != false && ShouldMergeWithLast(@event)) + { + // Merge with last event: update timestamp and end_value + // Return the existing sequence instead of creating a new event + MergeWithLastEventLocked(@event); + return _lastRecordedEvent.Sequence; + } + + _events.Add(evtWithSequence); + + // Auto-dehydrate old events to save memory + // Keep latest HotEventCount events with full payload, dehydrate the rest + if (_events.Count > hotEventCount) + { + DehydrateOldEvents(hotEventCount); + } + + // Trim oldest events if over limit (batch remove is more efficient than loop RemoveAt) + if (_events.Count > maxEvents) + { + int removeCount = _events.Count - maxEvents; + // Capture sequences to cascade delete mappings + var removedSequences = new HashSet(); + for (int i = 0; i < removeCount; i++) + { + removedSequences.Add(_events[i].Sequence); + } + _events.RemoveRange(0, removeCount); + + // Cascade delete: remove mappings for deleted events + _contextMappings.RemoveAll(m => removedSequences.Contains(m.EventSequence)); + } + } + + // Mark dirty and schedule deferred save (reduces disk I/O from O(N) to O(1)) + _isDirty = true; + ScheduleSave(); + + // Batch notification: accumulate event and schedule single delayCall + // This prevents callback queue bloat in high-frequency scenarios + lock (_pendingNotifications) + { + _pendingNotifications.Add(evtWithSequence); + } + + ScheduleNotify(); + + return evtWithSequence.Sequence; + } + + /// + /// Query events with optional filtering. + /// Thread-safe - can be called from any thread. + /// Uses snapshot pattern: capture only needed range inside lock, query outside. + /// + /// Performance optimization: Only copies the tail portion of _events + /// (limit + buffer) unless sinceSequence requires earlier events. + /// + /// Correctness guarantee: If sinceSequence is provided, ALL events with + /// Sequence > sinceSequence are returned, even if they fall outside the + /// normal tail window. The copy window is automatically extended to include + /// all matching events. + /// + public static IReadOnlyList Query(int limit = 50, long? sinceSequence = null) + { + List snapshot; + + lock (_queryLock) + { + int count = _events.Count; + if (count == 0) + { + return Array.Empty(); + } + + // Base window: tail portion for recent queries + int copyCount = Math.Min(count, limit + (limit / 10) + 10); + int startIndex = count - copyCount; + + // If sinceSequence is specified, ensure we don't miss matching events + // Find the first event with Sequence > sinceSequence and extend window if needed + if (sinceSequence.HasValue) + { + int firstMatchIndex = -1; + // Linear search from the end (most recent events are likely to match first) + for (int i = count - 1; i >= 0; i--) + { + if (_events[i].Sequence > sinceSequence.Value) + { + firstMatchIndex = i; + } + else if (firstMatchIndex >= 0) + { + // Found a non-matching event after matches, stop searching + break; + } + } + + // Extend window to include all matching events + if (firstMatchIndex >= 0 && firstMatchIndex < startIndex) + { + startIndex = firstMatchIndex; + copyCount = count - startIndex; + } + } + + snapshot = new List(copyCount); + for (int i = startIndex; i < count; i++) + { + snapshot.Add(_events[i]); + } + } + + // Query: LINQ runs outside lock, no blocking + var query = snapshot.AsEnumerable(); + + if (sinceSequence.HasValue) + { + query = query.Where(e => e.Sequence > sinceSequence.Value); + } + + return query.OrderByDescending(e => e.Sequence).Take(limit).ToList(); + } + + /// + /// Get the current sequence counter value. + /// + public static long CurrentSequence => _sequenceCounter; + + /// + /// Get total event count. + /// + public static int Count + { + get + { + lock (_queryLock) + { + return _events.Count; + } + } + } + + /// + /// Dehydrate old events (beyond hotEventCount) to save memory. + /// This is called automatically by Record(). + /// + private static void DehydrateOldEvents(int hotEventCount) + { + // Find events that need dehydration (not already dehydrated and beyond hot count) + for (int i = 0; i < _events.Count - hotEventCount; i++) + { + var evt = _events[i]; + if (evt != null && !evt.IsDehydrated && evt.Payload != null) + { + // Dehydrate the event (creates new instance with Payload = null) + _events[i] = evt.Dehydrate(); + } + } + } + + // ======================================================================== + // Event Merging (Deduplication) + // ======================================================================== + + /// + /// Checks if the given event should be merged with the last recorded event. + /// Merging criteria: + /// - Same event type (and type is mergeable) + /// - Same target ID + /// - Same property path (for property modification events) + /// - Within merge time window + /// + private static bool ShouldMergeWithLast(EditorEvent evt) + { + if (_lastRecordedEvent == null) + return false; + + var settings = ActionTraceSettings.Instance; + int mergeWindowMs = settings?.MergeWindowMs ?? 100; + + // Time window check + long timeDelta = evt.TimestampUnixMs - _lastRecordedTime; + if (timeDelta > mergeWindowMs || timeDelta < 0) + return false; + + // Type check: must be the same mergeable type + if (evt.Type != _lastRecordedEvent.Type) + return false; + + if (!MergeableEventTypes.Contains(evt.Type)) + return false; + + // Target check: must be the same target + if (evt.TargetId != _lastRecordedEvent.TargetId) + return false; + + // Property path check: for property modification events, must be same property + string currentPropertyPath = GetPropertyPathFromPayload(evt.Payload); + string lastPropertyPath = GetPropertyPathFromPayload(_lastRecordedEvent.Payload); + if (!string.Equals(currentPropertyPath, lastPropertyPath, StringComparison.Ordinal)) + return false; + + return true; + } + + /// + /// Merges the new event with the last recorded event. + /// Updates the last event's timestamp and end_value (if applicable). + /// IMPORTANT: This method must only be called while holding _queryLock. + /// + private static void MergeWithLastEventLocked(EditorEvent evt) + { + if (_lastRecordedEvent == null) + return; + + // Update timestamp to reflect the most recent activity + _lastRecordedTime = evt.TimestampUnixMs; + + // For property modification events, update the end_value + // This allows tracking the start and end of a continuous change (e.g., slider drag) + if (evt.Payload != null && _lastRecordedEvent.Payload != null) + { + var newPayload = new Dictionary(_lastRecordedEvent.Payload); + + // Update end_value with the new value + if (evt.Payload.TryGetValue("end_value", out var newValue)) + { + newPayload["end_value"] = newValue; + } + + // Update timestamp in payload + newPayload["timestamp"] = evt.TimestampUnixMs; + + // Add merge_count to track how many events were merged + int mergeCount = 1; + if (_lastRecordedEvent.Payload.TryGetValue("merge_count", out var existingCount)) + { + mergeCount = (int)existingCount + 1; + } + newPayload["merge_count"] = mergeCount; + + // Update the last event's payload (requires creating new EditorEvent) + // Safe to access _events here since caller holds _queryLock + int lastEventIndex = _events.Count - 1; + if (lastEventIndex >= 0) + { + _events[lastEventIndex] = new EditorEvent( + sequence: _lastRecordedEvent.Sequence, + timestampUnixMs: evt.TimestampUnixMs, + type: _lastRecordedEvent.Type, + targetId: _lastRecordedEvent.TargetId, + payload: newPayload + ); + _lastRecordedEvent = _events[lastEventIndex]; + } + } + + // Schedule save since we modified the last event + _isDirty = true; + ScheduleSave(); + } + + /// + /// Extracts the property path from an event payload. + /// Used for merge detection of property modification events. + /// + private static string GetPropertyPathFromPayload(IReadOnlyDictionary payload) + { + if (payload == null) + return null; + + if (payload.TryGetValue("property_path", out var propertyPath)) + return propertyPath as string; + + return null; + } + + /// + /// Clear all events and context mappings (for testing). + /// WARNING: This is destructive and cannot be undone. + /// All ActionTrace history and context associations will be lost. + /// + public static void Clear() + { + lock (_queryLock) + { + _events.Clear(); + _contextMappings.Clear(); + _sequenceCounter = 0; + } + // For Clear(), save immediately (not deferred) since it's a destructive operation + SaveToStorage(); + } + + /// + /// Clears all pending notifications and scheduled saves. + /// Call this when shutting down or reloading domains to prevent delayCall leaks. + /// + public static void ClearPendingOperations() + { + lock (_pendingNotifications) + { + _pendingNotifications.Clear(); + _notifyScheduled = false; + } + _saveScheduled = false; + } + + /// + /// Get diagnostic information about memory usage. + /// Useful for monitoring and debugging memory issues. + /// + public static string GetMemoryDiagnostics() + { + lock (_queryLock) + { + var settings = ActionTraceSettings.Instance; + int hotEventCount = settings?.HotEventCount ?? 100; + int maxEvents = settings?.MaxEvents ?? 1000; + + int totalEvents = _events.Count; + int hotEvents = Math.Min(totalEvents, hotEventCount); + int coldEvents = Math.Max(0, totalEvents - hotEventCount); + + int hydratedCount = 0; + int dehydratedCount = 0; + long estimatedPayloadBytes = 0; + + foreach (var evt in _events) + { + if (evt.IsDehydrated) + dehydratedCount++; + else if (evt.Payload != null) + { + hydratedCount++; + // Estimate payload size (rough approximation) + estimatedPayloadBytes += EstimatePayloadSize(evt.Payload); + } + } + + // Estimate dehydrated events size (~100 bytes each) + long dehydratedBytes = dehydratedCount * 100; + + // Total estimated size + long totalEstimatedBytes = estimatedPayloadBytes + dehydratedBytes; + double totalEstimatedMB = totalEstimatedBytes / (1024.0 * 1024.0); + + return $"EventStore Memory Diagnostics:\n" + + $" Total Events: {totalEvents}/{maxEvents}\n" + + $" Hot Events (full payload): {hotEvents}\n" + + $" Cold Events (dehydrated): {coldEvents}\n" + + $" Hydrated: {hydratedCount}\n" + + $" Dehydrated: {dehydratedCount}\n" + + $" Estimated Payload Memory: {estimatedPayloadBytes / 1024} KB\n" + + $" Total Estimated Memory: {totalEstimatedMB:F2} MB"; + } + } + + /// + /// Estimate the size of a payload in bytes. + /// This is a rough approximation for diagnostics. + /// + private static long EstimatePayloadSize(IReadOnlyDictionary payload) + { + if (payload == null) return 0; + + long size = 0; + foreach (var kvp in payload) + { + // Key string (assume average 20 chars) + size += kvp.Key.Length * 2; + + // Value + if (kvp.Value is string str) + size += str.Length * 2; + else if (kvp.Value is int) + size += 4; + else if (kvp.Value is long) + size += 8; + else if (kvp.Value is double) + size += 8; + else if (kvp.Value is bool) + size += 1; + else if (kvp.Value is IDictionary dict) + size += dict.Count * 100; // Rough estimate + else if (kvp.Value is System.Collections.ICollection list) + size += list.Count * 50; // Rough estimate + else + size += 50; // Unknown type + } + + return size; + } + + // ======================================================================== + // Context Mapping API (Phase 1) + // ======================================================================== + + /// + /// Add a context mapping for an event. + /// + /// Strategy: Multiple mappings allowed for same eventSequence (different contexts). + /// Duplicate detection: Same (eventSequence, contextId) pair will be skipped. + /// Query behavior: QueryWithContext returns the first (most recent) mapping per event. + /// + /// Thread-safe - can be called from EventRecorded subscribers. + /// + public static void AddContextMapping(ContextMapping mapping) + { + lock (_queryLock) + { + // Skip duplicate mappings (same eventSequence and contextId) + // This allows multiple different contexts for the same event, + // but prevents identical duplicates from bloating the list. + bool isDuplicate = false; + for (int i = _contextMappings.Count - 1; i >= 0; i--) + { + var existing = _contextMappings[i]; + if (existing.EventSequence == mapping.EventSequence && + existing.ContextId == mapping.ContextId) + { + isDuplicate = true; + break; + } + // Optimization: mappings are ordered by EventSequence + if (existing.EventSequence < mapping.EventSequence) + break; + } + + if (isDuplicate) + return; + + _contextMappings.Add(mapping); + + // Trim oldest mappings if over limit + if (_contextMappings.Count > MaxContextMappings) + { + int removeCount = _contextMappings.Count - MaxContextMappings; + _contextMappings.RemoveRange(0, removeCount); + } + } + + // Mark dirty and schedule deferred save + _isDirty = true; + ScheduleSave(); + } + + /// + /// Schedule a deferred save via delayCall. + /// Multiple rapid calls result in a single save (coalesced). + /// + private static void ScheduleSave() + { + // Only schedule if not already scheduled (prevents callback queue bloat) + if (_saveScheduled) + return; + + _saveScheduled = true; + + // Use delayCall to coalesce multiple saves into one + EditorApplication.delayCall += () => + { + _saveScheduled = false; + if (_isDirty) + { + SaveToStorage(); + _isDirty = false; + } + }; + } + + /// + /// Schedule batch notification via delayCall. + /// Multiple rapid events result in a single notification batch. + /// Thread-safe: check-and-set is atomic under lock. + /// + private static void ScheduleNotify() + { + // Atomic check-and-set under lock to prevent race conditions + lock (_pendingNotifications) + { + if (_notifyScheduled) + return; + + _notifyScheduled = true; + } + + EditorApplication.delayCall += DrainPendingNotifications; + } + + /// + /// Drain all pending notifications and invoke EventRecorded for each. + /// Called via delayCall, runs on main thread after current Record() completes. + /// Thread-safe: clears _notifyScheduled under lock. + /// + private static void DrainPendingNotifications() + { + List toNotify; + lock (_pendingNotifications) + { + _notifyScheduled = false; + + if (_pendingNotifications.Count == 0) + return; + + toNotify = new List(_pendingNotifications); + _pendingNotifications.Clear(); + } + + // Notify subscribers outside lock + foreach (var evt in toNotify) + { + EventRecorded?.Invoke(evt); + } + } + + /// + /// Query events with their context associations. + /// Returns a tuple of (Event, Context) where Context may be null. + /// Note: Source filtering is not supported in Phase 1 (ContextMappings only). + /// To filter by operation source, implement ContextStore (Phase 2). + /// + /// Performance optimization: Only copies the tail portion of lists + /// unless sinceSequence requires earlier events. + /// + /// Correctness guarantee: If sinceSequence is provided, ALL events with + /// Sequence > sinceSequence are returned, even if they fall outside the + /// normal tail window. + /// + public static IReadOnlyList<(EditorEvent Event, ContextMapping Context)> QueryWithContext( + int limit = 50, + long? sinceSequence = null) + { + List eventsSnapshot; + List mappingsSnapshot; + + lock (_queryLock) + { + int eventCount = _events.Count; + if (eventCount == 0) + { + return Array.Empty<(EditorEvent, ContextMapping)>(); + } + + // Base window: tail portion for recent queries + int copyCount = Math.Min(eventCount, limit + (limit / 10) + 10); + int startIndex = eventCount - copyCount; + + // If sinceSequence is specified, ensure we don't miss matching events + if (sinceSequence.HasValue) + { + int firstMatchIndex = -1; + for (int i = eventCount - 1; i >= 0; i--) + { + if (_events[i].Sequence > sinceSequence.Value) + { + firstMatchIndex = i; + } + else if (firstMatchIndex >= 0) + { + break; + } + } + + if (firstMatchIndex >= 0 && firstMatchIndex < startIndex) + { + startIndex = firstMatchIndex; + copyCount = eventCount - startIndex; + } + } + + eventsSnapshot = new List(copyCount); + for (int i = startIndex; i < eventCount; i++) + { + eventsSnapshot.Add(_events[i]); + } + + // For mappings, copy all (usually much smaller than events) + mappingsSnapshot = new List(_contextMappings); + } + + // Build lookup dictionary outside lock + var mappingBySequence = mappingsSnapshot + .GroupBy(m => m.EventSequence) + .ToDictionary(g => g.Key, g => g.FirstOrDefault()); + + // Query and join outside lock + var query = eventsSnapshot.AsEnumerable(); + + if (sinceSequence.HasValue) + { + query = query.Where(e => e.Sequence > sinceSequence.Value); + } + + var results = query + .OrderByDescending(e => e.Sequence) + .Take(limit) + .Select(e => + { + mappingBySequence.TryGetValue(e.Sequence, out var mapping); + // mapping may be null if no context association exists + return (Event: e, Context: mapping); + }) + .ToList(); + + return results; + } + + /// + /// Remove all context mappings for a specific context ID. + /// + public static void RemoveContextMappings(Guid contextId) + { + lock (_queryLock) + { + _contextMappings.RemoveAll(m => m.ContextId == contextId); + } + // Mark dirty and schedule deferred save + _isDirty = true; + ScheduleSave(); + } + + /// + /// Get the number of stored context mappings. + /// + public static int ContextMappingCount + { + get + { + lock (_queryLock) + { + return _contextMappings.Count; + } + } + } + + private static void LoadFromStorage() + { + if (_isLoaded) return; + + try + { + var state = McpJobStateStore.LoadState(StateKey); + if (state != null) + { + // Schema version check for migration support + if (state.SchemaVersion > CurrentSchemaVersion) + { + UnityEngine.Debug.LogWarning( + $"[EventStore] Stored schema version {state.SchemaVersion} is newer " + + $"than current version {CurrentSchemaVersion}. Data may not load correctly. " + + $"Consider updating the ActionTrace system."); + } + else if (state.SchemaVersion < CurrentSchemaVersion) + { + // Future: Add migration logic here when schema changes + UnityEngine.Debug.Log( + $"[EventStore] Migrating data from schema version {state.SchemaVersion} to {CurrentSchemaVersion}"); + } + + _sequenceCounter = state.SequenceCounter; + _events.Clear(); + if (state.Events != null) + { + _events.AddRange(state.Events); + } + _contextMappings.Clear(); + if (state.ContextMappings != null) + { + _contextMappings.AddRange(state.ContextMappings); + } + } + } + catch (Exception ex) + { + UnityEngine.Debug.LogWarning($"[EventStore] Failed to load from storage: {ex.Message}"); + } + finally + { + _isLoaded = true; + } + } + + private static void SaveToStorage() + { + try + { + var state = new EventStoreState + { + SchemaVersion = CurrentSchemaVersion, + SequenceCounter = _sequenceCounter, + Events = _events.ToList(), + ContextMappings = _contextMappings.ToList() + }; + McpJobStateStore.SaveState(StateKey, state); + } + catch (Exception ex) + { + UnityEngine.Debug.LogWarning($"[EventStore] Failed to save to storage: {ex.Message}"); + } + } + + /// + /// Persistent state schema for EventStore. + /// SchemaVersion: Increment when breaking changes are made. + /// + private class EventStoreState + { + public int SchemaVersion { get; set; } = CurrentSchemaVersion; + public long SequenceCounter { get; set; } + public List Events { get; set; } + public List ContextMappings { get; set; } + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Core/EventTypes.cs b/MCPForUnity/Editor/ActionTrace/Core/EventTypes.cs new file mode 100644 index 000000000..883b1c41f --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Core/EventTypes.cs @@ -0,0 +1,55 @@ +namespace MCPForUnity.Editor.ActionTrace.Core +{ + /// + /// Centralized constant definitions for ActionTrace event types. + /// Provides type-safe event type names and reduces string literal usage. + /// + /// Usage: + /// EventTypes.ComponentAdded // instead of "ComponentAdded" + /// + public static class EventTypes + { + // Component events + public const string ComponentAdded = "ComponentAdded"; + public const string ComponentRemoved = "ComponentRemoved"; + + // Property events (P0: Property-Level Tracking) + public const string PropertyModified = "PropertyModified"; + public const string SelectionPropertyModified = "SelectionPropertyModified"; + + // GameObject events + public const string GameObjectCreated = "GameObjectCreated"; + public const string GameObjectDestroyed = "GameObjectDestroyed"; + + // Hierarchy events + public const string HierarchyChanged = "HierarchyChanged"; + + // Selection events (P2.3: Selection Tracking) + public const string SelectionChanged = "SelectionChanged"; + + // Play mode events + public const string PlayModeChanged = "PlayModeChanged"; + + // Scene events + public const string SceneSaving = "SceneSaving"; + public const string SceneSaved = "SceneSaved"; + public const string SceneOpened = "SceneOpened"; + public const string NewSceneCreated = "NewSceneCreated"; + + // Asset events + public const string AssetImported = "AssetImported"; + public const string AssetCreated = "AssetCreated"; + public const string AssetDeleted = "AssetDeleted"; + public const string AssetMoved = "AssetMoved"; + public const string AssetModified = "AssetModified"; + + // Script events + public const string ScriptCompiled = "ScriptCompiled"; + public const string ScriptCompilationFailed = "ScriptCompilationFailed"; + + // Build events + public const string BuildStarted = "BuildStarted"; + public const string BuildCompleted = "BuildCompleted"; + public const string BuildFailed = "BuildFailed"; + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Core/GlobalIdHelper.cs b/MCPForUnity/Editor/ActionTrace/Core/GlobalIdHelper.cs new file mode 100644 index 000000000..f7ea18974 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Core/GlobalIdHelper.cs @@ -0,0 +1,274 @@ +using System; +using UnityEditor; +using UnityEngine; +using MCPForUnity.Editor.Helpers; + +namespace MCPForUnity.Editor.ActionTrace.Core +{ + /// + /// Cross-session stable object identifier for ActionTrace events. + /// + /// Uses Unity's GlobalObjectId (2020.3+) with fallback to Scene/Asset paths. + /// This ensures that TargetId references survive domain reloads and editor restarts. + /// + /// Reuses existing Helpers: + /// - GameObjectLookup.GetGameObjectPath() for Scene fallback paths + /// - GameObjectLookup.FindById() for legacy InstanceID resolution + /// + public static class GlobalIdHelper + { + /// + /// Prefix for fallback path format when GlobalObjectId is unavailable. + /// Format: "Scene:{scenePath}@{hierarchyPath}" or "Asset:{assetPath}" + /// + private const string ScenePrefix = "Scene:"; + private const string AssetPrefix = "Asset:"; + private const string InstancePrefix = "Instance:"; + private const string PathSeparator = "@"; + + /// + /// Converts a UnityEngine.Object to a cross-session stable ID string. + /// + /// Priority: + /// 1. GlobalObjectId (Unity 2020.3+) - Most stable + /// 2. Scene path + hierarchy path (for GameObjects in scenes) + /// 3. Asset path (for assets in Project view) + /// 4. InstanceID (last resort - not cross-session stable) + /// + public static string ToGlobalIdString(UnityEngine.Object obj) + { + if (obj == null) + return string.Empty; + +#if UNITY_2020_3_OR_NEWER + // Priority 1: Use Unity's built-in GlobalObjectId (most stable) + var globalId = GlobalObjectId.GetGlobalObjectIdSlow(obj); + // identifierType == 0 means invalid (not a scene object or asset) + if (globalId.identifierType != 0) + { + return globalId.ToString(); + } + // Fall through to fallback if GlobalObjectId is invalid +#endif + + // Priority 2 & 3: Use fallback paths (reuses GameObjectLookup) + return GetFallbackId(obj); + } + + /// + /// Attempts to resolve a GlobalId string back to a Unity object. + /// Returns null if the object no longer exists or the ID is invalid. + /// + public static UnityEngine.Object FromGlobalIdString(string globalIdStr) + { + if (string.IsNullOrEmpty(globalIdStr)) + return null; + +#if UNITY_2020_3_OR_NEWER + // Try parsing as GlobalObjectId first + if (GlobalObjectId.TryParse(globalIdStr, out var globalId)) + { + var obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(globalId); + if (obj != null) + return obj; + } +#endif + + // Try parsing fallback formats + return ParseFallbackId(globalIdStr); + } + + /// + /// Generates a fallback ID when GlobalObjectId is unavailable. + /// + /// Reuses existing Helpers: + /// - GameObjectLookup.GetGameObjectPath() for Scene GameObject paths + /// + /// Formats: + /// - Scene GameObject: "Scene:Assets/MyScene.unity@GameObject/Child/Target" + /// - Asset: "Asset:Assets/Prefabs/MyPrefab.prefab" + /// - Other: "Instance:12345" (not cross-session stable) + /// + private static string GetFallbackId(UnityEngine.Object obj) + { + // GameObjects in valid scenes: use scene path + hierarchy path + if (obj is GameObject go && go.scene.IsValid()) + { + // Reuse GameObjectLookup.GetGameObjectPath() + string hierarchyPath = GameObjectLookup.GetGameObjectPath(go); + return $"{ScenePrefix}{go.scene.path}{PathSeparator}{hierarchyPath}"; + } + + // Assets (ScriptableObject, Material, Texture, etc.): use AssetDatabase + string assetPath = AssetDatabase.GetAssetPath(obj); + if (!string.IsNullOrEmpty(assetPath)) + { + return $"{AssetPrefix}{assetPath}"; + } + + // Last resort: InstanceID (not cross-session stable) + return $"{InstancePrefix}{obj.GetInstanceID()}"; + } + + /// + /// Parses a fallback ID string back to a Unity object. + /// Handles Scene, Asset, and Instance formats. + /// + private static UnityEngine.Object ParseFallbackId(string idStr) + { + if (string.IsNullOrEmpty(idStr)) + return null; + + // Format: "Scene:{scenePath}@{hierarchyPath}" + if (idStr.StartsWith(ScenePrefix)) + { + int separatorIndex = idStr.IndexOf(PathSeparator); + if (separatorIndex > 0) + { + string scenePath = idStr.Substring(ScenePrefix.Length, separatorIndex - ScenePrefix.Length); + string hierarchyPath = idStr.Substring(separatorIndex + 1); + + // Load the scene if not already loaded + var scene = UnityEditor.SceneManagement.EditorSceneManager.GetSceneByPath(scenePath); + if (!scene.IsValid()) + { + // Scene not loaded - cannot resolve + return null; + } + + // Find GameObject by hierarchy path + var found = GameObject.Find(hierarchyPath); + return found; + } + } + + // Format: "Asset:{assetPath}" + if (idStr.StartsWith(AssetPrefix)) + { + string assetPath = idStr.Substring(AssetPrefix.Length); + return AssetDatabase.LoadMainAssetAtPath(assetPath); + } + + // Format: "Instance:{instanceId}" + // Reuse GameObjectLookup.FindById() + if (idStr.StartsWith(InstancePrefix)) + { + string instanceStr = idStr.Substring(InstancePrefix.Length); + if (int.TryParse(instanceStr, out int instanceId)) + { + return GameObjectLookup.FindById(instanceId); + } + } + + return null; + } + + /// + /// Extracts a human-readable display name from a GlobalId string. + /// Useful for ActionTrace Viewer UI display. + /// Returns the object name if resolvable, otherwise a formatted ID string. + /// + public static string GetDisplayName(string globalIdStr) + { + if (string.IsNullOrEmpty(globalIdStr)) + return ""; + + // Try to resolve the object + var obj = FromGlobalIdString(globalIdStr); + if (obj != null) + return obj.name; + + // Object not found, extract readable parts from ID +#if UNITY_2020_3_OR_NEWER + if (GlobalObjectId.TryParse(globalIdStr, out var globalId)) + { + return $"[{globalId.identifierType} {globalId.assetGUID.ToString().Substring(0, 8)}...]"; + } +#endif + + // Fallback format + if (globalIdStr.StartsWith(ScenePrefix)) + { + int separatorIndex = globalIdStr.IndexOf(PathSeparator); + if (separatorIndex > 0) + { + string hierarchyPath = globalIdStr.Substring(separatorIndex + 1); + // Extract just the object name (last part of path) + int lastSlash = hierarchyPath.LastIndexOf('/'); + return lastSlash >= 0 + ? hierarchyPath.Substring(lastSlash + 1) + : hierarchyPath; + } + } + + if (globalIdStr.StartsWith(AssetPrefix)) + { + string assetPath = globalIdStr.Substring(AssetPrefix.Length); + // Extract just the filename + int lastSlash = assetPath.LastIndexOf('/'); + return lastSlash >= 0 + ? assetPath.Substring(lastSlash + 1) + : assetPath; + } + + // Truncate long IDs for display + if (globalIdStr.Length > 50) + return globalIdStr.Substring(0, 47) + "..."; + + return globalIdStr; + } + + /// + /// Checks if a GlobalId string is valid (non-null and non-empty). + /// + public static bool IsValidId(string globalIdStr) + { + return !string.IsNullOrEmpty(globalIdStr); + } + + /// + /// Gets the type of an ID string (GlobalObjectId, Scene, Asset, Instance). + /// Useful for debugging and categorization. + /// + public static GlobalIdType GetIdType(string globalIdStr) + { + if (string.IsNullOrEmpty(globalIdStr)) + return GlobalIdType.Invalid; + +#if UNITY_2020_3_OR_NEWER + if (GlobalObjectId.TryParse(globalIdStr, out var globalId)) + return GlobalIdType.GlobalObjectId; +#endif + + if (globalIdStr.StartsWith(ScenePrefix)) + return GlobalIdType.ScenePath; + + if (globalIdStr.StartsWith(AssetPrefix)) + return GlobalIdType.AssetPath; + + if (globalIdStr.StartsWith(InstancePrefix)) + return GlobalIdType.InstanceId; + + return GlobalIdType.Unknown; + } + } + + /// + /// Type classification for GlobalId strings. + /// + public enum GlobalIdType + { + /// Null or empty string + Invalid, + /// Unity 2020.3+ GlobalObjectId format + GlobalObjectId, + /// "Scene:{path}@{hierarchy}" fallback format + ScenePath, + /// "Asset:{path}" fallback format + AssetPath, + /// "Instance:{id}" fallback format (not cross-session stable) + InstanceId, + /// Unknown format + Unknown + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Descriptors/ComponentEventDescriptor.cs b/MCPForUnity/Editor/ActionTrace/Descriptors/ComponentEventDescriptor.cs new file mode 100644 index 000000000..cc3629a84 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Descriptors/ComponentEventDescriptor.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Descriptors +{ + /// + /// Descriptor for ComponentAdded events. + /// + public sealed class ComponentAddedDescriptor : EventDescriptorBase + { + public override string EventType => EventTypes.ComponentAdded; + + public override string Summarize(EditorEvent evt) + { + var componentType = GetString(evt, "component_type", "Component"); + var targetName = GetString(evt, "game_object", GetTargetName(evt)); + return $"Added {componentType} component to {targetName}"; + } + + public override Dictionary ExtractPayload(Dictionary rawPayload) + { + if (rawPayload == null) + return new Dictionary(); + + return new Dictionary + { + ["component_type"] = rawPayload.GetValueOrDefault("component_type", "Unknown"), + ["game_object"] = rawPayload.GetValueOrDefault("game_object", "Unknown") + }; + } + } + + /// + /// Descriptor for HierarchyChanged events. + /// + public sealed class HierarchyChangedDescriptor : EventDescriptorBase + { + public override string EventType => EventTypes.HierarchyChanged; + + public override string Summarize(EditorEvent evt) + { + return "Scene hierarchy changed"; + } + + public override Dictionary ExtractPayload(Dictionary rawPayload) + { + return new Dictionary + { + ["timestamp"] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }; + } + } + + /// + /// Descriptor for AssetImported events. + /// + public sealed class AssetImportedDescriptor : EventDescriptorBase + { + public override string EventType => EventTypes.AssetImported; + + public override string Summarize(EditorEvent evt) + { + var path = GetString(evt, "path", "Unknown"); + var assetType = GetString(evt, "asset_type", "asset"); + + // More specific summaries for known asset types + if (assetType == "script") + return $"Imported script: {path}"; + if (assetType == "scene") + return $"Imported scene: {path}"; + if (assetType == "prefab") + return $"Imported prefab: {path}"; + if (assetType == "texture") + return $"Imported texture: {path}"; + if (assetType == "audio") + return $"Imported audio: {path}"; + + return $"Imported {assetType}: {path}"; + } + + public override Dictionary ExtractPayload(Dictionary rawPayload) + { + if (rawPayload == null) + return new Dictionary(); + + var path = rawPayload.GetValueOrDefault("path", string.Empty)?.ToString() ?? string.Empty; + var extension = System.IO.Path.GetExtension(path); + + return new Dictionary + { + ["path"] = path, + ["extension"] = extension, + ["asset_type"] = rawPayload.GetValueOrDefault("asset_type", DetectAssetType(extension)) + }; + } + + private static string DetectAssetType(string extension) + { + if (string.IsNullOrEmpty(extension)) + return "unknown"; + + return extension.ToLower() switch + { + ".cs" => "script", + ".unity" => "scene", + ".prefab" => "prefab", + ".mat" => "material", + ".png" or ".jpg" or ".jpeg" => "texture", + ".wav" or ".mp3" or ".ogg" => "audio", + ".fbx" => "model", + ".anim" => "animation", + ".controller" => "animator_controller", + _ => "unknown" + }; + } + } + + /// + /// Descriptor for PlayModeChanged events. + /// + public sealed class PlayModeChangedDescriptor : EventDescriptorBase + { + public override string EventType => EventTypes.PlayModeChanged; + + public override string Summarize(EditorEvent evt) + { + var state = GetString(evt, "state", "Unknown"); + return $"Play mode changed to {state}"; + } + + public override Dictionary ExtractPayload(Dictionary rawPayload) + { + return new Dictionary + { + ["state"] = rawPayload?.GetValueOrDefault("state", "Unknown") ?? "Unknown" + }; + } + } + + /// + /// Descriptor for SceneSaving events. + /// + public sealed class SceneSavingDescriptor : EventDescriptorBase + { + public override string EventType => EventTypes.SceneSaving; + + public override string Summarize(EditorEvent evt) + { + var sceneName = GetString(evt, "scene_name", "Scene"); + return $"Saving scene: {sceneName}"; + } + + public override Dictionary ExtractPayload(Dictionary rawPayload) + { + return new Dictionary + { + ["scene_name"] = rawPayload?.GetValueOrDefault("scene_name", "Unknown") ?? "Unknown", + ["path"] = rawPayload?.GetValueOrDefault("path", string.Empty) ?? string.Empty + }; + } + } + + /// + /// Descriptor for SceneOpened events. + /// + public sealed class SceneOpenedDescriptor : EventDescriptorBase + { + public override string EventType => EventTypes.SceneOpened; + + public override string Summarize(EditorEvent evt) + { + var sceneName = GetString(evt, "scene_name", "Scene"); + return $"Opened scene: {sceneName}"; + } + + public override Dictionary ExtractPayload(Dictionary rawPayload) + { + return new Dictionary + { + ["scene_name"] = rawPayload?.GetValueOrDefault("scene_name", "Unknown") ?? "Unknown", + ["path"] = rawPayload?.GetValueOrDefault("path", string.Empty) ?? string.Empty, + ["mode"] = rawPayload?.GetValueOrDefault("mode", "Unknown") ?? "Unknown" + }; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Descriptors/IEventDescriptor.cs b/MCPForUnity/Editor/ActionTrace/Descriptors/IEventDescriptor.cs new file mode 100644 index 000000000..e96de0ac0 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Descriptors/IEventDescriptor.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Descriptors +{ + /// + /// Interface for event descriptors. + /// Descriptors encapsulate event type metadata, payload schema, and summarization logic. + /// This decouples EventSummarizer from payload structure changes. + /// + public interface IEventDescriptor + { + /// + /// The event type this descriptor handles. + /// Must match one of the constants in EventTypes. + /// + string EventType { get; } + + /// + /// Generate a human-readable summary for this event type. + /// + string Summarize(EditorEvent evt); + + /// + /// Validate and extract payload fields. + /// Returns a sanitized payload dictionary with all required fields. + /// Can be used to validate payload structure before recording. + /// + Dictionary ExtractPayload(Dictionary rawPayload); + } + + /// + /// Base class for event descriptors with common functionality. + /// + public abstract class EventDescriptorBase : IEventDescriptor + { + public abstract string EventType { get; } + + public abstract string Summarize(EditorEvent evt); + + public virtual Dictionary ExtractPayload(Dictionary rawPayload) + { + // Default implementation: pass through payload as-is + return rawPayload != null + ? new Dictionary(rawPayload) + : new Dictionary(); + } + + /// + /// Helper method to safely get a string value from payload. + /// + protected string GetString(EditorEvent evt, string key, string defaultValue = "") + { + if (evt.Payload.TryGetValue(key, out var value)) + { + return value?.ToString() ?? defaultValue; + } + return defaultValue; + } + + /// + /// Helper method to safely get a target name from payload. + /// Tries multiple common keys like "name", "game_object", "scene_name", etc. + /// + protected string GetTargetName(EditorEvent evt) + { + // Try common name fields + if (evt.Payload.TryGetValue("name", out var name)) + return name.ToString(); + + if (evt.Payload.TryGetValue("game_object", out var goName)) + return goName.ToString(); + + if (evt.Payload.TryGetValue("scene_name", out var sceneName)) + return sceneName.ToString(); + + if (evt.Payload.TryGetValue("component_type", out var componentType)) + return componentType.ToString(); + + if (evt.Payload.TryGetValue("path", out var path)) + return path.ToString(); + + // Fall back to target ID + return evt.TargetId; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Helpers/ActionTraceHelper.cs b/MCPForUnity/Editor/ActionTrace/Helpers/ActionTraceHelper.cs new file mode 100644 index 000000000..b11bbc23c --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Helpers/ActionTraceHelper.cs @@ -0,0 +1,185 @@ +using System; +using UnityEngine; +using UnityEditor; + +namespace MCPForUnity.Editor.ActionTrace.Helpers +{ + /// + /// Helper utilities for ActionTrace feature. + /// + /// Centralized common formatting and conversion methods + /// to avoid code duplication across ActionTrace components. + /// + public static class ActionTraceHelper + { + /// + /// Formats a tool name for display. + /// Converts snake_case to Title Case. + /// + /// Examples: + /// - "manage_gameobject" → "Manage GameObject" + /// - "add_ActionTrace_note" → "Add ActionTrace Note" + /// - "get_ActionTrace" → "Get ActionTrace" + /// + /// Used in: + /// - TransactionAggregator (summary generation) + /// - UndoGroupManager (Undo group names) + /// + public static string FormatToolName(string toolName) + { + if (string.IsNullOrEmpty(toolName)) + return "AI Operation"; + + // Simple snake_case to Title Case conversion + // Matches underscore + lowercase letter, replaces with uppercase letter + return System.Text.RegularExpressions.Regex.Replace( + toolName, + "_([a-z])", + match => match.Groups[1].Value.ToUpper() + ); + } + + /// + /// Formats duration for display. + /// Converts milliseconds to human-readable "X.Xs" format. + /// + /// Examples: + /// - 500 → "0.5s" + /// - 1500 → "1.5s" + /// - 2340 → "2.3s" + /// + /// Used in: + /// - TransactionAggregator (AtomicOperation.DurationMs display) + /// + public static string FormatDuration(long milliseconds) + { + return $"{milliseconds / 1000.0:F1}s"; + } + + /// + /// Formats duration from a timestamp range. + /// + /// Parameters: + /// startMs: Start timestamp in milliseconds + /// endMs: End timestamp in milliseconds + /// + /// Returns: + /// Human-readable duration string (e.g., "2.3s") + /// + public static string FormatDurationFromRange(long startMs, long endMs) + { + return FormatDuration(endMs - startMs); + } + } + + /// + /// Shared reflection helpers for extracting data from Unity's UndoPropertyModification. + /// This class centralizes reflection logic that was duplicated across PropertyChangeTracker and SelectionPropertyTracker. + /// + public static class UndoReflectionHelper + { + /// + /// Generic reflection helper to extract nested values from UndoPropertyModification. + /// Traverses dot-separated property paths like "propertyModification.target". + /// + /// Handles both Property and Field access, providing flexibility for Unity's internal structure variations. + /// + /// The root object to start traversal from (typically UndoPropertyModification) + /// Dot-separated path to the desired value (e.g., "propertyModification.target") + /// The extracted value, or null if any part of the path cannot be resolved + public static object GetNestedValue(object root, string path) + { + if (root == null || string.IsNullOrEmpty(path)) + return null; + + var parts = path.Split('.'); + object current = root; + + foreach (var part in parts) + { + if (current == null) return null; + + // Try property first (for currentValue, previousValue) + var prop = current.GetType().GetProperty(part); + if (prop != null) + { + current = prop.GetValue(current); + continue; + } + + // Try field (for propertyModification, target, value, etc.) + var field = current.GetType().GetField(part); + if (field != null) + { + current = field.GetValue(current); + continue; + } + + return null; + } + + return current; + } + + /// + /// Extracts the target object from an UndoPropertyModification. + /// The target is the UnityEngine.Object being modified (e.g., a Component or GameObject). + /// + public static UnityEngine.Object GetTarget(UndoPropertyModification undoMod) + { + // Try direct 'currentValue.target' path + var result = GetNestedValue(undoMod, "currentValue.target"); + if (result is UnityEngine.Object obj) return obj; + + // Fallback to 'previousValue.target' + result = GetNestedValue(undoMod, "previousValue.target"); + if (result is UnityEngine.Object obj2) return obj2; + + return null; + } + + /// + /// Extracts the property path from an UndoPropertyModification. + /// The property path identifies which property was modified (e.g., "m_Intensity"). + /// + public static string GetPropertyPath(UndoPropertyModification undoMod) + { + var result = GetNestedValue(undoMod, "currentValue.propertyPath"); + if (result != null) return result as string; + + result = GetNestedValue(undoMod, "previousValue.propertyPath"); + return result as string; + } + + /// + /// Extracts the current (new) value from an UndoPropertyModification. + /// This is the value after the modification was applied. + /// + public static object GetCurrentValue(UndoPropertyModification undoMod) + { + // Try direct 'currentValue.value' path + var result = GetNestedValue(undoMod, "currentValue.value"); + if (result != null) return result; + + return GetNestedValue(undoMod, "currentValue"); + } + + /// + /// Extracts the previous (old) value from an UndoPropertyModification. + /// This is the value before the modification was applied. + /// + public static object GetPreviousValue(UndoPropertyModification undoMod) + { + // Try direct 'previousValue' property first + var result = GetNestedValue(undoMod, "previousValue"); + if (result != null) return result; + + // Try 'previousValue.value' (nested structure) + result = GetNestedValue(undoMod, "previousValue.value"); + if (result != null) return result; + + // Some Unity versions use 'propertyModification.value.before' + return GetNestedValue(undoMod, "propertyModification.value.before"); + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Integration/ManageAssetBridge.cs b/MCPForUnity/Editor/ActionTrace/Integration/ManageAssetBridge.cs new file mode 100644 index 000000000..776216961 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Integration/ManageAssetBridge.cs @@ -0,0 +1,87 @@ +using System; +using UnityEditor; +using MCPForUnity.Editor.Tools; +using MCPForUnity.Editor.Helpers; +using System.Collections.Generic; + +namespace MCPForUnity.Editor.ActionTrace.Integration +{ + /// + /// Low-coupling bridge between ManageAsset and ActionTrace systems. + /// + /// This class subscribes to ManageAsset's events and forwards them to ActionTraceEventEmitter. + /// The bridge pattern ensures: + /// - ManageAsset has no direct dependency on ActionTrace + /// - ActionTrace can be enabled/disabled without affecting ManageAsset + /// - Single point of integration for easy maintenance + /// + /// Location: ActionTrace/Integration/ (separate folder for cross-system bridges) + /// + [InitializeOnLoad] + internal static class ManageAssetBridge + { + static ManageAssetBridge() + { + // Subscribe to ManageAsset events + // Events can only be subscribed to; null checks are not needed for subscription + ManageAsset.OnAssetModified += OnAssetModifiedHandler; + ManageAsset.OnAssetCreated += OnAssetCreatedHandler; + ManageAsset.OnAssetDeleted += OnAssetDeletedHandler; + } + + /// + /// Forward asset modification events to ActionTrace. + /// + private static void OnAssetModifiedHandler(string assetPath, string assetType, IReadOnlyDictionary changes) + { + try + { + Capture.ActionTraceEventEmitter.EmitAssetModified(assetPath, assetType, changes); + } + catch (Exception ex) + { + McpLog.Warn($"[ManageAssetBridge] Failed to record asset modification: {ex.Message}"); + } + } + + /// + /// Forward asset creation events to ActionTrace. + /// + private static void OnAssetCreatedHandler(string assetPath, string assetType) + { + try + { + Capture.ActionTraceEventEmitter.EmitAssetCreated(assetPath, assetType); + } + catch (Exception ex) + { + McpLog.Warn($"[ManageAssetBridge] Failed to record asset creation: {ex.Message}"); + } + } + + /// + /// Forward asset deletion events to ActionTrace. + /// + private static void OnAssetDeletedHandler(string assetPath, string assetType) + { + try + { + Capture.ActionTraceEventEmitter.EmitAssetDeleted(assetPath, assetType); + } + catch (Exception ex) + { + McpLog.Warn($"[ManageAssetBridge] Failed to record asset deletion: {ex.Message}"); + } + } + + /// + /// Unsubscribe from all events (useful for testing or cleanup). + /// + internal static void Disconnect() + { + ManageAsset.OnAssetModified -= OnAssetModifiedHandler; + ManageAsset.OnAssetCreated -= OnAssetCreatedHandler; + ManageAsset.OnAssetDeleted -= OnAssetDeletedHandler; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Query/ActionTraceQuery.cs b/MCPForUnity/Editor/ActionTrace/Query/ActionTraceQuery.cs new file mode 100644 index 000000000..bb6532ca8 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Query/ActionTraceQuery.cs @@ -0,0 +1,316 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MCPForUnity.Editor.ActionTrace.Core; +using MCPForUnity.Editor.ActionTrace.Semantics; +using UnityEngine; + +namespace MCPForUnity.Editor.ActionTrace.Query +{ + /// + /// Query engine that projects events with semantic information. + /// All semantic data (importance, category, intent) is computed at query time + /// and does not modify the original events. + /// + public sealed class ActionTraceQuery + { + // Static color caches to avoid repeated Color allocations during UI rendering + private static readonly Dictionary EventTypeColors = new() + { + ["ComponentAdded"] = new Color(0.3f, 0.8f, 0.3f), + ["PropertyModified"] = new Color(0.3f, 0.6f, 0.8f), + ["SelectionPropertyModified"] = new Color(0.5f, 0.8f, 0.9f), + ["GameObjectCreated"] = new Color(0.8f, 0.3f, 0.8f), + ["HierarchyChanged"] = new Color(0.8f, 0.8f, 0.3f), + ["AINote"] = new Color(0.3f, 0.8f, 0.8f), + }; + + private static readonly Dictionary ImportanceColors = new() + { + ["critical"] = new Color(1f, 0.3f, 0.3f, 0.1f), + ["high"] = new Color(1f, 0.6f, 0f, 0.08f), + ["medium"] = new Color(1f, 1f, 0.3f, 0.06f), + ["low"] = null, + }; + + private static readonly Dictionary ImportanceBadgeColors = new() + { + ["critical"] = new Color(0.8f, 0.2f, 0.2f), + ["high"] = new Color(1f, 0.5f, 0f), + ["medium"] = new Color(1f, 0.8f, 0.2f), + ["low"] = new Color(0.5f, 0.5f, 0.5f), + }; + + private readonly IEventScorer _scorer; + private readonly IEventCategorizer _categorizer; + private readonly IIntentInferrer _inferrer; + + /// + /// Create a new ActionTraceQuery with optional custom semantic components. + /// If null, default implementations are used. + /// + public ActionTraceQuery( + IEventScorer scorer = null, + IEventCategorizer categorizer = null, + IIntentInferrer inferrer = null) + { + _scorer = scorer ?? new DefaultEventScorer(); + _categorizer = categorizer ?? new DefaultCategorizer(); + _inferrer = inferrer ?? new DefaultIntentInferrer(); + } + + /// + /// Project events with computed semantic information. + /// Returns ActionTraceViewItem objects containing the original event plus + /// dynamically calculated importance, category, and intent. + /// + public IReadOnlyList Project(IReadOnlyList events) + { + if (events == null || events.Count == 0) + return Array.Empty(); + + var result = new ActionTraceViewItem[events.Count]; + + for (int i = 0; i < events.Count; i++) + { + var evt = events[i]; + + // Compute importance score + var score = _scorer.Score(evt); + + // Categorize the score + var category = _categorizer.Categorize(score); + + // Compute context window (5 events before and after current event) for intent inference + int contextWindow = 5; + int contextStart = Math.Max(0, i - contextWindow); + int contextEnd = Math.Min(events.Count, i + contextWindow + 1); + int contextLength = contextEnd - contextStart; + + EditorEvent[] surrounding = null; + if (contextLength > 0) + { + surrounding = new EditorEvent[contextLength]; + + // Performance: EventStore queries are usually in chronological order (but Query returns may be descending). + // Detect order in O(1) (compare first/last sequence) and fill surrounding in chronological order if needed + bool isDescending = events.Count > 1 && events[0].Sequence > events[events.Count - 1].Sequence; + + if (!isDescending) + { + for (int j = 0; j < contextLength; j++) + { + surrounding[j] = events[contextStart + j]; + } + } + else + { + // events are descending (newest first), need to build surrounding in ascending order (oldest->newest) + // Fill from contextEnd-1 down to contextStart to produce ascending window + for (int j = 0; j < contextLength; j++) + { + surrounding[j] = events[contextEnd - 1 - j]; + } + } + } + + // Use surrounding parameter for intent inference (in chronological order) + var intent = _inferrer.Infer(evt, surrounding); + + // Use EditorEvent's GetSummary() method, which automatically handles dehydrated events + var displaySummary = evt.GetSummary(); + var displaySummaryLower = (displaySummary ?? string.Empty).ToLowerInvariant(); + var displayTargetIdLower = (evt.TargetId ?? string.Empty).ToLowerInvariant(); + var displayTime = DateTimeOffset.FromUnixTimeMilliseconds(evt.TimestampUnixMs).ToString("HH:mm:ss"); + var displaySequence = evt.Sequence.ToString(); + + // Precompute colors + var typeColor = GetEventTypeColor(evt.Type); + var importanceColor = GetImportanceColor(category); + var importanceBadgeColor = GetImportanceBadgeColor(category); + + result[i] = new ActionTraceViewItem + { + Event = evt, + ImportanceScore = score, + ImportanceCategory = category, + InferredIntent = intent, + // Set display cache + DisplaySummary = displaySummary, + DisplaySummaryLower = displaySummaryLower, + DisplayTargetIdLower = displayTargetIdLower, + DisplayTime = displayTime, + DisplaySequence = displaySequence, + TypeColor = typeColor, + ImportanceColor = importanceColor, + ImportanceBadgeColor = importanceBadgeColor + }; + } + + return result; + } + + /// + /// Project events with context associations. + /// Overload for QueryWithContext results. + /// + public IReadOnlyList ProjectWithContext( + IReadOnlyList<(EditorEvent Event, Context.ContextMapping Context)> eventsWithContext) + { + if (eventsWithContext == null || eventsWithContext.Count == 0) + return Array.Empty(); + + var result = new ActionTraceViewItem[eventsWithContext.Count]; + + for (int i = 0; i < eventsWithContext.Count; i++) + { + var (evt, ctx) = eventsWithContext[i]; + + var score = _scorer.Score(evt); + var category = _categorizer.Categorize(score); + + // Use simple inference to avoid List allocation + var intent = _inferrer.Infer(evt, surrounding: null); + + // Use EditorEvent's GetSummary() method, which automatically handles dehydrated events + var displaySummary = evt.GetSummary(); + var displaySummaryLower = (displaySummary ?? string.Empty).ToLowerInvariant(); + var displayTargetIdLower = (evt.TargetId ?? string.Empty).ToLowerInvariant(); + var displayTime = DateTimeOffset.FromUnixTimeMilliseconds(evt.TimestampUnixMs).ToString("HH:mm:ss"); + var displaySequence = evt.Sequence.ToString(); + + // Precompute colors + var typeColor = GetEventTypeColor(evt.Type); + var importanceColor = GetImportanceColor(category); + var importanceBadgeColor = GetImportanceBadgeColor(category); + + result[i] = new ActionTraceViewItem + { + Event = evt, + Context = ctx, + ImportanceScore = score, + ImportanceCategory = category, + InferredIntent = intent, + // Set display cache + DisplaySummary = displaySummary, + DisplaySummaryLower = displaySummaryLower, + DisplayTargetIdLower = displayTargetIdLower, + DisplayTime = displayTime, + DisplaySequence = displaySequence, + TypeColor = typeColor, + ImportanceColor = importanceColor, + ImportanceBadgeColor = importanceBadgeColor + }; + } + + return result; + } + + /// + /// Get event type color for display. + /// Uses cached values to avoid repeated allocations. + /// + private static Color GetEventTypeColor(string eventType) + { + return EventTypeColors.TryGetValue(eventType, out var color) ? color : Color.gray; + } + + /// + /// Get importance background color (nullable). + /// Uses cached values to avoid repeated allocations. + /// + private static Color? GetImportanceColor(string category) + { + return ImportanceColors.TryGetValue(category, out var color) ? color : null; + } + + /// + /// Get importance badge color. + /// Uses cached values to avoid repeated allocations. + /// + private static Color GetImportanceBadgeColor(string category) + { + return ImportanceBadgeColors.TryGetValue(category, out var color) ? color : Color.gray; + } + + /// + /// A view of an event with projected semantic information. + /// This is a computed projection, not stored data. + /// + /// Performance optimization: All display strings are precomputed at projection time + /// to avoid repeated allocations in OnGUI. + /// + public sealed class ActionTraceViewItem + { + /// + /// The original immutable event. + /// + public EditorEvent Event { get; set; } + + /// + /// Optional context association (may be null). + /// + public Context.ContextMapping Context { get; set; } + + /// + /// Computed importance score (0.0 to 1.0). + /// Higher values indicate more important events. + /// + public float ImportanceScore { get; set; } + + /// + /// Category label derived from importance score. + /// Values: "critical", "high", "medium", "low" + /// + public string ImportanceCategory { get; set; } + + /// + /// Inferred user intent or purpose. + /// May be null if intent cannot be determined. + /// + public string InferredIntent { get; set; } + + // ========== Display cache (avoid repeated allocations in OnGUI) ========== + + /// + /// Precomputed event summary for display. + /// + public string DisplaySummary { get; set; } + + /// + /// Precomputed summary in lowercase for search filtering. + /// + public string DisplaySummaryLower { get; set; } + + /// + /// Precomputed target ID in lowercase for search filtering. + /// + public string DisplayTargetIdLower { get; set; } + + /// + /// Precomputed formatted time (HH:mm:ss). + /// + public string DisplayTime { get; set; } + + /// + /// Precomputed sequence number as string. + /// + public string DisplaySequence { get; set; } + + /// + /// Precomputed event type color (avoid switch during rendering). + /// + public Color TypeColor { get; set; } + + /// + /// Precomputed importance background color. + /// + public Color? ImportanceColor { get; set; } + + /// + /// Precomputed importance badge color. + /// + public Color ImportanceBadgeColor { get; set; } + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Query/EventSummarizer.cs b/MCPForUnity/Editor/ActionTrace/Query/EventSummarizer.cs new file mode 100644 index 000000000..a793cc521 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Query/EventSummarizer.cs @@ -0,0 +1,257 @@ +using System; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Query +{ + /// + /// Generates human-readable summaries for editor events. + /// Hardcoded summaries for MVP - will be enhanced in Phase 2 with semantic analysis. + /// + public static class EventSummarizer + { + /// + /// Generate a human-readable summary for an event. + /// P1.2: Added support for AINote events. + /// + public static string Summarize(EditorEvent evt) + { + return evt.Type switch + { + EventTypes.ComponentAdded => SummarizeComponentAdded(evt), + EventTypes.PropertyModified => SummarizePropertyModified(evt), + EventTypes.SelectionPropertyModified => SummarizeSelectionPropertyModified(evt), + EventTypes.HierarchyChanged => "Scene hierarchy changed", + EventTypes.AssetImported => SummarizeAssetImported(evt), + EventTypes.AssetDeleted => SummarizeAssetDeleted(evt), + EventTypes.AssetMoved => SummarizeAssetMoved(evt), + EventTypes.PlayModeChanged => SummarizePlayModeChanged(evt), + EventTypes.SceneSaving => SummarizeSceneSaving(evt), + EventTypes.SceneOpened => SummarizeSceneOpened(evt), + "AINote" => SummarizeAINote(evt), // P1.2: AI comment support + _ => $"{evt.Type} on {GetTargetName(evt)}" + }; + } + + private static string SummarizeComponentAdded(EditorEvent evt) + { + if (evt.Payload != null && evt.Payload.TryGetValue("component_type", out var componentType)) + { + return $"Added {componentType} component to {GetGameObjectName(evt)}"; + } + return $"Added component to {GetTargetName(evt)}"; + } + + private static string SummarizeAssetImported(EditorEvent evt) + { + if (evt.Payload != null && evt.Payload.TryGetValue("path", out var path)) + { + if (evt.Payload.TryGetValue("asset_type", out var assetType)) + { + return $"Imported {assetType}: {path}"; + } + return $"Imported asset: {path}"; + } + return "Asset imported"; + } + + private static string SummarizeAssetDeleted(EditorEvent evt) + { + if (evt.Payload != null && evt.Payload.TryGetValue("path", out var path)) + { + return $"Deleted asset: {path}"; + } + return "Asset deleted"; + } + + private static string SummarizeAssetMoved(EditorEvent evt) + { + if (evt.Payload != null && + evt.Payload.TryGetValue("to_path", out var toPath) && + evt.Payload.TryGetValue("from_path", out var fromPath)) + { + return $"Moved asset from {fromPath} to {toPath}"; + } + return "Asset moved"; + } + + private static string SummarizePlayModeChanged(EditorEvent evt) + { + if (evt.Payload != null && evt.Payload.TryGetValue("state", out var state)) + { + return $"Play mode changed to {state}"; + } + return "Play mode changed"; + } + + private static string SummarizeSceneSaving(EditorEvent evt) + { + if (evt.Payload != null && evt.Payload.TryGetValue("scene_name", out var sceneName)) + { + return $"Saving scene: {sceneName}"; + } + return "Scene saving"; + } + + private static string SummarizeSceneOpened(EditorEvent evt) + { + if (evt.Payload != null && evt.Payload.TryGetValue("scene_name", out var sceneName)) + { + return $"Opened scene: {sceneName}"; + } + return "Scene opened"; + } + + private static string GetTargetName(EditorEvent evt) + { + // Try to get a human-readable name from payload + if (evt.Payload != null && evt.Payload.TryGetValue("name", out var name)) + { + return name.ToString(); + } + if (evt.Payload != null && evt.Payload.TryGetValue("game_object", out var goName)) + { + return goName.ToString(); + } + if (evt.Payload != null && evt.Payload.TryGetValue("scene_name", out var sceneName)) + { + return sceneName.ToString(); + } + // Fall back to target ID + return evt.TargetId; + } + + private static string GetGameObjectName(EditorEvent evt) + { + if (evt.Payload != null && evt.Payload.TryGetValue("game_object", out var goName)) + { + return goName.ToString(); + } + return GetTargetName(evt); + } + + /// + /// Generates a human-readable summary for property modification events. + /// Format: "Changed {ComponentType}.{PropertyPath} from {StartValue} to {EndValue}" + /// + private static string SummarizePropertyModified(EditorEvent evt) + { + // Try to get component type and property path + string componentType = null; + string propertyPath = null; + string targetName = null; + + if (evt.Payload != null && evt.Payload.TryGetValue("component_type", out var compType)) + componentType = compType.ToString(); + + if (evt.Payload != null && evt.Payload.TryGetValue("property_path", out var propPath)) + propertyPath = propPath.ToString(); + + if (evt.Payload != null && evt.Payload.TryGetValue("target_name", out var tgtName)) + targetName = tgtName.ToString(); + + // Get readable values (strip quotes from JSON strings) + string startValue = GetReadableValue(evt, "start_value"); + string endValue = GetReadableValue(evt, "end_value"); + + // Format: "Changed Light.m_Intensity from 1.0 to 5.0" + if (!string.IsNullOrEmpty(componentType) && !string.IsNullOrEmpty(propertyPath)) + { + // Strip "m_" prefix from Unity serialized property names for readability + string readableProperty = propertyPath.StartsWith("m_") + ? propertyPath.Substring(2) + : propertyPath; + + if (!string.IsNullOrEmpty(startValue) && !string.IsNullOrEmpty(endValue)) + { + return $"Changed {componentType}.{readableProperty} from {startValue} to {endValue}"; + } + return $"Changed {componentType}.{readableProperty}"; + } + + // Fallback to target name if available + if (!string.IsNullOrEmpty(targetName)) + { + if (!string.IsNullOrEmpty(propertyPath)) + { + string readableProperty = propertyPath.StartsWith("m_") + ? propertyPath.Substring(2) + : propertyPath; + return $"Changed {targetName}.{readableProperty}"; + } + return $"Changed {targetName}"; + } + + return "Property modified"; + } + + /// + /// Extracts a readable value from the payload, handling JSON formatting. + /// Removes quotes from string values and limits length. + /// + private static string GetReadableValue(EditorEvent evt, string key) + { + if (evt.Payload == null || !evt.Payload.TryGetValue(key, out var value)) + return null; + + string valueStr = value.ToString(); + if (string.IsNullOrEmpty(valueStr)) + return null; + + // Remove quotes from JSON string values + if (valueStr.StartsWith("\"") && valueStr.EndsWith("\"") && valueStr.Length > 1) + { + valueStr = valueStr.Substring(1, valueStr.Length - 2); + } + + // Truncate long values (e.g., long vectors) + if (valueStr.Length > 50) + { + valueStr = valueStr.Substring(0, 47) + "..."; + } + + return valueStr; + } + + /// + /// P2.4: Generate a human-readable summary for SelectionPropertyModified events. + /// Similar to PropertyModified but with selection context emphasized. + /// Format: "Changed {ComponentType}.{PropertyPath} from {StartValue} to {EndValue} (selected)" + /// + private static string SummarizeSelectionPropertyModified(EditorEvent evt) + { + // Reuse PropertyModified logic but add selection indicator + string baseSummary = SummarizePropertyModified(evt); + return $"{baseSummary} (selected)"; + } + + /// + /// P1.2: Generate a human-readable summary for AI Note events. + /// Format: "AI Note: {note}" or "AI Note from {agent_id}: {note}" + /// + private static string SummarizeAINote(EditorEvent evt) + { + if (evt.Payload == null) + return "AI Note"; + + // Get the note text + if (evt.Payload.TryGetValue("note", out var note)) + { + string noteText = note?.ToString() ?? "Empty note"; + + // Get agent_id if available + if (evt.Payload.TryGetValue("agent_id", out var agentId)) + { + string agent = agentId?.ToString(); + if (!string.IsNullOrEmpty(agent) && agent != "unknown") + { + return $"AI Note ({agent}): {noteText}"; + } + } + + return $"AI Note: {noteText}"; + } + + return "AI Note"; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Query/TransactionAggregator.cs b/MCPForUnity/Editor/ActionTrace/Query/TransactionAggregator.cs new file mode 100644 index 000000000..d4e62fb80 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Query/TransactionAggregator.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MCPForUnity.Editor.ActionTrace.Core; +using MCPForUnity.Editor.ActionTrace.Helpers; + +namespace MCPForUnity.Editor.ActionTrace.Query +{ + /// + /// Logical transaction aggregator for ActionTrace events. + /// + /// Groups continuous events into "atomic operations" (logical transactions) + /// to reduce token consumption and improve AI efficiency. + /// + /// Aggregation priority (from document ActionTrace-enhancements.md P1.1): + /// 1. ToolCallId boundary (strongest) - Different tool calls split + /// 2. TriggeredByTool boundary - Different tools split + /// 3. Time window boundary (from ActionTraceSettings.TransactionWindowMs) - User operations backup + /// + /// Design principles: + /// - Query-time computation (does not modify stored events) + /// - Preserves EventStore immutability + /// - Compatible with semantic projection layer + /// + /// Usage: + /// var operations = TransactionAggregator.Aggregate(events); + /// // Returns: 50 events → 3 AtomicOperation objects + /// + public static class TransactionAggregator + { + /// + /// Default time window for user operation aggregation (fallback if settings unavailable). + /// Events within 2 seconds are grouped if no ToolId information exists. + /// + private const long DefaultTransactionWindowMs = 2000; + + /// + /// Aggregates a flat list of events into logical transactions. + /// + /// Algorithm (from document decision tree): + /// 1. Check ToolCallId boundary (if exists) + /// 2. Check TriggeredByTool boundary (if exists) + /// 3. Fallback to 2-second time window + /// + /// Returns a list of AtomicOperation objects, each representing + /// a logical group of events (e.g., one tool call). + /// + public static List Aggregate(IReadOnlyList events) + { + if (events == null || events.Count == 0) + return new List(); + + var result = new List(); + var currentBatch = new List(events.Count / 2); // Preallocate half capacity + + for (int i = 0; i < events.Count; i++) + { + var evt = events[i]; + + if (currentBatch.Count == 0) + { + // First event starts a new batch + currentBatch.Add(evt); + continue; + } + + var first = currentBatch[0]; + if (ShouldSplit(first, evt)) + { + // Boundary reached - finalize current batch + if (currentBatch.Count > 0) + result.Add(CreateAtomicOperation(currentBatch)); + + // Start new batch with current event - clear and reuse list + currentBatch.Clear(); + currentBatch.Add(evt); + } + else + { + // Same transaction - add to current batch + currentBatch.Add(evt); + } + } + + // Don't forget the last batch + if (currentBatch.Count > 0) + result.Add(CreateAtomicOperation(currentBatch)); + + return result; + } + + /// + /// Determines if two events should be in different transactions. + /// + /// Decision tree (from ActionTrace-enhancements.md line 274-290): + /// - Priority 1: ToolCallId boundary (mandatory split if different) + /// - Priority 2: TriggeredByTool boundary (mandatory split if different) + /// - Priority 3: Time window (from ActionTraceSettings.TransactionWindowMs, default 2000ms) + /// + private static bool ShouldSplit(EditorEvent first, EditorEvent current) + { + // Get transaction window from settings, with fallback to default + var settings = ActionTraceSettings.Instance; + long transactionWindowMs = settings?.TransactionWindowMs ?? DefaultTransactionWindowMs; + + // Extract ToolCallId from Payload (if exists) + string firstToolCallId = GetToolCallId(first); + string currentToolCallId = GetToolCallId(current); + + // ========== Priority 1: ToolCallId boundary ========== + // If both events have ToolCallId and they differ, mandatory split + if (!string.IsNullOrEmpty(currentToolCallId) && + !string.IsNullOrEmpty(firstToolCallId)) + { + if (currentToolCallId != firstToolCallId) + return true; // Different tool call → split + } + // If current has ToolCallId but first doesn't, check if it's same tool + else if (!string.IsNullOrEmpty(currentToolCallId)) + { + // Current event starts a new tool call → split + return true; + } + + // ========== Priority 2: TriggeredByTool boundary ========== + string firstTool = GetTriggeredByTool(first); + string currentTool = GetTriggeredByTool(current); + + if (!string.IsNullOrEmpty(currentTool) && + !string.IsNullOrEmpty(firstTool)) + { + if (currentTool != firstTool) + return true; // Different tool → split + } + + // ========== Priority 3: Time window (user operations) ========== + // If no ToolId information, use configured time window + long timeDelta = current.TimestampUnixMs - first.TimestampUnixMs; + return timeDelta > transactionWindowMs; + } + + /// + /// Creates an AtomicOperation from a batch of events. + /// + /// Summary generation strategy: + /// - If tool_call_id exists: "ToolName: N events in X.Xs" + /// - If time-based: Use first event's summary + " + N-1 related events" + /// + private static AtomicOperation CreateAtomicOperation(List batch) + { + if (batch == null || batch.Count == 0) + throw new ArgumentException("Batch cannot be empty", nameof(batch)); + + var first = batch[0]; + var last = batch[batch.Count - 1]; + + string toolCallId = GetToolCallId(first); + string toolName = GetTriggeredByTool(first); + + // Generate summary + string summary = GenerateSummary(batch, toolCallId, toolName); + + // Calculate duration + long durationMs = last.TimestampUnixMs - first.TimestampUnixMs; + + return new AtomicOperation + { + StartSequence = first.Sequence, + EndSequence = last.Sequence, + Summary = summary, + EventCount = batch.Count, + DurationMs = durationMs, + ToolCallId = toolCallId, + TriggeredByTool = toolName + }; + } + + /// + /// Generates a human-readable summary for an atomic operation. + /// + private static string GenerateSummary( + List batch, + string toolCallId, + string toolName) + { + if (batch.Count == 1) + { + // Single event - use its summary + return EventSummarizer.Summarize(batch[0]); + } + + // Multiple events + if (!string.IsNullOrEmpty(toolCallId)) + { + // Tool call - use tool name + count + string displayName = string.IsNullOrEmpty(toolName) + ? "AI operation" + : ActionTraceHelper.FormatToolName(toolName); + + return $"{displayName}: {batch.Count} events in {ActionTraceHelper.FormatDurationFromRange(batch[0].TimestampUnixMs, batch[batch.Count - 1].TimestampUnixMs)}"; + } + + // Time-based aggregation - use first event + count + string firstSummary = EventSummarizer.Summarize(batch[0]); + return $"{firstSummary} + {batch.Count - 1} related events"; + } + + /// + /// Extracts a string value from event Payload by key. + /// Returns null if not present or value is null. + /// + private static string GetPayloadString(EditorEvent evt, string key) + { + if (evt.Payload == null) + return null; + + if (evt.Payload.TryGetValue(key, out var value)) + return value?.ToString(); + + return null; + } + + /// + /// Extracts tool_call_id from event Payload. + /// Returns null if not present. + /// + private static string GetToolCallId(EditorEvent evt) => GetPayloadString(evt, "tool_call_id"); + + /// + /// Extracts triggered_by_tool from event Payload. + /// Returns null if not present. + /// + private static string GetTriggeredByTool(EditorEvent evt) => GetPayloadString(evt, "triggered_by_tool"); + } + + /// + /// Represents a logical transaction (atomic operation) composed of multiple events. + /// + /// Use cases: + /// - AI tool call grouping (e.g., "create_complex_object" → 50 events) + /// - User rapid operations (e.g., 5 component additions in 1.5s) + /// - Undo group alignment (one Ctrl+Z = one AtomicOperation) + /// + /// From ActionTrace-enhancements.md P1.1, line 189-198. + /// + public sealed class AtomicOperation + { + /// + /// First event sequence number in this transaction. + /// + public long StartSequence { get; set; } + + /// + /// Last event sequence number in this transaction. + /// + public long EndSequence { get; set; } + + /// + /// Human-readable summary of the entire transaction. + /// Examples: + /// - "Manage GameObject: 50 events in 2.3s" + /// - "Added Rigidbody to Player + 4 related events" + /// + public string Summary { get; set; } + + /// + /// Number of events in this transaction. + /// + public int EventCount { get; set; } + + /// + /// Duration of the transaction in milliseconds. + /// Time from first event to last event. + /// + public long DurationMs { get; set; } + + /// + /// Tool call identifier if this transaction represents a single tool call. + /// Null for time-based user operations. + /// + public string ToolCallId { get; set; } + + /// + /// Tool name that triggered this transaction. + /// Examples: "manage_gameobject", "add_ActionTrace_note" + /// Null for user manual operations. + /// + public string TriggeredByTool { get; set; } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Semantics/DefaultCategorizer.cs b/MCPForUnity/Editor/ActionTrace/Semantics/DefaultCategorizer.cs new file mode 100644 index 000000000..6331fdfd5 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Semantics/DefaultCategorizer.cs @@ -0,0 +1,27 @@ +namespace MCPForUnity.Editor.ActionTrace.Semantics +{ + /// + /// Default implementation of event categorization. + /// Maps importance scores to category labels. + /// + public sealed class DefaultCategorizer : IEventCategorizer + { + /// + /// Categorize an importance score into a label. + /// + public string Categorize(float score) + { + // Ensure score is in valid range + if (score < 0f) score = 0f; + if (score > 1f) score = 1f; + + return score switch + { + >= 0.9f => "critical", + >= 0.7f => "high", + >= 0.4f => "medium", + _ => "low" + }; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Semantics/DefaultEventScorer.cs b/MCPForUnity/Editor/ActionTrace/Semantics/DefaultEventScorer.cs new file mode 100644 index 000000000..928da2622 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Semantics/DefaultEventScorer.cs @@ -0,0 +1,122 @@ +using System; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Semantics +{ + /// + /// Default implementation of event importance scoring. + /// Scores are based on event type and payload characteristics. + /// + public sealed class DefaultEventScorer : IEventScorer + { + private static readonly Lazy _instance = new(() => new DefaultEventScorer()); + + /// + /// Singleton instance for use in EventStore importance filtering. + /// + public static DefaultEventScorer Instance => _instance.Value; + + /// + /// Calculate importance score for an event. + /// Higher scores indicate more significant events. + /// + /// Scoring strategy (L3 Semantic Whitelist): + /// - Critical (1.0): Build failures, AI notes, critical errors + /// - High (0.7-0.9): Scripts, Scenes, Component operations, Property changes + /// - Medium (0.4-0.6): GameObject operations, Asset imports + /// - Low (0.1-0.3): Hierarchy changes, Play mode toggles + /// + /// Default behavior: get_action_Trace only returns events with score >= 0.4 (medium+) + /// unless include_low_importance=true is specified. + /// + public float Score(EditorEvent evt) + { + // For dehydrated events (Payload is null), use a low default score + if (evt.Payload == null) + return 0.1f; + + return evt.Type switch + { + // ========== Critical (1.0) ========== + // Build failures and AI annotations are top priority + EventTypes.BuildFailed => 1.0f, + EventTypes.ScriptCompilationFailed => 1.0f, + "AINote" => 1.0f, // AI-written notes are always critical + + // ========== High (0.7-0.9) ========== + // Scripts and Scenes are project structure changes + EventTypes.AssetCreated or EventTypes.AssetImported when IsScript(evt) => 0.9f, + EventTypes.AssetCreated or EventTypes.AssetImported when IsScene(evt) => 0.7f, + EventTypes.AssetCreated or EventTypes.AssetImported when IsPrefab(evt) => 0.8f, + + // Component and Property modifications (direct user actions) + EventTypes.ComponentRemoved => 0.7f, + EventTypes.SelectionPropertyModified => 0.7f, // Selected object property changes are high priority + EventTypes.PropertyModified => 0.6f, // P0 property-level tracking + EventTypes.ComponentAdded => 0.6f, + + // Scene operations + EventTypes.SceneSaved => 0.8f, + EventTypes.SceneSaving => 0.5f, // Scene saving in progress + EventTypes.SceneOpened => 0.7f, + EventTypes.NewSceneCreated => 0.6f, // New scene creation + + // Build operations (success is important but less than failure) + EventTypes.BuildStarted => 0.9f, + EventTypes.BuildCompleted => 1.0f, + + // Destructive asset operations (high importance) + EventTypes.AssetDeleted => 0.8f, // Permanent deletion is critical + + // ========== Medium (0.4-0.6) ========== + // GameObject operations (structure changes) + EventTypes.GameObjectDestroyed => 0.6f, + EventTypes.GameObjectCreated => 0.5f, + EventTypes.AssetCreated or EventTypes.AssetImported => 0.5f, + EventTypes.AssetModified => 0.4f, // Asset content changes + EventTypes.ScriptCompiled => 0.4f, + + // ========== Low (0.1-0.3) ========== + // Hierarchy changes are noise (happen very frequently) + EventTypes.HierarchyChanged => 0.2f, + EventTypes.SelectionChanged => 0.1f, // Selection changes happen very frequently + EventTypes.AssetMoved => 0.3f, // Moving assets within project + EventTypes.PlayModeChanged => 0.3f, + + // Default low importance for unknown types + _ => 0.1f + }; + } + + private static bool IsScript(EditorEvent e) + { + if (e.Payload == null) return false; + if (e.Payload.TryGetValue("extension", out var ext)) + return ext.ToString() == ".cs"; + if (e.Payload.TryGetValue("type", out var type)) + return type.ToString()?.Contains("Script") == true || + type.ToString()?.Contains("MonoScript") == true; + return false; + } + + private static bool IsScene(EditorEvent e) + { + if (e.Payload == null) return false; + if (e.Payload.TryGetValue("extension", out var ext)) + return ext.ToString() == ".unity"; + if (e.Payload.TryGetValue("type", out var type)) + return type.ToString()?.Contains("Scene") == true; + return false; + } + + private static bool IsPrefab(EditorEvent e) + { + if (e.Payload == null) return false; + if (e.Payload.TryGetValue("extension", out var ext)) + return ext.ToString() == ".prefab"; + if (e.Payload.TryGetValue("type", out var type)) + return type.ToString()?.Contains("Prefab") == true; + return false; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Semantics/DefaultIntentInferrer.cs b/MCPForUnity/Editor/ActionTrace/Semantics/DefaultIntentInferrer.cs new file mode 100644 index 000000000..b926f9250 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Semantics/DefaultIntentInferrer.cs @@ -0,0 +1,160 @@ +using System.Collections.Generic; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Semantics +{ + /// + /// Default implementation of intent inference. + /// Analyzes events to infer user intent based on type and context. + /// + public sealed class DefaultIntentInferrer : IIntentInferrer + { + /// + /// Infer the intent behind an event. + /// Uses event type and payload to determine user intent. + /// + public string Infer(EditorEvent evt, IReadOnlyList surrounding) + { + // For dehydrated events (Payload is null), intent cannot be inferred, return null + if (evt.Payload == null) + return null; + + return evt.Type switch + { + // Asset-related intents + EventTypes.AssetCreated or EventTypes.AssetImported when IsScript(evt) => "Coding", + EventTypes.AssetCreated or EventTypes.AssetImported when IsScene(evt) => "Creating Scene", + EventTypes.AssetCreated or EventTypes.AssetImported when IsTexture(evt) => "Importing Texture", + EventTypes.AssetCreated or EventTypes.AssetImported when IsAudio(evt) => "Importing Audio", + EventTypes.AssetCreated or EventTypes.AssetImported when IsPrefab(evt) => "Creating Prefab", + EventTypes.AssetCreated or EventTypes.AssetImported => "Importing Asset", + + // GameObject operations + EventTypes.GameObjectCreated => "Adding GameObject", + EventTypes.GameObjectDestroyed => "Removing GameObject", + + // Component operations + EventTypes.ComponentAdded when IsRigidBody(evt) => "Adding Physics Component", + EventTypes.ComponentAdded when IsCollider(evt) => "Adding Collider", + EventTypes.ComponentAdded when IsScript(evt) => "Attaching Script", + EventTypes.ComponentAdded => "Adding Component", + EventTypes.ComponentRemoved => "Removing Component", + + // Scene operations + EventTypes.SceneSaved => "Saving Scene", + EventTypes.SceneOpened => "Opening Scene", + EventTypes.NewSceneCreated => "Creating New Scene", + + // Build operations + EventTypes.BuildStarted => "Build Started", + EventTypes.BuildCompleted => "Build Completed", + EventTypes.BuildFailed => "Build Failed", + + // Script operations + EventTypes.ScriptCompiled => "Compiling Scripts", + EventTypes.ScriptCompilationFailed => "Script Compilation Failed", + + // Hierarchy operations + EventTypes.HierarchyChanged when IsReparenting(surrounding) => "Adjusting Hierarchy", + EventTypes.HierarchyChanged when IsBatchOperation(surrounding) => "Batch Operation", + EventTypes.HierarchyChanged => null, // Too frequent, don't infer + + _ => null + }; + } + + private static bool IsScript(EditorEvent e) + { + if (e.Payload.TryGetValue("extension", out var ext)) + return ext.ToString() == ".cs"; + if (e.Payload.TryGetValue("component_type", out var type)) + return type.ToString()?.Contains("MonoBehaviour") == true; + return false; + } + + private static bool IsScene(EditorEvent e) + { + if (e.Payload.TryGetValue("extension", out var ext)) + return ext.ToString() == ".unity"; + return false; + } + + private static bool IsPrefab(EditorEvent e) + { + if (e.Payload.TryGetValue("extension", out var ext)) + return ext.ToString() == ".prefab"; + return false; + } + + private static bool IsTexture(EditorEvent e) + { + if (e.Payload.TryGetValue("extension", out var ext)) + { + var extStr = ext.ToString(); + return extStr == ".png" || extStr == ".jpg" || extStr == ".jpeg" || + extStr == ".psd" || extStr == ".tga" || extStr == ".exr"; + } + if (e.Payload.TryGetValue("type", out var type)) + return type.ToString()?.Contains("Texture") == true; + return false; + } + + private static bool IsAudio(EditorEvent e) + { + if (e.Payload.TryGetValue("extension", out var ext)) + { + var extStr = ext.ToString(); + return extStr == ".wav" || extStr == ".mp3" || extStr == ".ogg" || + extStr == ".aif" || extStr == ".aiff"; + } + return false; + } + + private static bool IsRigidBody(EditorEvent e) + { + if (e.Payload.TryGetValue("component_type", out var type)) + { + var typeStr = type.ToString(); + return typeStr == "Rigidbody" || typeStr == "Rigidbody2D"; + } + return false; + } + + private static bool IsCollider(EditorEvent e) + { + if (e.Payload.TryGetValue("component_type", out var type)) + { + var typeStr = type.ToString(); + return typeStr?.Contains("Collider") == true; + } + return false; + } + + private static bool IsReparenting(IReadOnlyList surrounding) + { + // If there are multiple hierarchy changes in quick succession, + // it's likely a reparenting operation + int count = 0; + foreach (var e in surrounding) + { + if (e.Type == "HierarchyChanged") count++; + if (count >= 3) return true; + } + return false; + } + + private static bool IsBatchOperation(IReadOnlyList surrounding) + { + // Many events of the same type suggest a batch operation + if (surrounding.Count < 5) return false; + + var firstType = surrounding[0].Type; + int sameTypeCount = 0; + foreach (var e in surrounding) + { + if (e.Type == firstType) sameTypeCount++; + } + return sameTypeCount >= 5; + } + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Semantics/IEventCategorizer.cs b/MCPForUnity/Editor/ActionTrace/Semantics/IEventCategorizer.cs new file mode 100644 index 000000000..4438b0065 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Semantics/IEventCategorizer.cs @@ -0,0 +1,17 @@ +namespace MCPForUnity.Editor.ActionTrace.Semantics +{ + /// + /// Event categorizer interface. + /// Converts importance scores into categorical labels. + /// Categories are computed at query time, not stored with events. + /// + public interface IEventCategorizer + { + /// + /// Categorize an importance score into a label. + /// + /// Importance score from 0.0 to 1.0 + /// Category label (e.g., "critical", "high", "medium", "low") + string Categorize(float score); + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Semantics/IEventScorer.cs b/MCPForUnity/Editor/ActionTrace/Semantics/IEventScorer.cs new file mode 100644 index 000000000..0286a889a --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Semantics/IEventScorer.cs @@ -0,0 +1,20 @@ +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Semantics +{ + /// + /// Event importance scorer interface. + /// Returns a float score (0.0 to 1.0) representing event importance. + /// Scores are computed at query time, not stored with events. + /// + public interface IEventScorer + { + /// + /// Calculate importance score for an event. + /// Higher values indicate more important events. + /// + /// The event to score + /// Score from 0.0 (least important) to 1.0 (most important) + float Score(EditorEvent evt); + } +} diff --git a/MCPForUnity/Editor/ActionTrace/Semantics/IIntentInferrer.cs b/MCPForUnity/Editor/ActionTrace/Semantics/IIntentInferrer.cs new file mode 100644 index 000000000..9b42437fd --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/Semantics/IIntentInferrer.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.ActionTrace.Semantics +{ + /// + /// Intent inference interface. + /// Analyzes events to infer the user's intent or purpose. + /// Intents are computed at query time using surrounding event context. + /// + public interface IIntentInferrer + { + /// + /// Infer the intent behind an event. + /// May analyze surrounding events to determine context. + /// + /// The event to analyze + /// Surrounding events for context (may be empty) + /// Inferred intent description, or null if unable to infer + string Infer(EditorEvent evt, IReadOnlyList surrounding); + } +} diff --git a/MCPForUnity/Editor/ActionTrace/VCS/VcsContextProvider.cs b/MCPForUnity/Editor/ActionTrace/VCS/VcsContextProvider.cs new file mode 100644 index 000000000..a26e177b7 --- /dev/null +++ b/MCPForUnity/Editor/ActionTrace/VCS/VcsContextProvider.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using UnityEditor; +using UnityEngine; + +namespace MCPForUnity.Editor.ActionTrace.VCS +{ + /// + /// Version Control System (VCS) integration for ActionTrace events. + /// + /// Purpose (from ActionTrace-enhancements.md P2.2): + /// - Track Git commit and branch information + /// - Mark events as "dirty" if they occurred after last commit + /// - Help AI understand "dirty state" (uncommitted changes) + /// + /// Implementation: + /// - Polls Git status periodically (via EditorApplication.delayCall) + /// - Injects vcs_context into event payloads + /// - Supports Git-only (Unity Collaborate, SVN, Perforce not implemented) + /// + /// Event payload format: + /// { + /// "sequence": 123, + /// "summary": "Added Rigidbody to Player", + /// "vcs_context": { + /// "commit_id": "abc123", + /// "branch": "feature/player-movement", + /// "is_dirty": true + /// } + /// } + /// + public static class VcsContextProvider + { + // Configuration + private const float PollIntervalSeconds = 5.0f; // Poll every 5 seconds + + // State + private static VcsContext _currentContext; + private static double _lastPollTime; + + /// + /// Initializes the VCS context provider and starts polling. + /// + static VcsContextProvider() + { + _currentContext = GetInitialContext(); + EditorApplication.update += OnUpdate; + } + + /// + /// Periodic update to refresh Git status. + /// + private static void OnUpdate() + { + if (EditorApplication.timeSinceStartup - _lastPollTime > PollIntervalSeconds) + { + RefreshContext(); + _lastPollTime = EditorApplication.timeSinceStartup; + } + } + + /// + /// Gets the current VCS context for event injection. + /// Thread-safe (called from any thread during event recording). + /// + public static VcsContext GetCurrentContext() + { + if (_currentContext == null) + { + _currentContext = GetInitialContext(); + } + + return _currentContext; + } + + /// + /// Refreshes the VCS context by polling Git status. + /// + private static void RefreshContext() + { + try + { + _currentContext = QueryGitStatus(); + } + catch (System.Exception ex) + { + UnityEngine.Debug.LogWarning($"[VcsContextProvider] Failed to query Git status: {ex.Message}"); + // Fall back to default context + _currentContext = VcsContext.CreateDefault(); + } + } + + /// + /// Queries Git status using git command. + /// Returns current commit, branch, and dirty state. + /// + private static VcsContext QueryGitStatus() + { + // Check if this is a Git repository + if (!IsGitRepository()) + { + return VcsContext.CreateDefault(); + } + + // Get current commit + var commitId = RunGitCommand("rev-parse HEAD"); + var shortCommit = commitId?.Length > 8 ? commitId.Substring(0, 8) : commitId; + + // Get current branch + var branch = RunGitCommand("rev-parse --abbrev-ref HEAD"); + + // Check if working tree is dirty + var statusOutput = RunGitCommand("status --porcelain"); + var isDirty = !string.IsNullOrEmpty(statusOutput); + + return new VcsContext + { + CommitId = shortCommit ?? "unknown", + Branch = branch ?? "unknown", + IsDirty = isDirty + }; + } + + /// + /// Gets initial VCS context on startup. + /// + private static VcsContext GetInitialContext() + { + try + { + return QueryGitStatus(); + } + catch + { + return VcsContext.CreateDefault(); + } + } + + /// + /// Checks if the current project is under Git version control. + /// + private static bool IsGitRepository() + { + try + { + var projectPath = System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath); + var gitPath = System.IO.Path.Combine(projectPath, ".git"); + + return System.IO.Directory.Exists(gitPath); + } + catch + { + return false; + } + } + + /// + /// Runs a Git command and returns stdout. + /// Returns null if command fails. + /// + private static string RunGitCommand(string arguments) + { + try + { + var projectPath = System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath); + var gitPath = System.IO.Path.Combine(projectPath, ".git"); + + // Find git executable + string gitExe = FindGitExecutable(); + if (string.IsNullOrEmpty(gitExe)) + return null; + + var startInfo = new ProcessStartInfo + { + FileName = gitExe, + Arguments = $"-C \"{projectPath}\" {arguments}", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + using (var process = Process.Start(startInfo)) + { + // Read both StandardOutput and StandardError simultaneously to avoid buffer blocking + var outputTask = System.Threading.Tasks.Task.Run(() => process.StandardOutput.ReadToEnd()); + var errorTask = System.Threading.Tasks.Task.Run(() => process.StandardError.ReadToEnd()); + + process.WaitForExit(); + + // Wait for both read tasks to complete + System.Threading.Tasks.Task.WaitAll(outputTask, errorTask); + + var output = outputTask.Result; + var error = errorTask.Result; + + // Log if there is error output + if (!string.IsNullOrEmpty(error)) + { + UnityEngine.Debug.LogWarning($"[VcsContextProvider] Git error: {error.Trim()}"); + } + + return output.Trim(); + } + } + catch (System.Exception ex) + { + UnityEngine.Debug.LogWarning($"[VcsContextProvider] Git command failed: {ex.Message}"); + return null; + } + } + + /// + /// Finds the Git executable path. + /// + private static string FindGitExecutable() + { + // Try common Git locations + string[] gitPaths = new[] + { + @"C:\Program Files\Git\bin\git.exe", + @"C:\Program Files (x86)\Git\bin\git.exe", + "/usr/bin/git", + "/usr/local/bin/git" + }; + + foreach (var path in gitPaths) + { + if (System.IO.File.Exists(path)) + return path; + } + + // Try system PATH + try + { + var startInfo = new ProcessStartInfo + { + FileName = "git", + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using (var process = Process.Start(startInfo)) + { + process.WaitForExit(); + if (process.ExitCode == 0) + return "git"; // Found in PATH + } + } + catch + { + // Git executable not found in PATH + } + + return null; + } + } + + /// + /// Represents the VCS context at the time of event recording. + /// + public sealed class VcsContext + { + /// + /// Current Git commit hash (short form, 8 characters). + /// Example: "abc12345" + /// + public string CommitId { get; set; } + + /// + /// Current Git branch name. + /// Example: "feature/player-movement", "main" + /// + public string Branch { get; set; } + + /// + /// Whether the working tree has uncommitted changes. + /// True if there are modified/new/deleted files not yet committed. + /// + public bool IsDirty { get; set; } + + // Cached dictionary to prevent repeated allocations + private Dictionary _cachedDictionary; + private string _lastCachedCommitId; + private string _lastCachedBranch; + private bool _lastCachedIsDirty; + + /// + /// Creates a default Vcs context for non-Git repositories. + /// + public static VcsContext CreateDefault() + { + return new VcsContext + { + CommitId = "unknown", + Branch = "unknown", + IsDirty = false + }; + } + + /// + /// Converts this context to a dictionary for event payload injection. + /// Uses caching to prevent repeated allocations (called on every event record). + /// + public Dictionary ToDictionary() + { + // Check if cache is valid (no fields changed since last call) + if (_cachedDictionary != null && + _lastCachedCommitId == CommitId && + _lastCachedBranch == Branch && + _lastCachedIsDirty == IsDirty) + { + return _cachedDictionary; + } + + // Cache is invalid or doesn't exist - create new dictionary + _cachedDictionary = new Dictionary + { + ["commit_id"] = CommitId, + ["branch"] = Branch, + ["is_dirty"] = IsDirty + }; + + // Update cache validation fields + _lastCachedCommitId = CommitId; + _lastCachedBranch = Branch; + _lastCachedIsDirty = IsDirty; + + return _cachedDictionary; + } + } +} diff --git a/MCPForUnity/Editor/Helpers/AssetPathUtility.cs b/MCPForUnity/Editor/Helpers/AssetPathUtility.cs index 34c9ea49d..025344c5c 100644 --- a/MCPForUnity/Editor/Helpers/AssetPathUtility.cs +++ b/MCPForUnity/Editor/Helpers/AssetPathUtility.cs @@ -158,8 +158,10 @@ public static string GetMcpServerPackageSource() { // Check for override first (supports git URLs, file:// paths, local paths) string sourceOverride = EditorPrefs.GetString(EditorPrefKeys.GitUrlOverride, ""); + McpLog.Info($"[DEBUG] GitUrlOverride key: '{EditorPrefKeys.GitUrlOverride}', value: '{sourceOverride}'"); if (!string.IsNullOrEmpty(sourceOverride)) { + McpLog.Info($"[DEBUG] Using override: {sourceOverride}"); return sourceOverride; } diff --git a/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs b/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs index c280d9559..74f122b36 100644 --- a/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs +++ b/MCPForUnity/Editor/MenuItems/MCPForUnityMenu.cs @@ -32,5 +32,11 @@ public static void ShowEditorPrefsWindow() { EditorPrefsWindow.ShowWindow(); } + + [MenuItem("Window/MCP For Unity/ActionTrace", priority = 4)] + public static void ShowActionTraceWindow() + { + ActionTraceEditorWindow.ShowWindow(); + } } } diff --git a/MCPForUnity/Editor/Resources/ActionTrace/ActionTraceViewResource.cs b/MCPForUnity/Editor/Resources/ActionTrace/ActionTraceViewResource.cs new file mode 100644 index 000000000..21f3b16b0 --- /dev/null +++ b/MCPForUnity/Editor/Resources/ActionTrace/ActionTraceViewResource.cs @@ -0,0 +1,549 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Remoting.Contexts; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Context; +using MCPForUnity.Editor.ActionTrace.Core; +using MCPForUnity.Editor.ActionTrace.Query; +using MCPForUnity.Editor.ActionTrace.Semantics; +using Newtonsoft.Json.Linq; +using static MCPForUnity.Editor.ActionTrace.Query.ActionTraceQuery; + +namespace MCPForUnity.Editor.Resources.ActionTrace +{ + /// + /// MCP resource for querying the action trace of editor events. + /// + /// URI: mcpforunity://action_trace_view + /// + /// Parameters: + /// - limit: Maximum number of events to return (default: 50) + /// - since_sequence: Only return events after this sequence number + /// - include_context: If true, include context associations (default: false) + /// - include_semantics: If true, include importance, category, intent (default: false) + /// - min_importance: Minimum importance score to include (default: "medium") + /// Options: "low" (0.0+), "medium" (0.4+), "high" (0.7+), "critical" (0.9+) + /// - source: Filter by operation source: "ai", "human", "system" (optional) + /// + /// L3 Semantic Whitelist: + /// By default, only events with importance >= 0.4 (medium+) are returned. + /// To include low-importance events like HierarchyChanged, specify min_importance="low". + /// + [McpForUnityResource("action_trace_view")] + public static class ActionTraceViewResource + { + public static object HandleCommand(JObject @params) + { + try + { + int limit = GetLimit(@params); + long? sinceSequence = GetSinceSequence(@params); + bool includeContext = GetIncludeContext(@params); + bool includeSemantics = GetIncludeSemantics(@params); + string sourceFilter = GetSourceFilter(@params); + + // L3 Semantic Whitelist: Parse minimum importance threshold + float minImportance = GetMinImportance(@params); + + // P1.2 Task-Level Filtering: Parse task and conversation IDs + string taskId = GetTaskId(@params); + string conversationId = GetConversationId(@params); + + // P1.1 Transaction Aggregation: Parse summary_only parameter + bool summaryOnly = GetSummaryOnly(@params); + + // If summary_only is requested, return aggregated transactions + if (summaryOnly) + { + return QueryAggregated(limit, sinceSequence, minImportance, taskId, conversationId); + } + + // Decide query mode based on parameters + bool useContextQuery = includeContext || !string.IsNullOrEmpty(sourceFilter); + + if (useContextQuery) + { + return QueryWithContext(limit, sinceSequence, sourceFilter, includeSemantics, minImportance, taskId, conversationId); + } + + if (includeSemantics) + { + return QueryWithSemanticsOnly(limit, sinceSequence, minImportance, taskId, conversationId); + } + + // Basic query without context or semantics (apply importance filter anyway) + return QueryBasic(limit, sinceSequence, minImportance, taskId, conversationId); + } + catch (Exception ex) + { + McpLog.Error($"[ActionTraceViewResource] Error: {ex.Message}"); + return new ErrorResponse($"Error retrieving ActionTrace: {ex.Message}"); + } + } + + /// + /// Basic query without context or semantics + /// Applies L3 importance filter by default (medium+ importance). + /// P1.2: Supports task_id and conversation_id filtering. + /// + private static object QueryBasic(int limit, long? sinceSequence, float minImportance, string taskId, string conversationId) + { + var events = EventStore.Query(limit, sinceSequence); + + // L3 Semantic Whitelist: Filter by importance + var scorer = new DefaultEventScorer(); + var filteredEvents = events + .Where(e => scorer.Score(e) >= minImportance) + .ToList(); + + // P1.2 Task-Level Filtering: Filter by task_id and conversation_id + filteredEvents = ApplyTaskFilters(filteredEvents, taskId, conversationId); + + var eventItems = filteredEvents.Select(e => new + { + sequence = e.Sequence, + timestamp_unix_ms = e.TimestampUnixMs, + type = e.Type, + target_id = e.TargetId, + summary = EventSummarizer.Summarize(e) + }).ToArray(); + + return new SuccessResponse("Retrieved ActionTrace events.", new + { + schema_version = "action_trace_view@1", + events = eventItems, + total_count = eventItems.Length, + current_sequence = EventStore.CurrentSequence + }); + } + + /// + /// Query with semantics but without context + /// Applies L3 importance filter by default. + /// P1.2: Supports task_id and conversation_id filtering. + /// + private static object QueryWithSemanticsOnly(int limit, long? sinceSequence, float minImportance, string taskId, string conversationId) + { + var rawEvents = EventStore.Query(limit, sinceSequence); + var query = new ActionTraceQuery(); + var projected = query.Project(rawEvents); + + // L3 Semantic Whitelist: Filter by importance + var filtered = projected + .Where(p => p.ImportanceScore >= minImportance) + .ToList(); + + // P1.2 Task-Level Filtering: Filter by task_id and conversation_id + filtered = ApplyTaskFiltersToProjected(filtered, taskId, conversationId); + + var eventItems = filtered.Select(p => new + { + sequence = p.Event.Sequence, + timestamp_unix_ms = p.Event.TimestampUnixMs, + type = p.Event.Type, + target_id = p.Event.TargetId, + summary = EventSummarizer.Summarize(p.Event), + importance_score = p.ImportanceScore, + importance_category = p.ImportanceCategory, + inferred_intent = p.InferredIntent + }).ToArray(); + + return new SuccessResponse("Retrieved ActionTrace events with semantics.", new + { + schema_version = "action_trace_view@3", + events = eventItems, + total_count = eventItems.Length, + current_sequence = EventStore.CurrentSequence + }); + } + + /// + /// Query with context and optional semantics + /// Note: Source filtering requires persistent OperationContext storage. + /// + private static object QueryWithContext(int limit, long? sinceSequence, string sourceFilter, bool includeSemantics, float minImportance, string taskId, string conversationId) + { + // Check if source filter is requested (requires persistent context storage) + if (!string.IsNullOrEmpty(sourceFilter)) + { + return new ErrorResponse( + "Source filtering requires persistent OperationContext storage. " + + "The 'source' parameter is not yet supported." + ); + } + + var eventsWithContext = EventStore.QueryWithContext(limit, sinceSequence); + + // Apply semantics if requested + if (includeSemantics) + { + var query = new ActionTraceQuery(); + var projected = query.ProjectWithContext(eventsWithContext); + + // L3 Semantic Whitelist: Filter by importance + var filtered = projected + .Where(p => p.ImportanceScore >= minImportance) + .ToList(); + + var events = filtered.Select(p => + { + var hasContext = p.Context != null; + var contextId = hasContext ? p.Context.ContextId.ToString() : null; + + return new + { + sequence = p.Event.Sequence, + timestamp_unix_ms = p.Event.TimestampUnixMs, + type = p.Event.Type, + target_id = p.Event.TargetId, + summary = EventSummarizer.Summarize(p.Event), + has_context = hasContext, + context = hasContext ? new { context_id = contextId } : null, + importance_score = p.ImportanceScore, + importance_category = p.ImportanceCategory, + inferred_intent = p.InferredIntent + }; + }).ToArray(); + + return new SuccessResponse("Retrieved ActionTrace events with context and semantics.", new + { + schema_version = "action_trace_view@3", + events = events, + total_count = events.Length, + current_sequence = EventStore.CurrentSequence, + context_mapping_count = EventStore.ContextMappingCount + }); + } + else + { + // Context only response - apply importance filter manually + var scorer = new DefaultEventScorer(); + var filtered = eventsWithContext + .Where(x => scorer.Score(x.Event) >= minImportance) + .ToList(); + + var events = filtered.Select(x => + { + var hasContext = x.Context != null; + var contextId = hasContext ? x.Context.ContextId.ToString() : null; + + return new + { + sequence = x.Event.Sequence, + timestamp_unix_ms = x.Event.TimestampUnixMs, + type = x.Event.Type, + target_id = x.Event.TargetId, + summary = EventSummarizer.Summarize(x.Event), + has_context = hasContext, + context = hasContext ? new { context_id = contextId } : null + }; + }).ToArray(); + + return new SuccessResponse("Retrieved ActionTrace events with context.", new + { + schema_version = "action_trace_view@2", + events = events, + total_count = events.Length, + current_sequence = EventStore.CurrentSequence, + context_mapping_count = EventStore.ContextMappingCount + }); + } + } + + private static int GetLimit(JObject @params) + { + var limitToken = @params["limit"] ?? @params["count"]; + if (limitToken != null && int.TryParse(limitToken.ToString(), out int limit)) + { + return Math.Clamp(limit, 1, 1000); + } + return 50; // Default + } + + private static long? GetSinceSequence(JObject @params) + { + var sinceToken = @params["since_sequence"] ?? @params["sinceSequence"] ?? @params["since"]; + if (sinceToken != null && long.TryParse(sinceToken.ToString(), out long since)) + { + return since; + } + return null; + } + + private static bool GetIncludeContext(JObject @params) + { + var includeToken = @params["include_context"] ?? @params["includeContext"]; + if (includeToken != null) + { + if (bool.TryParse(includeToken.ToString(), out bool include)) + { + return include; + } + } + return false; + } + + private static string GetSourceFilter(JObject @params) + { + var sourceToken = @params["source"] ?? @params["operation_source"]; + return sourceToken?.ToString(); + } + + private static bool GetIncludeSemantics(JObject @params) + { + var includeToken = @params["include_semantics"] ?? @params["includeSemantics"]; + if (includeToken != null) + { + if (bool.TryParse(includeToken.ToString(), out bool include)) + { + return include; + } + } + return false; + } + + /// + /// L3 Semantic Whitelist: Parse minimum importance threshold. + /// + /// Default: "medium" (0.4) - filters out low-importance noise like HierarchyChanged + /// + /// Options: + /// - "low" or 0.0: Include all events + /// - "medium" or 0.4: Include meaningful operations (default) + /// - "high" or 0.7: Include only significant changes + /// - "critical" or 0.9: Include only critical events (build failures, AI notes) + /// + /// Returns: float threshold for importance filtering + /// + private static float GetMinImportance(JObject @params) + { + var importanceToken = @params["min_importance"] ?? @params["minImportance"]; + if (importanceToken != null) + { + string importanceStr = importanceToken.ToString()?.ToLower()?.Trim(); + + // Parse string values + if (!string.IsNullOrEmpty(importanceStr)) + { + return importanceStr switch + { + "low" => 0.0f, + "medium" => 0.4f, + "high" => 0.7f, + "critical" => 0.9f, + _ => float.TryParse(importanceStr, out float val) ? val : 0.4f + }; + } + } + + // Default to medium importance (L3 Semantic Whitelist active by default) + return 0.4f; + } + + /// + /// P1.2: Parse task_id parameter. + /// + private static string GetTaskId(JObject @params) + { + var token = @params["task_id"] ?? @params["taskId"]; + return token?.ToString(); + } + + /// + /// P1.2: Parse conversation_id parameter. + /// + private static string GetConversationId(JObject @params) + { + var token = @params["conversation_id"] ?? @params["conversationId"]; + return token?.ToString(); + } + + /// + /// P1.2: Apply task_id and conversation_id filters to raw event list. + /// Filters AINote events by matching task_id and conversation_id in payload. + /// + private static List ApplyTaskFilters(List events, string taskId, string conversationId) + { + // If no filters specified, return original list + if (string.IsNullOrEmpty(taskId) && string.IsNullOrEmpty(conversationId)) + return events; + + return events.Where(e => + { + // Only AINote events have task_id and conversation_id + if (e.Type != "AINote") + return true; // Keep non-AINote events + + // Check task_id filter + if (!string.IsNullOrEmpty(taskId)) + { + if (e.Payload.TryGetValue("task_id", out var taskVal)) + { + string eventTaskId = taskVal?.ToString(); + if (eventTaskId != taskId) + return false; // Filter out: task_id doesn't match + } + else + { + return false; // Filter out: AINote without task_id + } + } + + // Check conversation_id filter + if (!string.IsNullOrEmpty(conversationId)) + { + if (e.Payload.TryGetValue("conversation_id", out var convVal)) + { + string eventConvId = convVal?.ToString(); + if (eventConvId != conversationId) + return false; // Filter out: conversation_id doesn't match + } + } + + return true; // Keep: passed all filters + }).ToList(); + } + + /// + /// P1.2: Apply task filters to projected events (with semantics). + /// + private static List ApplyTaskFiltersToProjected(List projected, string taskId, string conversationId) + { + if (string.IsNullOrEmpty(taskId) && string.IsNullOrEmpty(conversationId)) + return projected; + + return projected.Where(p => + { + if (p.Event.Type != "AINote") + return true; + + if (!string.IsNullOrEmpty(taskId)) + { + if (p.Event.Payload.TryGetValue("task_id", out var taskVal)) + { + if (taskVal?.ToString() != taskId) + return false; + } + else + { + return false; + } + } + + if (!string.IsNullOrEmpty(conversationId)) + { + if (p.Event.Payload.TryGetValue("conversation_id", out var convVal)) + { + if (convVal?.ToString() != conversationId) + return false; + } + } + + return true; + }).ToList(); + } + + /// + /// P1.2: Apply task filters to EventWithContext list. + /// + private static List<(EditorEvent Event, ContextMapping Context)> ApplyTaskFiltersToEventWithContext(List<(EditorEvent Event, ContextMapping Context)> eventsWithContext, string taskId, string conversationId) + { + if (string.IsNullOrEmpty(taskId) && string.IsNullOrEmpty(conversationId)) + return eventsWithContext; + + return eventsWithContext.Where(x => + { + if (x.Event.Type != "AINote") + return true; + + if (!string.IsNullOrEmpty(taskId)) + { + if (x.Event.Payload.TryGetValue("task_id", out var taskVal)) + { + if (taskVal?.ToString() != taskId) + return false; + } + else + { + return false; + } + } + + if (!string.IsNullOrEmpty(conversationId)) + { + if (x.Event.Payload.TryGetValue("conversation_id", out var convVal)) + { + if (convVal?.ToString() != conversationId) + return false; + } + } + + return true; + }).ToList(); + } + + /// + /// P1.1: Parse summary_only parameter. + /// + private static bool GetSummaryOnly(JObject @params) + { + var token = @params["summary_only"] ?? @params["summaryOnly"]; + if (token != null) + { + if (bool.TryParse(token.ToString(), out bool summaryOnly)) + { + return summaryOnly; + } + } + return false; // Default to false + } + + /// + /// P1.1: Query with transaction aggregation. + /// + /// Returns AtomicOperation list instead of raw events. + /// Reduces token consumption by grouping related events. + /// + /// From ActionTrace-enhancements.md line 294-300: + /// "summary_only=True 时返回 AtomicOperation 列表而非原始事件" + /// + private static object QueryAggregated(int limit, long? sinceSequence, float minImportance, string taskId, string conversationId) + { + // Step 1: Query raw events + var events = EventStore.Query(limit, sinceSequence); + + // Step 2: Apply importance filter (L3 Semantic Whitelist) + var scorer = new DefaultEventScorer(); + var filteredEvents = events + .Where(e => scorer.Score(e) >= minImportance) + .ToList(); + + // Step 3: Apply task-level filtering (P1.2) + filteredEvents = ApplyTaskFilters(filteredEvents, taskId, conversationId); + + // Step 4: Aggregate into transactions + var operations = TransactionAggregator.Aggregate(filteredEvents); + + // Step 5: Project to response format + var eventItems = operations.Select(op => new + { + start_sequence = op.StartSequence, + end_sequence = op.EndSequence, + summary = op.Summary, + event_count = op.EventCount, + duration_ms = op.DurationMs, + tool_call_id = op.ToolCallId, + triggered_by_tool = op.TriggeredByTool + }).ToArray(); + + return new SuccessResponse($"Retrieved {eventItems.Length} aggregated operations.", new + { + schema_version = "action_trace_view@4", + events = eventItems, + total_count = eventItems.Length, + current_sequence = EventStore.CurrentSequence + }); + } + } +} diff --git a/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs b/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs index 30e31958e..472f332ad 100644 --- a/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs +++ b/MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs @@ -168,6 +168,43 @@ static StdioBridgeHost() ScheduleInitRetry(); } }; + + // CRITICAL FIX: Stop listener BEFORE domain reload to prevent zombie listeners + // Domain reload does NOT trigger EditorApplication.quitting, so we must + // explicitly stop here. This prevents the old domain's listener from + // remaining bound to the port after the new domain loads. + try + { + var assemblyReloadEventsType = Type.GetType("UnityEditor.AssemblyReloadEvents, UnityEditor"); + if (assemblyReloadEventsType != null) + { + var beforeAssemblyReloadEvent = assemblyReloadEventsType.GetEvent("beforeAssemblyReload"); + if (beforeAssemblyReloadEvent != null) + { + beforeAssemblyReloadEvent.AddEventHandler(null, new System.Action(OnBeforeAssemblyReload)); + if (IsDebugEnabled()) + McpLog.Info("[StdioBridgeHost] Registered beforeAssemblyReload handler"); + } + } + } + catch { } + } + + /// + /// Called immediately before Unity performs a domain reload (script compilation). + /// This is CRITICAL for preventing zombie listeners because EditorApplication.quitting + /// is NOT triggered during domain reload. + /// + private static void OnBeforeAssemblyReload() + { + if (IsDebugEnabled()) + McpLog.Info("[StdioBridgeHost] beforeAssemblyReload: stopping listener to prevent zombie"); + + // Mark as reloading in heartbeat status file + WriteHeartbeat(true, "domain_reload"); + + // Stop the listener BEFORE domain reload + Stop(); } private static void InitializeAfterCompilation() @@ -278,6 +315,85 @@ private static bool IsCompiling() return false; } + /// + /// Detects and attempts to cleanup zombie listeners from previous Unity sessions. + /// After domain reload, the old listener may still be bound to the port even though + /// our static fields are reset. This method probes the port and closes zombie connections. + /// + private static void CleanupZombieListeners(int port) + { + try + { + // Try to detect if there's a listener on the port that doesn't respond to handshake + using (var testClient = new TcpClient()) + { + try + { + // Try quick connect with short timeout + var connectTask = testClient.ConnectAsync(IPAddress.Loopback, port); + if (connectTask.Wait(500) && testClient.Connected) + { + // Connection succeeded - try to receive handshake + testClient.ReceiveTimeout = 500; + var stream = testClient.GetStream(); + byte[] buffer = new byte[256]; + + // Try to read handshake + int bytesRead = stream.Read(buffer, 0, buffer.Length); + string response = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead); + + // If we get the expected handshake, it's a healthy listener + if (response.Contains("FRAMING=1") || response.Contains("WELCOME")) + { + if (IsDebugEnabled()) + McpLog.Info($"[Cleanup] Port {port}: healthy MCP listener detected"); + testClient.Close(); + return; // Healthy listener, don't cleanup + } + + // If we get here, connection succeeded but no proper handshake + // This is likely a zombie listener - close the connection + if (IsDebugEnabled()) + McpLog.Warn($"[Cleanup] Port {port}: zombie listener detected (no handshake), attempting cleanup"); + + testClient.Close(); + + // Give the zombie listener a moment to release the port + Thread.Sleep(100); + + // Try a few more times to force the zombie to release + for (int i = 0; i < 5; i++) + { + using (var forceClient = new TcpClient()) + { + try + { + if (forceClient.ConnectAsync(IPAddress.Loopback, port).Wait(200)) + { + forceClient.Close(); + } + } + catch { } + } + Thread.Sleep(50); + } + } + } + catch (SocketException) + { + // Port not in use - no cleanup needed + if (IsDebugEnabled()) + McpLog.Info($"[Cleanup] Port {port}: not in use"); + } + } + } + catch (Exception ex) + { + if (IsDebugEnabled()) + McpLog.Debug($"[Cleanup] Error during zombie cleanup: {ex.Message}"); + } + } + public static void Start() { lock (startStopLock) @@ -293,9 +409,12 @@ public static void Start() Stop(); + // Get the port and cleanup any zombie listeners before starting + currentUnityPort = PortManager.GetPortWithFallback(); + CleanupZombieListeners(currentUnityPort); + try { - currentUnityPort = PortManager.GetPortWithFallback(); LogBreadcrumb("Start"); @@ -389,16 +508,17 @@ private static TcpListener CreateConfiguredListener(int port) { var newListener = new TcpListener(IPAddress.Loopback, port); #if !UNITY_EDITOR_OSX - newListener.Server.SetSocketOption( - SocketOptionLevel.Socket, - SocketOptionName.ReuseAddress, - true - ); + // NOTE: We do NOT set ReuseAddress=true to prevent zombie listeners from domain reload. + // Without SO_REUSEADDRESS, if an old listener is still bound, the new bind will fail + // with AddressAlreadyInUse, and the retry logic will wait for the OS to clean up the old socket. + // This is safer than allowing multiple listeners on the same port (zombie problem). + // macOS still needs ReuseAddress for proper domain reload behavior. #endif #if UNITY_EDITOR_WIN try { - newListener.ExclusiveAddressUse = false; + // Explicitly enable exclusive address use to prevent multiple bindings + newListener.ExclusiveAddressUse = true; } catch { } #endif @@ -442,6 +562,16 @@ public static void Stop() } } + // Clear the resume flag when stopping for reasons other than domain reload. + // This prevents the UI from getting stuck showing "Resuming..." when a client disconnects. + // We skip clearing during assembly reloads since OnBeforeAssemblyReload sets the flag + // and OnAfterAssemblyReload expects it to still be set. + bool isReloading = EditorApplication.isCompiling; + if (!isReloading) + { + try { EditorPrefs.DeleteKey(EditorPrefKeys.ResumeStdioAfterReload); } catch { } + } + TcpClient[] toClose; lock (clientsLock) { diff --git a/MCPForUnity/Editor/Tools/ActionTraceSettingsTool.cs b/MCPForUnity/Editor/Tools/ActionTraceSettingsTool.cs new file mode 100644 index 000000000..7c59a6421 --- /dev/null +++ b/MCPForUnity/Editor/Tools/ActionTraceSettingsTool.cs @@ -0,0 +1,64 @@ +using System; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Core; +using Newtonsoft.Json.Linq; + +namespace MCPForUnity.Editor.Tools +{ + /// + /// MCP tool for querying ActionTrace system settings. + /// + /// Returns the current configuration of the ActionTrace system, + /// allowing Python端 to access live settings instead of hardcoded defaults. + /// + [McpForUnityTool("get_action_trace_settings")] + public static class ActionTraceSettingsTool + { + /// + /// Parameters for get_action_trace_settings tool. + /// This tool takes no parameters. + /// + public class Parameters + { + // No parameters required + } + + public static object HandleCommand(JObject @params) + { + try + { + var settings = ActionTraceSettings.Instance; + + return new SuccessResponse("Retrieved ActionTrace settings.", new + { + schema_version = "action_trace_settings@1", + + // Event filtering + min_importance_for_recording = settings.MinImportanceForRecording, + disabled_event_types = settings.DisabledEventTypes, + + // Event merging + enable_event_merging = settings.EnableEventMerging, + merge_window_ms = settings.MergeWindowMs, + + // Storage limits + max_events = settings.MaxEvents, + hot_event_count = settings.HotEventCount, + + // Transaction aggregation + transaction_window_ms = settings.TransactionWindowMs, + + // Current store state + current_sequence = EventStore.CurrentSequence, + total_events_stored = EventStore.Count, + context_mapping_count = EventStore.ContextMappingCount + }); + } + catch (Exception ex) + { + McpLog.Error($"[ActionTraceSettingsTool] Error: {ex.Message}"); + return new ErrorResponse($"Failed to get ActionTrace settings: {ex.Message}"); + } + } + } +} diff --git a/MCPForUnity/Editor/Tools/AddTimelineNoteTool.cs b/MCPForUnity/Editor/Tools/AddTimelineNoteTool.cs new file mode 100644 index 000000000..2a7e3cd62 --- /dev/null +++ b/MCPForUnity/Editor/Tools/AddTimelineNoteTool.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Core; + +namespace MCPForUnity.Editor.Tools +{ + /// + /// MCP Tool for adding AI comments/notes to the ActionTrace. + /// + /// Usage: AI agents call this tool to record summaries, decisions, or task completion notes. + /// + /// Multi-Agent Collaboration: + /// - task_id: Groups all notes from a single task (e.g., "refactor-player-movement") + /// - conversation_id: Tracks continuity across sessions + /// - agent_id: Identifies which AI wrote the note + /// + /// Example payload: + /// { + /// "note": "完成玩家移动系统的重构,速度从 5 提升到 8", + /// "agent_id": "ChatGLM 1337", + /// "intent": "refactoring", + /// "task_id": "task-abc123", + /// "conversation_id": "conv-xyz789", + /// "related_sequences": [100, 101, 102] + /// } + /// + [McpForUnityTool("add_action_trace_note")] + public static class AddActionTraceNoteTool + { + /// + /// Parameters for add_action_trace_note tool. + /// + public class Parameters + { + /// + /// The note text to record + /// + [ToolParameter("The note text to record", Required = true)] + public string Note { get; set; } + + /// + /// Identifies which AI wrote the note (default: "unknown") + /// + [ToolParameter("Identifies which AI wrote the note", Required = false, DefaultValue = "unknown")] + public string AgentId { get; set; } = "unknown"; + + /// + /// Groups all notes from a single task + /// + [ToolParameter("Groups all notes from a single task (e.g., 'refactor-player-movement')", Required = false)] + public string TaskId { get; set; } + + /// + /// Tracks continuity across sessions + /// + [ToolParameter("Tracks continuity across sessions", Required = false)] + public string ConversationId { get; set; } + + /// + /// Intent or purpose of the note + /// + [ToolParameter("Intent or purpose of the note", Required = false)] + public string Intent { get; set; } + + /// + /// Model identifier of the AI agent + /// + [ToolParameter("Model identifier of the AI agent", Required = false)] + public string AgentModel { get; set; } + + /// + /// Related event sequences to link with this note + /// + [ToolParameter("Related event sequences to link with this note", Required = false)] + public long[] RelatedSequences { get; set; } + } + + public static object HandleCommand(JObject @params) + { + try + { + // Required parameters + string note = @params["note"]?.ToString(); + if (string.IsNullOrEmpty(note)) + { + return new ErrorResponse("Note text is required."); + } + + // Support both snake_case (legacy) and camelCase (normalized by batch_execute) + string agentId = @params["agent_id"]?.ToString() ?? @params["agentId"]?.ToString() ?? "unknown"; + string taskId = @params["task_id"]?.ToString() ?? @params["taskId"]?.ToString(); + string conversationId = @params["conversation_id"]?.ToString() ?? @params["conversationId"]?.ToString(); + + // Build payload with all fields + var payload = new Dictionary + { + ["note"] = note, + ["agent_id"] = agentId + }; + + // Task-level tracking (P1.2 multi-agent collaboration) + if (!string.IsNullOrEmpty(taskId)) + { + payload["task_id"] = taskId; + } + + // Conversation-level tracking (cross-session continuity) + if (!string.IsNullOrEmpty(conversationId)) + { + payload["conversation_id"] = conversationId; + } + + // Optional fields - support both snake_case and camelCase + var intentToken = @params["intent"] ?? @params["Intent"]; + if (intentToken != null) + { + payload["intent"] = intentToken.ToString(); + } + + var agentModelToken = @params["agent_model"] ?? @params["agentModel"]; + if (agentModelToken != null) + { + payload["agent_model"] = agentModelToken.ToString(); + } + + // Related event sequences (if explicitly linking to specific events) + var relatedSeqToken = @params["related_sequences"] ?? @params["relatedSequences"]; + if (relatedSeqToken != null) + { + try + { + var relatedSeqs = relatedSeqToken.ToObject(); + if (relatedSeqs != null && relatedSeqs.Length > 0) + { + payload["related_sequences"] = relatedSeqs; + } + } + catch (Exception ex) + { + McpLog.Warn($"[AddActionTraceNoteTool] Failed to parse related_sequences: {ex.Message}"); + } + } + + // Record the AINote event + var evt = new EditorEvent( + sequence: 0, // Assigned by EventStore.Record() + timestampUnixMs: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + type: "AINote", // P1.2: AI notes are always critical importance + targetId: $"agent:{agentId}", + payload: payload + ); + + long recordedSequence = EventStore.Record(evt); + + return new SuccessResponse($"AI note added to action trace (sequence {recordedSequence})", new + { + sequence = recordedSequence, + timestamp_unix_ms = evt.TimestampUnixMs, + task_id = taskId, + conversation_id = conversationId + }); + } + catch (Exception ex) + { + McpLog.Error($"[AddActionTraceNoteTool] Error: {ex.Message}"); + return new ErrorResponse($"Failed to add action trace note: {ex.Message}"); + } + } + } +} diff --git a/MCPForUnity/Editor/Tools/GetActionTraceTool.cs b/MCPForUnity/Editor/Tools/GetActionTraceTool.cs new file mode 100644 index 000000000..d6060c80e --- /dev/null +++ b/MCPForUnity/Editor/Tools/GetActionTraceTool.cs @@ -0,0 +1,86 @@ +using System; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.Resources.ActionTrace; +using Newtonsoft.Json.Linq; + +namespace MCPForUnity.Editor.Tools +{ + /// + /// MCP tool for querying the action trace of editor events. + /// + /// This is a convenience wrapper around ActionTraceViewResource that provides + /// a cleaner "get_action_trace" tool name for AI consumption. + /// + [McpForUnityTool("get_action_trace")] + public static class GetActionTraceTool + { + /// + /// Parameters for get_action_trace tool. + /// + public class Parameters + { + /// + /// Maximum number of events to return (1-1000, default: 50) + /// + [ToolParameter("Maximum number of events to return (1-1000, default: 50)", Required = false, DefaultValue = "50")] + public int Limit { get; set; } = 50; + + /// + /// Only return events after this sequence number (for incremental queries) + /// + [ToolParameter("Only return events after this sequence number", Required = false)] + public long? SinceSequence { get; set; } + + /// + /// Filter by event types (e.g., ["GameObjectCreated", "ComponentAdded"]) + /// + [ToolParameter("Filter by event types", Required = false)] + public string[] EventTypes { get; set; } + + /// + /// Whether to include full event payload (default: true) + /// + [ToolParameter("Whether to include full event payload", Required = false, DefaultValue = "true")] + public bool IncludePayload { get; set; } = true; + + /// + /// Whether to include context associations (default: false) + /// + [ToolParameter("Whether to include context associations", Required = false, DefaultValue = "false")] + public bool IncludeContext { get; set; } = false; + + /// + /// Whether to include semantic analysis results (importance, category, intent) + /// + [ToolParameter("Whether to include semantic analysis results", Required = false, DefaultValue = "false")] + public bool IncludeSemantics { get; set; } = false; + + /// + /// Minimum importance level (low/medium/high/critical) + /// + [ToolParameter("Minimum importance level", Required = false, DefaultValue = "medium")] + public string MinImportance { get; set; } = "medium"; + + /// + /// Filter by task ID + /// + [ToolParameter("Filter by task ID", Required = false)] + public string TaskId { get; set; } + + /// + /// Filter by conversation ID + /// + [ToolParameter("Filter by conversation ID", Required = false)] + public string ConversationId { get; set; } + } + + /// + /// Main handler for action trace queries. + /// + public static object HandleCommand(JObject @params) + { + // Delegate to the existing ActionTraceViewResource implementation + return ActionTraceViewResource.HandleCommand(@params); + } + } +} diff --git a/MCPForUnity/Editor/Tools/ManageAsset.cs b/MCPForUnity/Editor/Tools/ManageAsset.cs index a285c9dcb..f1b4e2558 100644 --- a/MCPForUnity/Editor/Tools/ManageAsset.cs +++ b/MCPForUnity/Editor/Tools/ManageAsset.cs @@ -25,7 +25,31 @@ namespace MCPForUnity.Editor.Tools [McpForUnityTool("manage_asset", AutoRegister = false)] public static class ManageAsset { - // --- Main Handler --- + // ======================================================================== + // ActionTrace Integration (Low-Coupling Event Callbacks) + // ======================================================================== + /// + /// Callback raised when an asset is modified. External systems (like ActionTrace) + /// can subscribe to this to track changes without tight coupling. + /// + /// Parameters: (assetPath, assetType, changesDictionary) + /// - changesDictionary: property path -> {old, new} values + /// + public static event Action> OnAssetModified; + + /// + /// Callback raised when an asset is created. + /// + public static event Action OnAssetCreated; + + /// + /// Callback raised when an asset is deleted. + /// + public static event Action OnAssetDeleted; + + // ======================================================================== + // Main Handler + // ======================================================================== // Define the list of valid actions private static readonly List ValidActions = new List @@ -264,6 +288,10 @@ private static object CreateAsset(JObject @params) } AssetDatabase.SaveAssets(); + + // === ActionTrace Integration: Notify subscribers (low-coupling) === + OnAssetCreated?.Invoke(fullPath, assetType); + // AssetDatabase.Refresh(); // CreateAsset often handles refresh return new SuccessResponse( $"Asset '{fullPath}' created successfully.", @@ -466,6 +494,14 @@ prop.Value is JObject componentProperties EditorUtility.SetDirty(asset); // Save all modified assets to disk. AssetDatabase.SaveAssets(); + + // === ActionTrace Integration: Notify subscribers (low-coupling) === + OnAssetModified?.Invoke( + fullPath, + asset.GetType().FullName, + properties.ToObject>() + ); + // Refresh might be needed in some edge cases, but SaveAssets usually covers it. // AssetDatabase.Refresh(); return new SuccessResponse( @@ -500,11 +536,17 @@ private static object DeleteAsset(string path) if (!AssetExists(fullPath)) return new ErrorResponse($"Asset not found at path: {fullPath}"); + // Capture asset type before deletion (for ActionTrace callback) + string assetType = AssetDatabase.GetMainAssetTypeAtPath(fullPath)?.FullName ?? "Unknown"; + try { bool success = AssetDatabase.DeleteAsset(fullPath); if (success) { + // === ActionTrace Integration: Notify subscribers (low-coupling) === + OnAssetDeleted?.Invoke(fullPath, assetType); + // AssetDatabase.Refresh(); // DeleteAsset usually handles refresh return new SuccessResponse($"Asset '{fullPath}' deleted successfully."); } diff --git a/MCPForUnity/Editor/Tools/UndoToSequenceTool.cs b/MCPForUnity/Editor/Tools/UndoToSequenceTool.cs new file mode 100644 index 000000000..b910d7761 --- /dev/null +++ b/MCPForUnity/Editor/Tools/UndoToSequenceTool.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Core; +using UnityEditor; + +namespace MCPForUnity.Editor.Tools +{ + /// + /// MCP Tool for reverting the editor state to a specific ActionTrace sequence. + /// + /// Purpose (from ActionTrace-enhancements.md P2.4): + /// - Allows AI to "undo" to a previous state identified by sequence number + /// - Provides "regret medicine" for AI operations + /// + /// Implementation Notes: + /// - Unity Undo API does NOT support "revert to specific group" directly + /// - This tool calculates how many Undo steps are needed to reach target sequence + /// - Performs multiple Undo.PerformUndo() operations + /// + /// Limitations: + /// - Only works if Undo history is intact (no domain reload) + /// - Cannot redo after this operation (standard Ctrl+Y won't work) + /// - Best used immediately after realizing a mistake + /// + [McpForUnityTool("undo_to_sequence")] + public static class UndoToSequenceTool + { + /// + /// Parameters for undo_to_sequence tool. + /// + public class Parameters + { + /// + /// Target sequence number to revert to + /// + [ToolParameter("Target sequence number to revert to", Required = true)] + public long SequenceId { get; set; } + + /// + /// If true, only calculate steps without executing + /// + [ToolParameter("If true, only calculate steps without executing", Required = false, DefaultValue = "false")] + public bool DryRun { get; set; } = false; + } + + /// + /// Handles the undo_to_sequence command. + /// + /// Parameters: + /// sequence_id (long): Target sequence number to revert to + /// dry_run (bool, optional): If true, only calculate steps without executing + /// + /// Returns: + /// Success response with steps performed and information + /// + public static object HandleCommand(JObject @params) + { + try + { + // Parse required parameter + long targetSequence = 0; + var sequenceToken = @params["sequence_id"] ?? @params["sequenceId"]; + if (sequenceToken == null || !long.TryParse(sequenceToken.ToString(), out targetSequence)) + { + return new ErrorResponse("sequence_id parameter is required and must be a number."); + } + + // Optional dry_run parameter + bool dryRun = false; + var dryRunToken = @params["dry_run"] ?? @params["dryRun"]; + if (dryRunToken != null) + { + bool.TryParse(dryRunToken.ToString(), out dryRun); + } + + // Get current sequence + long currentSequence = EventStore.CurrentSequence; + if (targetSequence >= currentSequence) + { + return new ErrorResponse($"Target sequence ({targetSequence}) is not in the past. Current sequence: {currentSequence}"); + } + + // Query events to find which ones occurred after target sequence + var eventsAfterTarget = EventStore.Query( + limit: int.MaxValue, // Get all events + sinceSequence: targetSequence + ).ToList(); + + if (eventsAfterTarget.Count == 0) + { + return new ErrorResponse($"No events found after sequence {targetSequence}."); + } + + // Count Undo groups after target sequence + var undoGroupsAfterTarget = new HashSet(); + foreach (var evt in eventsAfterTarget) + { + if (evt.Payload != null && evt.Payload.TryGetValue("undo_group", out var groupObj)) + { + if (int.TryParse(groupObj?.ToString(), out int groupId)) + { + undoGroupsAfterTarget.Add(groupId); + } + } + } + + int stepsToUndo = undoGroupsAfterTarget.Count; + + if (stepsToUndo == 0) + { + return new SuccessResponse($"No Undo operations to perform. The target sequence {targetSequence} may have been reached without Undo-recorded operations."); + } + + // Dry run - only return information + if (dryRun) + { + return new SuccessResponse($"Dry run: {stepsToUndo} Undo steps needed to reach sequence {targetSequence}", new + { + target_sequence = targetSequence, + current_sequence = currentSequence, + undo_steps_needed = stepsToUndo, + events_after_target = eventsAfterTarget.Count, + affected_undo_groups = undoGroupsAfterTarget.ToArray() + }); + } + + // Perform the undo operations + McpLog.Info($"[UndoToSequenceTool] Reverting {stepsToUndo} Undo steps to reach sequence {targetSequence}"); + + for (int i = 0; i < stepsToUndo; i++) + { + Undo.PerformUndo(); + } + + // Force GUI refresh to update the scene + EditorApplication.delayCall += () => + { + UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene()); + }; + + return new SuccessResponse($"Successfully reverted {stepsToUndo} Undo steps to reach sequence {targetSequence}", new + { + target_sequence = targetSequence, + undo_steps_performed = stepsToUndo, + events_after_target = eventsAfterTarget.Count, + note = "Warning: Redo (Ctrl+Y) may not work correctly after this operation. Consider this a one-way revert." + }); + } + catch (Exception ex) + { + McpLog.Error($"[UndoToSequenceTool] Error: {ex.Message}"); + return new ErrorResponse($"Failed to undo to sequence: {ex.Message}"); + } + } + } +} diff --git a/MCPForUnity/Editor/Tools/UndoToSequenceTool.cs.meta b/MCPForUnity/Editor/Tools/UndoToSequenceTool.cs.meta new file mode 100644 index 000000000..937869870 --- /dev/null +++ b/MCPForUnity/Editor/Tools/UndoToSequenceTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7fe08e9f7251a0e4fb69cd385c0e8f2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MCPForUnity/Editor/Windows/ActionTraceEditorWindow.cs b/MCPForUnity/Editor/Windows/ActionTraceEditorWindow.cs new file mode 100644 index 000000000..600cf1c23 --- /dev/null +++ b/MCPForUnity/Editor/Windows/ActionTraceEditorWindow.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.ActionTrace.Core; +using MCPForUnity.Editor.ActionTrace.Query; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace MCPForUnity.Editor.Windows +{ + public sealed class ActionTraceEditorWindow : EditorWindow + { + #region Constants + + private const string UxmlName = "ActionTraceEditorWindow"; + private const double RefreshInterval = 1.0; + private const int DefaultQueryLimit = 200; + + // UI Element Names + private static class UINames + { + public const string EventList = "event-list"; + public const string DetailScrollView = "detail-scroll-view"; + public const string StatusLabel = "status-label"; + public const string CountLabel = "count-label"; + public const string SearchField = "search-field"; + public const string ImportanceToggle = "importance-toggle"; + public const string ContextToggle = "context-toggle"; + public const string FilterMenu = "filter-menu"; + public const string SettingsButton = "settings-button"; + public const string RefreshButton = "refresh-button"; + public const string ClearButton = "clear-button"; + } + + // USS Class Names + private static class Classes + { + public const string EventItem = "event-item"; + public const string EventTime = "event-time"; + public const string EventType = "event-type"; + public const string EventSummary = "event-summary"; + public const string ImportanceBadge = "importance-badge"; + public const string HasContext = "has-context"; + public const string DetailContainer = "detail-container"; + public const string DetailRow = "detail-row"; + public const string DetailLabel = "detail-label"; + public const string DetailValue = "detail-value"; + } + + #endregion + + // UI + private ListView _eventListView; + private ScrollView _detailScrollView; + private Label _statusLabel; + private Label _countLabel; + private ToolbarSearchField _searchField; + private ToolbarToggle _importanceToggle; + private ToolbarToggle _contextToggle; + private ToolbarMenu _filterMenu; + private ToolbarButton _settingsButton; + private ToolbarButton _refreshButton; + private ToolbarButton _clearButton; + + // Data + private readonly List _currentEvents = new(); + private ActionTraceQuery _actionTraceQuery; + + private string _searchText = string.Empty; + private float _minImportance; + private bool _showSemantics; + private bool _showContext; + + private double _lastRefreshTime; + + public static void ShowWindow() + { + var window = GetWindow("ActionTrace"); + window.minSize = new Vector2(900, 600); + } + + private void CreateGUI() + { + var uxml = LoadUxmlAsset(); + if (uxml == null) return; + + uxml.CloneTree(rootVisualElement); + if (rootVisualElement.childCount == 0) + { + McpLog.Error("ActionTraceEditorWindow: UXML loaded but rootVisualElement is empty."); + return; + } + + SetupReferences(); + ValidateRequiredElements(); + SetupListView(); + SetupToolbar(); + + _actionTraceQuery = new ActionTraceQuery(); + _minImportance = ActionTraceSettings.Instance?.MinImportanceForRecording ?? 0.4f; + + RefreshEvents(); + UpdateStatus(); + } + + private VisualTreeAsset LoadUxmlAsset() + { + // Try loading by name first (simplest approach) + var guids = AssetDatabase.FindAssets($"{UxmlName} t:VisualTreeAsset"); + if (guids?.Length > 0) + { + var path = AssetDatabase.GUIDToAssetPath(guids[0]); + var asset = AssetDatabase.LoadAssetAtPath(path); + if (asset != null) return asset; + } + + // Fallback: try package-relative path + var basePath = AssetPathUtility.GetMcpPackageRootPath(); + if (!string.IsNullOrEmpty(basePath)) + { + var expectedPath = $"{basePath}/Editor/Windows/{UxmlName}.uxml"; + var sanitized = AssetPathUtility.SanitizeAssetPath(expectedPath); + var asset = AssetDatabase.LoadAssetAtPath(sanitized); + if (asset != null) return asset; + } + + McpLog.Error($"ActionTraceEditorWindow.uxml not found in project."); + return null; + } + + private void ValidateRequiredElements() + { + if (_eventListView == null) + McpLog.Error($"'{UINames.EventList}' ListView not found in UXML."); + if (_detailScrollView == null) + McpLog.Error($"'{UINames.DetailScrollView}' ScrollView not found in UXML."); + if (_statusLabel == null) + McpLog.Error($"'{UINames.StatusLabel}' Label not found in UXML."); + if (_countLabel == null) + McpLog.Error($"'{UINames.CountLabel}' Label not found in UXML."); + } + + private void SetupReferences() + { + _eventListView = rootVisualElement.Q(UINames.EventList); + _detailScrollView = rootVisualElement.Q(UINames.DetailScrollView); + _statusLabel = rootVisualElement.Q