using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace MCPForUnity.Editor.Data { /// /// Registry of Python tool files to sync to the MCP server. /// Add your Python files here - they can be stored anywhere in your project. /// [CreateAssetMenu(fileName = "PythonTools", menuName = "MCP For Unity/Python Tools")] public class PythonToolsAsset : ScriptableObject { [Tooltip("Add Python files (.py) to sync to the MCP server. Files can be located anywhere in your project.")] public List pythonFiles = new List(); [Header("Sync Options")] [Tooltip("Use content hashing to detect changes (recommended). If false, always copies on startup.")] public bool useContentHashing = true; [Header("Sync State (Read-only)")] [Tooltip("Internal tracking - do not modify")] public List fileStates = new List(); /// /// Gets all valid Python files (filters out null/missing references) /// public IEnumerable GetValidFiles() { return pythonFiles.Where(f => f != null); } /// /// Checks if a file needs syncing /// public bool NeedsSync(TextAsset file, string currentHash) { if (!useContentHashing) return true; // Always sync if hashing disabled var state = fileStates.FirstOrDefault(s => s.assetGuid == GetAssetGuid(file)); return state == null || state.contentHash != currentHash; } /// /// Records that a file was synced /// public void RecordSync(TextAsset file, string hash) { string guid = GetAssetGuid(file); var state = fileStates.FirstOrDefault(s => s.assetGuid == guid); if (state == null) { state = new PythonFileState { assetGuid = guid }; fileStates.Add(state); } state.contentHash = hash; state.lastSyncTime = DateTime.UtcNow; state.fileName = file.name; } /// /// Removes state entries for files no longer in the list /// public void CleanupStaleStates() { var validGuids = new HashSet(GetValidFiles().Select(GetAssetGuid)); fileStates.RemoveAll(s => !validGuids.Contains(s.assetGuid)); } private string GetAssetGuid(TextAsset asset) { return UnityEditor.AssetDatabase.AssetPathToGUID(UnityEditor.AssetDatabase.GetAssetPath(asset)); } /// /// Called when the asset is modified in the Inspector /// Triggers sync to handle file additions/removals /// private void OnValidate() { // Cleanup stale states immediately CleanupStaleStates(); // Trigger sync after a delay to handle file removals // Delay ensures the asset is saved before sync runs UnityEditor.EditorApplication.delayCall += () => { if (this != null) // Check if asset still exists { MCPForUnity.Editor.Helpers.PythonToolSyncProcessor.SyncAllTools(); } }; } } [Serializable] public class PythonFileState { public string assetGuid; public string fileName; public string contentHash; public DateTime lastSyncTime; } }