-
Notifications
You must be signed in to change notification settings - Fork 633
Feature/action trace #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
Open
whatevertogo
wants to merge
29
commits into
CoplayDev:main
Choose a base branch
from
whatevertogo:feature/ActionTrace
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Feature/action trace #570
Changes from all commits
Commits
Show all changes
29 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 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate event emission for imported assets.
This section iterates
importedAssetsagain and emitsAssetModifiedevents for non-newly-created assets. However, lines 56-58 already emitAssetImportedfor these same assets, resulting in duplicate events for the same import operation.Since
IsNewlyCreatedAssetalways returnsfalse, every imported asset that passesShouldTrackModificationwill generate both anAssetImportedevent (line 58) and anAssetModifiedevent (line 125).Consider removing this section or making it mutually exclusive with the imported assets handling above.
🐛 Suggested fix
If you need to distinguish modifications from imports, implement
IsNewlyCreatedAssetproperly first, then use it to emit eitherAssetCreated/AssetImportedORAssetModified, but not both.📝 Committable suggestion
🤖 Prompt for AI Agents