using System; using System.IO; using Codely.Newtonsoft.Json.Linq; using UnityEditor; using UnityEngine; using UnityEngine.UIElements; using UnityTcp.Editor.Helpers; namespace UnityTcp.Editor.Tools { /// /// [EXPERIMENTAL] Handles UI Toolkit operations (UXML, USS, PanelSettings). /// public static class ManageUIToolkit { public static object HandleCommand(JObject @params) { string action = @params["action"]?.ToString().ToLower(); if (string.IsNullOrEmpty(action)) { return Response.Error("Action parameter is required."); } try { switch (action) { case "ensure_panel_settings_asset": return EnsurePanelSettingsAsset(@params); case "link_uss_to_uxml": return LinkUssToUxml(@params); case "create_uxml": return CreateUxml(@params); case "create_uss": return CreateUss(@params); default: return Response.Error( $"Unknown action: '{action}'. Valid actions: ensure_panel_settings_asset, link_uss_to_uxml, create_uxml, create_uss." ); } } catch (Exception e) { Debug.LogError($"[ManageUIToolkit] Action '{action}' failed: {e}"); return Response.Error($"[EXPERIMENTAL] UI Toolkit operation failed: {e.Message}"); } } private static object EnsurePanelSettingsAsset(JObject @params) { try { var writeCheck = WriteGuard.CheckWriteAllowed("ensure_panel_settings_asset"); if (writeCheck != null) return writeCheck; string path = @params["path"]?.ToString(); if (string.IsNullOrEmpty(path)) return Response.Error("'path' parameter required."); if (!path.EndsWith(".asset")) path += ".asset"; // Check if already exists var existingAsset = AssetDatabase.LoadAssetAtPath(path); if (existingAsset != null) { return new { success = true, message = "[EXPERIMENTAL] PanelSettings asset already exists.", data = new { path = path, alreadyExists = true }, state_delta = StateComposer.CreateAssetDelta(new[] { new { path = path, imported = false, hasMeta = true } }) }; } // Create directory if needed string dir = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } // Create PanelSettings asset var panelSettings = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(panelSettings, path); AssetDatabase.SaveAssets(); StateComposer.IncrementRevision(); return new { success = true, message = "[EXPERIMENTAL] PanelSettings asset created.", data = new { path = path, alreadyExists = false }, state_delta = StateComposer.CreateAssetDelta(new[] { new { path = path, imported = true, hasMeta = true } }) }; } catch (Exception e) { return Response.Error($"[EXPERIMENTAL] Failed to ensure PanelSettings asset: {e.Message}"); } } private static object LinkUssToUxml(JObject @params) { try { var writeCheck = WriteGuard.CheckWriteAllowed("link_uss_to_uxml"); if (writeCheck != null) return writeCheck; // Support both parameter naming conventions: uxml/uss and uxml_path/uss_path, // as well as GUID-based references via uxml_guid/uss_guid. string uxmlShorthand = @params["uxml"]?.ToString(); string uxmlPathParam = @params["uxml_path"]?.ToString(); string uxmlGuidParam = @params["uxml_guid"]?.ToString(); string ussShorthand = @params["uss"]?.ToString(); string ussPathParam = @params["uss_path"]?.ToString(); string ussGuidParam = @params["uss_guid"]?.ToString(); bool hasUxmlIdentifier = !string.IsNullOrEmpty(uxmlShorthand) || !string.IsNullOrEmpty(uxmlPathParam) || !string.IsNullOrEmpty(uxmlGuidParam); bool hasUssIdentifier = !string.IsNullOrEmpty(ussShorthand) || !string.IsNullOrEmpty(ussPathParam) || !string.IsNullOrEmpty(ussGuidParam); if (!hasUxmlIdentifier) return Response.Error("Either 'uxml', 'uxml_path', or 'uxml_guid' parameter is required."); if (!hasUssIdentifier) return Response.Error("Either 'uss', 'uss_path', or 'uss_guid' parameter is required."); string uxmlGuidUsed; string ussGuidUsed; string uxmlPath = ResolveAssetPath(uxmlShorthand, uxmlPathParam, uxmlGuidParam, out uxmlGuidUsed); string ussPath = ResolveAssetPath(ussShorthand, ussPathParam, ussGuidParam, out ussGuidUsed); if (string.IsNullOrEmpty(uxmlPath)) { if (!string.IsNullOrEmpty(uxmlGuidUsed)) { return Response.Error($"UXML asset not found for GUID: {uxmlGuidUsed}"); } return Response.Error("UXML path could not be resolved."); } if (string.IsNullOrEmpty(ussPath)) { if (!string.IsNullOrEmpty(ussGuidUsed)) { return Response.Error($"USS asset not found for GUID: {ussGuidUsed}"); } return Response.Error("USS path could not be resolved."); } var uxmlAsset = AssetDatabase.LoadAssetAtPath(uxmlPath); if (uxmlAsset == null) return Response.Error($"UXML not found at: {uxmlPath}"); var ussAsset = AssetDatabase.LoadAssetAtPath(ussPath); if (ussAsset == null) return Response.Error($"USS not found at: {ussPath}"); // Read UXML file content string uxmlContent = File.ReadAllText(uxmlPath); // Check if USS is already linked string ussFileName = Path.GetFileName(ussPath); if (uxmlContent.Contains($"src=\"{ussFileName}\"")) { return new { success = true, message = "[EXPERIMENTAL] USS already linked to UXML.", data = new { uxml = uxmlPath, uss = ussPath, alreadyLinked = true }, state_delta = StateComposer.CreateAssetDelta(new[] { new { path = uxmlPath, imported = false, hasMeta = true } }) }; } // Add USS reference to UXML // Insert after tag int insertPos = uxmlContent.IndexOf("= 0) { insertPos = uxmlContent.IndexOf('>', insertPos) + 1; string styleTag = $"\n