-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: action trace feat: the HookSystem for Unity #570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 28 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
204e95a
fix: resolve UV path override not being detected in System Requirements
whatevertogo 25e5d05
fix: improve uv/uvx detection robustness on macOS and Linux
whatevertogo cc22320
Merge branch 'CoplayDev:main' into main
whatevertogo 8d5fa2f
refactor: unify process execution with ExecPath.TryRun and add Window…
whatevertogo 84cee8c
fix: improve version parsing to handle both spaces and parentheses
whatevertogo 510e631
refactor: improve platform detectors with absolute path resolution
whatevertogo bf41479
fix: improve error handling in PathResolverService by logging exceptions
whatevertogo f39857c
Remove .meta files added after fork and update .gitignore
whatevertogo c4be11c
Merge branch 'CoplayDev:main' into main
whatevertogo 1832715
Update .gitignore
whatevertogo 554ddd0
save .meta
whatevertogo fb5909d
refactor: unify uv/uvx naming and path detection across platforms
whatevertogo 254125a
fix: improve validation light(uvxPathStatus) logic for UVX path overr…
whatevertogo f9ae5d5
refactor: streamline UV version validation and unify path detection m…
whatevertogo 84cb9c6
fix: add type handling for Claude Code client in config JSON builder
whatevertogo ee33077
fix: correct command from 'uvx' to 'uv' for Python version listing in…
whatevertogo 2c3ebcd
Merge branch 'CoplayDev:main' into main
whatevertogo 66fe194
Merge branch 'CoplayDev:main' into main
whatevertogo 79bce47
Merge branch 'CoplayDev:main' into main
whatevertogo b0eb274
feat: Add ActionTrace system for editor event tracking and replay
whatevertogo ec59a59
refactor: split EventStore into partial classes for better maintainab…
whatevertogo 4e54591
fix: update stylesheet references and comment unsupported styles in A…
whatevertogo e599807
refactor: update comments and documentation in action trace files for…
whatevertogo f475bee
feat: enhance ActionTrace with layered settings, preset system, and q…
whatevertogo af77674
feat: optimize performance in ActionTrace by replacing LINQ with manu…
whatevertogo f547208
feat: enhance ActionTrace settings with Range attributes and dynamic …
whatevertogo 44b7045
feat: add GlobalIdHelper for cross-session stable object identificati…
whatevertogo a86506c
fix: replace delayCall with EditorApplication.update to avoid memory …
whatevertogo f340636
Merge branch 'main' into feature/ActionTrace
whatevertogo 061a821
Merge branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo 25e1253
feat: add built-in HookRegistry system with Event Args pattern
whatevertogo 13c0bc5
fix: resolve P1 issues in ActionTrace system
whatevertogo 05e7674
Merge branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo 1e727eb
Enhance ActionTrace Editor Window UI
whatevertogo 2e161b7
Merge remote-tracking branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo 9b24a2e
fix: enhance event handling and error logging in ActionTrace system
whatevertogo 4609817
refactor: improve ActionTrace system architecture and UI
whatevertogo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
533 changes: 533 additions & 0 deletions
533
MCPForUnity/Editor/ActionTrace/Capture/ActionTraceEventEmitter.cs
Large diffs are not rendered by default.
Oops, something went wrong.
228 changes: 228 additions & 0 deletions
228
MCPForUnity/Editor/ActionTrace/Capture/AssetChangePostprocessor.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,228 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using MCPForUnity.Editor.ActionTrace.Core; | ||
| using MCPForUnity.Editor.Helpers; | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
|
|
||
| namespace MCPForUnity.Editor.ActionTrace.Capture | ||
| { | ||
| /// <summary> | ||
| /// Asset postprocessor for tracking asset changes in ActionTrace. | ||
| /// Uses Unity's AssetPostprocessor callback pattern, not event subscription. | ||
| /// | ||
| /// Events generated: | ||
| /// - AssetImported: When an asset is imported from outside | ||
| /// - AssetCreated: When a new asset is created in Unity | ||
| /// - AssetDeleted: When an asset is deleted | ||
| /// - AssetMoved: When an asset is moved/renamed | ||
| /// - AssetModified: When an existing asset is modified | ||
| /// | ||
| /// All asset events use "Asset:{path}" format for TargetId to ensure | ||
| /// cross-session stability. | ||
| /// </summary> | ||
| internal sealed class AssetChangePostprocessor : AssetPostprocessor | ||
| { | ||
| private static void OnPostprocessAllAssets( | ||
| string[] importedAssets, | ||
| string[] deletedAssets, | ||
| string[] movedAssets, | ||
| string[] movedFromAssetPaths) | ||
| { | ||
| // ========== Imported Assets (includes newly created assets) ========== | ||
| foreach (var assetPath in importedAssets) | ||
| { | ||
| if (string.IsNullOrEmpty(assetPath)) continue; | ||
|
|
||
| // L1 Blacklist: Skip junk assets before creating events | ||
| if (!EventFilter.ShouldTrackAsset(assetPath)) | ||
| continue; | ||
|
|
||
| string targetId = $"Asset:{assetPath}"; | ||
| string assetType = GetAssetType(assetPath); | ||
|
|
||
| var payload = new Dictionary<string, object> | ||
| { | ||
| ["path"] = assetPath, | ||
| ["extension"] = System.IO.Path.GetExtension(assetPath), | ||
| ["asset_type"] = assetType | ||
| }; | ||
|
|
||
| // Distinguish between imported and newly created assets | ||
| if (IsNewlyCreatedAsset(assetPath)) | ||
| { | ||
| RecordEvent(EventTypes.AssetCreated, targetId, payload); | ||
| } | ||
| else | ||
| { | ||
| RecordEvent(EventTypes.AssetImported, targetId, payload); | ||
| } | ||
| } | ||
|
|
||
| // ========== Deleted Assets ========== | ||
| foreach (var assetPath in deletedAssets) | ||
| { | ||
| if (string.IsNullOrEmpty(assetPath)) continue; | ||
|
|
||
| // L1 Blacklist: Skip junk assets | ||
| if (!EventFilter.ShouldTrackAsset(assetPath)) | ||
| continue; | ||
|
|
||
| string targetId = $"Asset:{assetPath}"; | ||
|
|
||
| var payload = new Dictionary<string, object> | ||
| { | ||
| ["path"] = assetPath | ||
| }; | ||
|
|
||
| RecordEvent(EventTypes.AssetDeleted, targetId, 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; | ||
|
|
||
| string targetId = $"Asset:{movedAssets[i]}"; | ||
|
|
||
| var payload = new Dictionary<string, object> | ||
| { | ||
| ["to_path"] = movedAssets[i], | ||
| ["from_path"] = fromPath | ||
| }; | ||
|
|
||
| RecordEvent(EventTypes.AssetMoved, targetId, payload); | ||
| } | ||
|
|
||
| // ========== Modified Assets ========== | ||
| // Track asset modifications separately (e.g., texture imports, prefab changes) | ||
| foreach (var assetPath in importedAssets) | ||
| { | ||
| if (string.IsNullOrEmpty(assetPath)) continue; | ||
|
|
||
| // Only track modifications for existing assets | ||
| if (!IsNewlyCreatedAsset(assetPath) && EventFilter.ShouldTrackAsset(assetPath)) | ||
| { | ||
| string targetId = $"Asset:{assetPath}"; | ||
| string assetType = GetAssetType(assetPath); | ||
|
|
||
| // Only record modifications for certain asset types | ||
| if (ShouldTrackModification(assetPath)) | ||
| { | ||
| var payload = new Dictionary<string, object> | ||
| { | ||
| ["path"] = assetPath, | ||
| ["extension"] = System.IO.Path.GetExtension(assetPath), | ||
| ["asset_type"] = assetType | ||
| }; | ||
|
|
||
| RecordEvent(EventTypes.AssetModified, targetId, payload); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Determines if an asset was newly created vs imported. | ||
| /// Newly created assets have a .meta file with recent creation time. | ||
| /// </summary> | ||
| private static bool IsNewlyCreatedAsset(string assetPath) | ||
| { | ||
| try | ||
| { | ||
| string metaPath = assetPath + ".meta"; | ||
| var meta = AssetDatabase.LoadMainAssetAtPath(metaPath); | ||
| // This is a simplified check - in production you'd check file creation time | ||
| return false; // Default to treating as imported for now | ||
| } | ||
| catch | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Determines if modifications to this asset type should be tracked. | ||
| /// Tracks modifications for commonly edited asset types. | ||
| /// </summary> | ||
| private static bool ShouldTrackModification(string assetPath) | ||
| { | ||
| string ext = System.IO.Path.GetExtension(assetPath).ToLower(); | ||
| // Track modifications for these asset types | ||
| return ext == ".png" || ext == ".jpg" || ext == ".jpeg" || | ||
| ext == ".psd" || ext == ".tif" || | ||
| ext == ".fbx" || ext == ".obj" || | ||
| ext == ".prefab" || ext == ".unity" || | ||
| ext == ".anim" || ext == ".controller"; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the asset type based on file extension. | ||
| /// </summary> | ||
| private static string GetAssetType(string assetPath) | ||
| { | ||
| string ext = System.IO.Path.GetExtension(assetPath).ToLower(); | ||
| return ext switch | ||
| { | ||
| ".cs" => "script", | ||
| ".unity" => "scene", | ||
| ".prefab" => "prefab", | ||
| ".mat" => "material", | ||
| ".png" or ".jpg" or ".jpeg" or ".gif" or ".tga" or ".psd" or ".tif" or ".bmp" => "texture", | ||
| ".fbx" or ".obj" or ".blend" or ".3ds" => "model", | ||
| ".anim" => "animation", | ||
| ".controller" => "animator_controller", | ||
| ".shader" => "shader", | ||
| ".asset" => "scriptable_object", | ||
| ".physicmaterial" => "physics_material", | ||
| ".physicmaterial2d" => "physics_material_2d", | ||
| ".guiskin" => "gui_skin", | ||
| ".fontsettings" => "font", | ||
| ".mixer" => "audio_mixer", | ||
| ".rendertexture" => "render_texture", | ||
| ".spriteatlas" => "sprite_atlas", | ||
| ".tilepalette" => "tile_palette", | ||
| _ => "unknown" | ||
| }; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Records an event to the EventStore with proper context injection. | ||
| /// </summary> | ||
| private static void RecordEvent(string type, string targetId, Dictionary<string, object> 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) | ||
| { | ||
| McpLog.Warn($"[AssetChangePostprocessor] Failed to record event: {ex.Message}"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.