uloop-cli 0.50.2 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,13 +4,14 @@
4
4
  *
5
5
  * This file is automatically generated from:
6
6
  * - Editor/Api/McpTools/<ToolFolder>/SKILL.md
7
+ * - Editor/Api/McpTools/<ToolFolder>/examples/*.md (additional files)
7
8
  * - skill-definitions/cli-only/<SkillFolder>/SKILL.md
8
9
  *
9
10
  * To add a new skill, create a SKILL.md file in the appropriate location.
10
11
  * To exclude a skill from bundling, add `internal: true` to its frontmatter.
11
12
  */
12
13
 
13
- import captureUnityWindowSkill from '../../../Editor/Api/McpTools/CaptureUnityWindow/SKILL.md';
14
+ import captureWindowSkill from '../../../Editor/Api/McpTools/CaptureWindow/SKILL.md';
14
15
  import clearConsoleSkill from '../../../Editor/Api/McpTools/ClearConsole/SKILL.md';
15
16
  import compileSkill from '../../../Editor/Api/McpTools/Compile/SKILL.md';
16
17
  import controlPlayModeSkill from '../../../Editor/Api/McpTools/ControlPlayMode/SKILL.md';
@@ -29,13 +30,14 @@ export interface BundledSkill {
29
30
  name: string;
30
31
  dirName: string;
31
32
  content: string;
33
+ additionalFiles?: Record<string, string>;
32
34
  }
33
35
 
34
36
  export const BUNDLED_SKILLS: BundledSkill[] = [
35
37
  {
36
- name: 'uloop-capture-unity-window',
37
- dirName: 'uloop-capture-unity-window',
38
- content: captureUnityWindowSkill,
38
+ name: 'uloop-capture-window',
39
+ dirName: 'uloop-capture-window',
40
+ content: captureWindowSkill,
39
41
  },
40
42
  {
41
43
  name: 'uloop-clear-console',
@@ -56,6 +58,2220 @@ export const BUNDLED_SKILLS: BundledSkill[] = [
56
58
  name: 'uloop-execute-dynamic-code',
57
59
  dirName: 'uloop-execute-dynamic-code',
58
60
  content: executeDynamicCodeSkill,
61
+ additionalFiles: {
62
+ 'examples/asset-operations.md': `# Asset Operations
63
+
64
+ Code examples for AssetDatabase operations using \`execute-dynamic-code\`.
65
+
66
+ ## Find Assets by Type
67
+
68
+ \`\`\`csharp
69
+ using UnityEditor;
70
+ using System.Collections.Generic;
71
+
72
+ string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab");
73
+ List<string> paths = new List<string>();
74
+
75
+ foreach (string guid in prefabGuids)
76
+ {
77
+ paths.Add(AssetDatabase.GUIDToAssetPath(guid));
78
+ }
79
+ return $"Found {paths.Count} prefabs";
80
+ \`\`\`
81
+
82
+ ## Find Assets by Name
83
+
84
+ \`\`\`csharp
85
+ using UnityEditor;
86
+ using System.Collections.Generic;
87
+
88
+ string searchName = "Player";
89
+ string[] guids = AssetDatabase.FindAssets(searchName);
90
+ List<string> paths = new List<string>();
91
+
92
+ foreach (string guid in guids)
93
+ {
94
+ paths.Add(AssetDatabase.GUIDToAssetPath(guid));
95
+ }
96
+ return $"Found {paths.Count} assets matching '{searchName}'";
97
+ \`\`\`
98
+
99
+ ## Find Assets in Folder
100
+
101
+ \`\`\`csharp
102
+ using UnityEditor;
103
+ using System.Collections.Generic;
104
+
105
+ string folder = "Assets/Prefabs";
106
+ string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { folder });
107
+ List<string> paths = new List<string>();
108
+
109
+ foreach (string guid in guids)
110
+ {
111
+ paths.Add(AssetDatabase.GUIDToAssetPath(guid));
112
+ }
113
+ return $"Found {paths.Count} prefabs in {folder}";
114
+ \`\`\`
115
+
116
+ ## Duplicate Asset
117
+
118
+ \`\`\`csharp
119
+ using UnityEditor;
120
+
121
+ string sourcePath = "Assets/Materials/MyMaterial.mat";
122
+ string destPath = "Assets/Materials/MyMaterial_Backup.mat";
123
+
124
+ bool success = AssetDatabase.CopyAsset(sourcePath, destPath);
125
+ return success ? $"Copied to {destPath}" : "Copy failed";
126
+ \`\`\`
127
+
128
+ ## Move Asset
129
+
130
+ \`\`\`csharp
131
+ using UnityEditor;
132
+
133
+ string sourcePath = "Assets/OldFolder/MyAsset.asset";
134
+ string destPath = "Assets/NewFolder/MyAsset.asset";
135
+
136
+ string error = AssetDatabase.MoveAsset(sourcePath, destPath);
137
+ return string.IsNullOrEmpty(error) ? $"Moved to {destPath}" : $"Error: {error}";
138
+ \`\`\`
139
+
140
+ ## Rename Asset
141
+
142
+ \`\`\`csharp
143
+ using UnityEditor;
144
+
145
+ string assetPath = "Assets/Materials/OldName.mat";
146
+ string newName = "NewName";
147
+
148
+ string error = AssetDatabase.RenameAsset(assetPath, newName);
149
+ return string.IsNullOrEmpty(error) ? $"Renamed to {newName}" : $"Error: {error}";
150
+ \`\`\`
151
+
152
+ ## Rename Asset (Undo-supported)
153
+
154
+ \`\`\`csharp
155
+ using UnityEditor;
156
+
157
+ // ObjectNames.SetNameSmart() supports Undo (AssetDatabase.RenameAsset() does NOT)
158
+ Object selected = Selection.activeObject;
159
+ if (selected == null)
160
+ {
161
+ return "No asset selected";
162
+ }
163
+
164
+ string oldName = selected.name;
165
+ ObjectNames.SetNameSmart(selected, "NewName");
166
+ AssetDatabase.SaveAssets();
167
+ return $"Renamed {oldName} to {selected.name}";
168
+ \`\`\`
169
+
170
+ ## Get Asset Path from Object
171
+
172
+ \`\`\`csharp
173
+ using UnityEditor;
174
+
175
+ GameObject selected = Selection.activeGameObject;
176
+ if (selected == null)
177
+ {
178
+ return "No object selected";
179
+ }
180
+
181
+ string path = AssetDatabase.GetAssetPath(selected);
182
+ if (string.IsNullOrEmpty(path))
183
+ {
184
+ return "Selected object is not an asset (scene object)";
185
+ }
186
+ return $"Asset path: {path}";
187
+ \`\`\`
188
+
189
+ ## Load Asset at Path
190
+
191
+ \`\`\`csharp
192
+ using UnityEditor;
193
+
194
+ string path = "Assets/Prefabs/Player.prefab";
195
+ GameObject asset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
196
+
197
+ if (asset == null)
198
+ {
199
+ return $"Asset not found at {path}";
200
+ }
201
+ return $"Loaded: {asset.name}";
202
+ \`\`\`
203
+
204
+ ## Get All Assets of Type
205
+
206
+ \`\`\`csharp
207
+ using UnityEditor;
208
+
209
+ string[] scriptGuids = AssetDatabase.FindAssets("t:MonoScript");
210
+ int count = 0;
211
+
212
+ foreach (string guid in scriptGuids)
213
+ {
214
+ string path = AssetDatabase.GUIDToAssetPath(guid);
215
+ if (path.StartsWith("Assets/"))
216
+ {
217
+ count++;
218
+ }
219
+ }
220
+ return $"Found {count} scripts in Assets folder";
221
+ \`\`\`
222
+
223
+ ## Check if Asset Exists
224
+
225
+ \`\`\`csharp
226
+ using UnityEditor;
227
+
228
+ string path = "Assets/Prefabs/Player.prefab";
229
+ string guid = AssetDatabase.AssetPathToGUID(path);
230
+
231
+ bool exists = !string.IsNullOrEmpty(guid);
232
+ return exists ? $"Asset exists: {path}" : $"Asset not found: {path}";
233
+ \`\`\`
234
+
235
+ ## Get Asset Dependencies
236
+
237
+ \`\`\`csharp
238
+ using UnityEditor;
239
+
240
+ string assetPath = "Assets/Prefabs/Player.prefab";
241
+ string[] dependencies = AssetDatabase.GetDependencies(assetPath, true);
242
+
243
+ return $"Asset has {dependencies.Length} dependencies";
244
+ \`\`\`
245
+
246
+ ## Refresh AssetDatabase
247
+
248
+ \`\`\`csharp
249
+ using UnityEditor;
250
+
251
+ AssetDatabase.Refresh();
252
+ return "AssetDatabase refreshed";
253
+ \`\`\`
254
+ `,
255
+ 'examples/batch-operations.md': `# Batch Operations
256
+
257
+ Code examples for batch processing using \`execute-dynamic-code\`.
258
+
259
+ ## Batch Modify Selected Objects
260
+
261
+ \`\`\`csharp
262
+ using UnityEditor;
263
+
264
+ GameObject[] selected = Selection.gameObjects;
265
+ if (selected.Length == 0)
266
+ {
267
+ return "No GameObjects selected";
268
+ }
269
+
270
+ int undoGroup = Undo.GetCurrentGroup();
271
+ Undo.SetCurrentGroupName("Batch Modify");
272
+
273
+ foreach (GameObject obj in selected)
274
+ {
275
+ Undo.RecordObject(obj.transform, "");
276
+ obj.transform.localScale = Vector3.one * 2;
277
+ }
278
+
279
+ Undo.CollapseUndoOperations(undoGroup);
280
+ return $"Scaled {selected.Length} objects (Single undo step)";
281
+ \`\`\`
282
+
283
+ ## Edit Multiple Objects with SerializedObject
284
+
285
+ \`\`\`csharp
286
+ using UnityEditor;
287
+
288
+ GameObject[] selected = Selection.gameObjects;
289
+ if (selected.Length == 0)
290
+ {
291
+ return "No GameObjects selected";
292
+ }
293
+
294
+ List<Transform> transforms = new List<Transform>();
295
+ foreach (GameObject obj in selected)
296
+ {
297
+ transforms.Add(obj.transform);
298
+ }
299
+
300
+ SerializedObject serializedObj = new SerializedObject(transforms.ToArray());
301
+ SerializedProperty positionProp = serializedObj.FindProperty("m_LocalPosition");
302
+ positionProp.vector3Value = Vector3.zero;
303
+ serializedObj.ApplyModifiedProperties();
304
+
305
+ return $"Reset position of {selected.Length} objects";
306
+ \`\`\`
307
+
308
+ ## Batch Add Component
309
+
310
+ \`\`\`csharp
311
+ using UnityEditor;
312
+
313
+ GameObject[] selected = Selection.gameObjects;
314
+ if (selected.Length == 0)
315
+ {
316
+ return "No GameObjects selected";
317
+ }
318
+
319
+ int undoGroup = Undo.GetCurrentGroup();
320
+ Undo.SetCurrentGroupName("Batch Add Rigidbody");
321
+
322
+ int addedCount = 0;
323
+ foreach (GameObject obj in selected)
324
+ {
325
+ if (obj.GetComponent<Rigidbody>() == null)
326
+ {
327
+ Undo.AddComponent<Rigidbody>(obj);
328
+ addedCount++;
329
+ }
330
+ }
331
+
332
+ Undo.CollapseUndoOperations(undoGroup);
333
+ return $"Added Rigidbody to {addedCount} objects";
334
+ \`\`\`
335
+
336
+ ## Batch Process Assets with StartAssetEditing
337
+
338
+ \`\`\`csharp
339
+ using UnityEditor;
340
+
341
+ string[] guids = AssetDatabase.FindAssets("t:Material", new[] { "Assets/Materials" });
342
+ if (guids.Length == 0)
343
+ {
344
+ return "No materials found";
345
+ }
346
+
347
+ AssetDatabase.StartAssetEditing();
348
+
349
+ int modified = 0;
350
+ foreach (string guid in guids)
351
+ {
352
+ string path = AssetDatabase.GUIDToAssetPath(guid);
353
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
354
+ if (mat != null)
355
+ {
356
+ mat.color = Color.white;
357
+ EditorUtility.SetDirty(mat);
358
+ modified++;
359
+ }
360
+ }
361
+
362
+ AssetDatabase.StopAssetEditing();
363
+ AssetDatabase.SaveAssets();
364
+
365
+ return $"Reset color of {modified} materials";
366
+ \`\`\`
367
+
368
+ ## Batch Rename GameObjects
369
+
370
+ \`\`\`csharp
371
+ using UnityEditor;
372
+
373
+ GameObject[] selected = Selection.gameObjects;
374
+ if (selected.Length == 0)
375
+ {
376
+ return "No GameObjects selected";
377
+ }
378
+
379
+ int undoGroup = Undo.GetCurrentGroup();
380
+ Undo.SetCurrentGroupName("Batch Rename");
381
+
382
+ for (int i = 0; i < selected.Length; i++)
383
+ {
384
+ Undo.RecordObject(selected[i], "");
385
+ selected[i].name = $"Item_{i:D3}";
386
+ }
387
+
388
+ Undo.CollapseUndoOperations(undoGroup);
389
+ return $"Renamed {selected.Length} objects";
390
+ \`\`\`
391
+
392
+ ## Batch Set Layer
393
+
394
+ \`\`\`csharp
395
+ using UnityEditor;
396
+
397
+ GameObject[] selected = Selection.gameObjects;
398
+ if (selected.Length == 0)
399
+ {
400
+ return "No GameObjects selected";
401
+ }
402
+
403
+ int layer = LayerMask.NameToLayer("Default");
404
+
405
+ int undoGroup = Undo.GetCurrentGroup();
406
+ Undo.SetCurrentGroupName("Batch Set Layer");
407
+
408
+ foreach (GameObject obj in selected)
409
+ {
410
+ Undo.RecordObject(obj, "");
411
+ obj.layer = layer;
412
+ }
413
+
414
+ Undo.CollapseUndoOperations(undoGroup);
415
+ return $"Set layer of {selected.Length} objects to Default";
416
+ \`\`\`
417
+
418
+ ## Batch Set Tag
419
+
420
+ \`\`\`csharp
421
+ using UnityEditor;
422
+
423
+ GameObject[] selected = Selection.gameObjects;
424
+ if (selected.Length == 0)
425
+ {
426
+ return "No GameObjects selected";
427
+ }
428
+
429
+ int undoGroup = Undo.GetCurrentGroup();
430
+ Undo.SetCurrentGroupName("Batch Set Tag");
431
+
432
+ foreach (GameObject obj in selected)
433
+ {
434
+ Undo.RecordObject(obj, "");
435
+ obj.tag = "Enemy";
436
+ }
437
+
438
+ Undo.CollapseUndoOperations(undoGroup);
439
+ return $"Tagged {selected.Length} objects as Enemy";
440
+ \`\`\`
441
+
442
+ ## Batch Modify ScriptableObjects
443
+
444
+ \`\`\`csharp
445
+ using UnityEditor;
446
+
447
+ string[] guids = AssetDatabase.FindAssets("t:ScriptableObject", new[] { "Assets/Data" });
448
+ if (guids.Length == 0)
449
+ {
450
+ return "No ScriptableObjects found";
451
+ }
452
+
453
+ int modified = 0;
454
+ foreach (string guid in guids)
455
+ {
456
+ string path = AssetDatabase.GUIDToAssetPath(guid);
457
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
458
+ if (so == null) continue;
459
+
460
+ SerializedObject serializedObj = new SerializedObject(so);
461
+ SerializedProperty prop = serializedObj.FindProperty("isEnabled");
462
+ if (prop != null)
463
+ {
464
+ prop.boolValue = true;
465
+ serializedObj.ApplyModifiedProperties();
466
+ EditorUtility.SetDirty(so);
467
+ modified++;
468
+ }
469
+ }
470
+
471
+ AssetDatabase.SaveAssets();
472
+ return $"Enabled {modified} ScriptableObjects";
473
+ \`\`\`
474
+
475
+ ## Batch Remove Component
476
+
477
+ \`\`\`csharp
478
+ using UnityEditor;
479
+
480
+ GameObject[] selected = Selection.gameObjects;
481
+ if (selected.Length == 0)
482
+ {
483
+ return "No GameObjects selected";
484
+ }
485
+
486
+ int undoGroup = Undo.GetCurrentGroup();
487
+ Undo.SetCurrentGroupName("Batch Remove Rigidbody");
488
+
489
+ int removedCount = 0;
490
+ foreach (GameObject obj in selected)
491
+ {
492
+ Rigidbody rb = obj.GetComponent<Rigidbody>();
493
+ if (rb != null)
494
+ {
495
+ Undo.DestroyObjectImmediate(rb);
496
+ removedCount++;
497
+ }
498
+ }
499
+
500
+ Undo.CollapseUndoOperations(undoGroup);
501
+ return $"Removed Rigidbody from {removedCount} objects";
502
+ \`\`\`
503
+
504
+ ## Batch Set Static Flags
505
+
506
+ \`\`\`csharp
507
+ using UnityEditor;
508
+
509
+ GameObject[] selected = Selection.gameObjects;
510
+ if (selected.Length == 0)
511
+ {
512
+ return "No GameObjects selected";
513
+ }
514
+
515
+ int undoGroup = Undo.GetCurrentGroup();
516
+ Undo.SetCurrentGroupName("Batch Set Static");
517
+
518
+ foreach (GameObject obj in selected)
519
+ {
520
+ Undo.RecordObject(obj, "");
521
+ GameObjectUtility.SetStaticEditorFlags(obj, StaticEditorFlags.BatchingStatic | StaticEditorFlags.OccludeeStatic);
522
+ }
523
+
524
+ Undo.CollapseUndoOperations(undoGroup);
525
+ return $"Set static flags on {selected.Length} objects";
526
+ \`\`\`
527
+
528
+ ## Batch Process with Progress Bar
529
+
530
+ \`\`\`csharp
531
+ using UnityEditor;
532
+
533
+ string[] guids = AssetDatabase.FindAssets("t:Texture2D");
534
+ if (guids.Length == 0)
535
+ {
536
+ return "No textures found";
537
+ }
538
+
539
+ int processed = 0;
540
+ foreach (string guid in guids)
541
+ {
542
+ string path = AssetDatabase.GUIDToAssetPath(guid);
543
+ TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
544
+ if (importer != null && importer.maxTextureSize > 1024)
545
+ {
546
+ importer.maxTextureSize = 1024;
547
+ importer.SaveAndReimport();
548
+ processed++;
549
+ }
550
+
551
+ if (processed % 10 == 0)
552
+ {
553
+ EditorUtility.DisplayProgressBar("Processing Textures", path, (float)processed / guids.Length);
554
+ }
555
+ }
556
+
557
+ EditorUtility.ClearProgressBar();
558
+ return $"Resized {processed} textures to max 1024";
559
+ \`\`\`
560
+
561
+ ## Batch Align Objects
562
+
563
+ \`\`\`csharp
564
+ using UnityEditor;
565
+
566
+ GameObject[] selected = Selection.gameObjects;
567
+ if (selected.Length < 2)
568
+ {
569
+ return "Select at least 2 objects";
570
+ }
571
+
572
+ int undoGroup = Undo.GetCurrentGroup();
573
+ Undo.SetCurrentGroupName("Align Objects");
574
+
575
+ float startX = selected[0].transform.position.x;
576
+ float spacing = 2f;
577
+
578
+ for (int i = 0; i < selected.Length; i++)
579
+ {
580
+ Undo.RecordObject(selected[i].transform, "");
581
+ Vector3 pos = selected[i].transform.position;
582
+ pos.x = startX + (i * spacing);
583
+ selected[i].transform.position = pos;
584
+ }
585
+
586
+ Undo.CollapseUndoOperations(undoGroup);
587
+ return $"Aligned {selected.Length} objects with {spacing}m spacing";
588
+ \`\`\`
589
+
590
+ ## Batch Rename Assets (Undo-supported)
591
+
592
+ \`\`\`csharp
593
+ using UnityEditor;
594
+
595
+ // ObjectNames.SetNameSmart() supports Undo (AssetDatabase.RenameAsset() does NOT)
596
+ Object[] selected = Selection.objects;
597
+ if (selected.Length == 0)
598
+ {
599
+ return "No assets selected";
600
+ }
601
+
602
+ for (int i = 0; i < selected.Length; i++)
603
+ {
604
+ string newName = $"{i:D3}_{selected[i].name}";
605
+ ObjectNames.SetNameSmart(selected[i], newName);
606
+ }
607
+
608
+ AssetDatabase.SaveAssets();
609
+ return $"Renamed {selected.Length} assets";
610
+ \`\`\`
611
+
612
+ ## Batch Replace Material
613
+
614
+ \`\`\`csharp
615
+ using UnityEditor;
616
+
617
+ GameObject[] selected = Selection.gameObjects;
618
+ if (selected.Length == 0)
619
+ {
620
+ return "No GameObjects selected";
621
+ }
622
+
623
+ string materialPath = "Assets/Materials/NewMaterial.mat";
624
+ Material newMat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
625
+ if (newMat == null)
626
+ {
627
+ return $"Material not found at {materialPath}";
628
+ }
629
+
630
+ int undoGroup = Undo.GetCurrentGroup();
631
+ Undo.SetCurrentGroupName("Batch Replace Material");
632
+
633
+ int replaced = 0;
634
+ foreach (GameObject obj in selected)
635
+ {
636
+ MeshRenderer renderer = obj.GetComponent<MeshRenderer>();
637
+ if (renderer != null)
638
+ {
639
+ Undo.RecordObject(renderer, "");
640
+ renderer.sharedMaterial = newMat;
641
+ replaced++;
642
+ }
643
+ }
644
+
645
+ Undo.CollapseUndoOperations(undoGroup);
646
+ return $"Replaced material on {replaced} objects";
647
+ \`\`\`
648
+
649
+ `,
650
+ 'examples/cleanup-operations.md': `# Cleanup Operations
651
+
652
+ Code examples for project cleanup operations using \`execute-dynamic-code\`.
653
+
654
+ ## Detect Missing Scripts on GameObject
655
+
656
+ \`\`\`csharp
657
+ using UnityEditor;
658
+
659
+ GameObject selected = Selection.activeGameObject;
660
+ if (selected == null)
661
+ {
662
+ return "No GameObject selected";
663
+ }
664
+
665
+ int missingCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(selected);
666
+ return $"{selected.name} has {missingCount} missing script(s)";
667
+ \`\`\`
668
+
669
+ ## Remove Missing Scripts from GameObject
670
+
671
+ \`\`\`csharp
672
+ using UnityEditor;
673
+
674
+ GameObject selected = Selection.activeGameObject;
675
+ if (selected == null)
676
+ {
677
+ return "No GameObject selected";
678
+ }
679
+
680
+ int removedCount = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(selected);
681
+ return $"Removed {removedCount} missing script(s) from {selected.name}";
682
+ \`\`\`
683
+
684
+ ## Scan Scene for Missing Scripts
685
+
686
+ \`\`\`csharp
687
+ using UnityEditor;
688
+
689
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
690
+ List<string> objectsWithMissing = new List<string>();
691
+
692
+ foreach (GameObject obj in allObjects)
693
+ {
694
+ int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(obj);
695
+ if (count > 0)
696
+ {
697
+ objectsWithMissing.Add($"{obj.name} ({count})");
698
+ }
699
+ }
700
+
701
+ if (objectsWithMissing.Count == 0)
702
+ {
703
+ return "No missing scripts found in scene";
704
+ }
705
+
706
+ return $"Objects with missing scripts: {string.Join(", ", objectsWithMissing)}";
707
+ \`\`\`
708
+
709
+ ## Remove All Missing Scripts from Scene
710
+
711
+ \`\`\`csharp
712
+ using UnityEditor;
713
+
714
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
715
+ int totalRemoved = 0;
716
+
717
+ int undoGroup = Undo.GetCurrentGroup();
718
+ Undo.SetCurrentGroupName("Remove All Missing Scripts");
719
+
720
+ foreach (GameObject obj in allObjects)
721
+ {
722
+ int removed = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(obj);
723
+ totalRemoved += removed;
724
+ }
725
+
726
+ Undo.CollapseUndoOperations(undoGroup);
727
+ return $"Removed {totalRemoved} missing scripts from scene";
728
+ \`\`\`
729
+
730
+ ## Detect Missing References in Component
731
+
732
+ \`\`\`csharp
733
+ using UnityEditor;
734
+
735
+ GameObject selected = Selection.activeGameObject;
736
+ if (selected == null)
737
+ {
738
+ return "No GameObject selected";
739
+ }
740
+
741
+ List<string> missingRefs = new List<string>();
742
+
743
+ Component[] components = selected.GetComponents<Component>();
744
+ foreach (Component comp in components)
745
+ {
746
+ if (comp == null) continue;
747
+
748
+ SerializedObject so = new SerializedObject(comp);
749
+ SerializedProperty prop = so.GetIterator();
750
+
751
+ while (prop.NextVisible(true))
752
+ {
753
+ if (prop.propertyType == SerializedPropertyType.ObjectReference)
754
+ {
755
+ if (prop.objectReferenceValue == null && prop.objectReferenceInstanceIDValue != 0)
756
+ {
757
+ missingRefs.Add($"{comp.GetType().Name}.{prop.name}");
758
+ }
759
+ }
760
+ }
761
+ }
762
+
763
+ if (missingRefs.Count == 0)
764
+ {
765
+ return "No missing references found";
766
+ }
767
+
768
+ return $"Missing references: {string.Join(", ", missingRefs)}";
769
+ \`\`\`
770
+
771
+ ## Scan Scene for Missing References
772
+
773
+ \`\`\`csharp
774
+ using UnityEditor;
775
+
776
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
777
+ List<string> results = new List<string>();
778
+
779
+ foreach (GameObject obj in allObjects)
780
+ {
781
+ Component[] components = obj.GetComponents<Component>();
782
+ foreach (Component comp in components)
783
+ {
784
+ if (comp == null) continue;
785
+
786
+ SerializedObject so = new SerializedObject(comp);
787
+ SerializedProperty prop = so.GetIterator();
788
+
789
+ while (prop.NextVisible(true))
790
+ {
791
+ if (prop.propertyType == SerializedPropertyType.ObjectReference)
792
+ {
793
+ if (prop.objectReferenceValue == null && prop.objectReferenceInstanceIDValue != 0)
794
+ {
795
+ results.Add($"{obj.name}/{comp.GetType().Name}.{prop.name}");
796
+ }
797
+ }
798
+ }
799
+ }
800
+ }
801
+
802
+ if (results.Count == 0)
803
+ {
804
+ return "No missing references found in scene";
805
+ }
806
+
807
+ return $"Missing references ({results.Count}): {string.Join(", ", results.Take(10))}...";
808
+ \`\`\`
809
+
810
+ ## Find Unused Materials in Project
811
+
812
+ \`\`\`csharp
813
+ using UnityEditor;
814
+
815
+ string[] materialGuids = AssetDatabase.FindAssets("t:Material");
816
+ HashSet<string> usedMaterials = new HashSet<string>();
817
+
818
+ string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab");
819
+ foreach (string guid in prefabGuids)
820
+ {
821
+ string path = AssetDatabase.GUIDToAssetPath(guid);
822
+ string[] deps = AssetDatabase.GetDependencies(path, true);
823
+ foreach (string dep in deps)
824
+ {
825
+ if (dep.EndsWith(".mat"))
826
+ {
827
+ usedMaterials.Add(dep);
828
+ }
829
+ }
830
+ }
831
+
832
+ List<string> unusedMaterials = new List<string>();
833
+ foreach (string guid in materialGuids)
834
+ {
835
+ string path = AssetDatabase.GUIDToAssetPath(guid);
836
+ if (!usedMaterials.Contains(path))
837
+ {
838
+ unusedMaterials.Add(path);
839
+ }
840
+ }
841
+
842
+ return $"Found {unusedMaterials.Count} potentially unused materials";
843
+ \`\`\`
844
+
845
+ ## Find Empty GameObjects
846
+
847
+ \`\`\`csharp
848
+ using UnityEditor;
849
+
850
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
851
+ List<string> emptyObjects = new List<string>();
852
+
853
+ foreach (GameObject obj in allObjects)
854
+ {
855
+ Component[] components = obj.GetComponents<Component>();
856
+ if (components.Length == 1 && obj.transform.childCount == 0)
857
+ {
858
+ emptyObjects.Add(obj.name);
859
+ }
860
+ }
861
+
862
+ if (emptyObjects.Count == 0)
863
+ {
864
+ return "No empty GameObjects found";
865
+ }
866
+
867
+ return $"Empty objects ({emptyObjects.Count}): {string.Join(", ", emptyObjects.Take(20))}";
868
+ \`\`\`
869
+
870
+ ## Find Duplicate Names in Hierarchy
871
+
872
+ \`\`\`csharp
873
+ using UnityEditor;
874
+
875
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
876
+ Dictionary<string, int> nameCounts = new Dictionary<string, int>();
877
+
878
+ foreach (GameObject obj in allObjects)
879
+ {
880
+ if (nameCounts.ContainsKey(obj.name))
881
+ {
882
+ nameCounts[obj.name]++;
883
+ }
884
+ else
885
+ {
886
+ nameCounts[obj.name] = 1;
887
+ }
888
+ }
889
+
890
+ List<string> duplicates = new List<string>();
891
+ foreach (KeyValuePair<string, int> kvp in nameCounts)
892
+ {
893
+ if (kvp.Value > 1)
894
+ {
895
+ duplicates.Add($"{kvp.Key} ({kvp.Value})");
896
+ }
897
+ }
898
+
899
+ if (duplicates.Count == 0)
900
+ {
901
+ return "No duplicate names found";
902
+ }
903
+
904
+ return $"Duplicate names: {string.Join(", ", duplicates.Take(15))}";
905
+ \`\`\`
906
+
907
+ ## Check for Broken Prefab Instances
908
+
909
+ \`\`\`csharp
910
+ using UnityEditor;
911
+
912
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
913
+ List<string> brokenPrefabs = new List<string>();
914
+
915
+ foreach (GameObject obj in allObjects)
916
+ {
917
+ if (PrefabUtility.IsPartOfPrefabInstance(obj))
918
+ {
919
+ GameObject prefabAsset = PrefabUtility.GetCorrespondingObjectFromSource(obj);
920
+ if (prefabAsset == null)
921
+ {
922
+ brokenPrefabs.Add(obj.name);
923
+ }
924
+ }
925
+ }
926
+
927
+ if (brokenPrefabs.Count == 0)
928
+ {
929
+ return "No broken prefab instances found";
930
+ }
931
+
932
+ return $"Broken prefab instances: {string.Join(", ", brokenPrefabs)}";
933
+ \`\`\`
934
+
935
+ ## Find Objects with Negative Scale
936
+
937
+ \`\`\`csharp
938
+ using UnityEditor;
939
+
940
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
941
+ List<string> negativeScale = new List<string>();
942
+
943
+ foreach (GameObject obj in allObjects)
944
+ {
945
+ Vector3 scale = obj.transform.localScale;
946
+ if (scale.x < 0 || scale.y < 0 || scale.z < 0)
947
+ {
948
+ negativeScale.Add($"{obj.name} ({scale})");
949
+ }
950
+ }
951
+
952
+ if (negativeScale.Count == 0)
953
+ {
954
+ return "No objects with negative scale found";
955
+ }
956
+
957
+ return $"Negative scale objects: {string.Join(", ", negativeScale.Take(10))}";
958
+ \`\`\`
959
+
960
+ ## Remove Empty Parent GameObjects
961
+
962
+ \`\`\`csharp
963
+ using UnityEditor;
964
+
965
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
966
+
967
+ int undoGroup = Undo.GetCurrentGroup();
968
+ Undo.SetCurrentGroupName("Remove Empty Parents");
969
+
970
+ int removedCount = 0;
971
+ foreach (GameObject obj in allObjects)
972
+ {
973
+ if (obj == null) continue;
974
+
975
+ Component[] components = obj.GetComponents<Component>();
976
+ if (components.Length == 1 && obj.transform.childCount == 0)
977
+ {
978
+ Undo.DestroyObjectImmediate(obj);
979
+ removedCount++;
980
+ }
981
+ }
982
+
983
+ Undo.CollapseUndoOperations(undoGroup);
984
+ return $"Removed {removedCount} empty GameObjects";
985
+ \`\`\`
986
+
987
+ ## Find Large Meshes
988
+
989
+ \`\`\`csharp
990
+ using UnityEditor;
991
+
992
+ string[] meshGuids = AssetDatabase.FindAssets("t:Mesh");
993
+ List<string> largeMeshes = new List<string>();
994
+ int threshold = 10000;
995
+
996
+ foreach (string guid in meshGuids)
997
+ {
998
+ string path = AssetDatabase.GUIDToAssetPath(guid);
999
+ Mesh mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
1000
+ if (mesh != null && mesh.vertexCount > threshold)
1001
+ {
1002
+ largeMeshes.Add($"{path} ({mesh.vertexCount} verts)");
1003
+ }
1004
+ }
1005
+
1006
+ if (largeMeshes.Count == 0)
1007
+ {
1008
+ return $"No meshes with more than {threshold} vertices found";
1009
+ }
1010
+
1011
+ return $"Large meshes: {string.Join(", ", largeMeshes.Take(10))}";
1012
+ \`\`\`
1013
+
1014
+ ## Validate Asset References
1015
+
1016
+ \`\`\`csharp
1017
+ using UnityEditor;
1018
+
1019
+ string[] guids = AssetDatabase.FindAssets("t:ScriptableObject", new[] { "Assets/Data" });
1020
+ List<string> invalidRefs = new List<string>();
1021
+
1022
+ foreach (string guid in guids)
1023
+ {
1024
+ string path = AssetDatabase.GUIDToAssetPath(guid);
1025
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
1026
+ if (so == null) continue;
1027
+
1028
+ SerializedObject serializedObj = new SerializedObject(so);
1029
+ SerializedProperty prop = serializedObj.GetIterator();
1030
+
1031
+ while (prop.NextVisible(true))
1032
+ {
1033
+ if (prop.propertyType == SerializedPropertyType.ObjectReference)
1034
+ {
1035
+ if (prop.objectReferenceValue == null && prop.objectReferenceInstanceIDValue != 0)
1036
+ {
1037
+ invalidRefs.Add($"{path}: {prop.name}");
1038
+ }
1039
+ }
1040
+ }
1041
+ }
1042
+
1043
+ if (invalidRefs.Count == 0)
1044
+ {
1045
+ return "All asset references are valid";
1046
+ }
1047
+
1048
+ return $"Invalid references ({invalidRefs.Count}): {string.Join(", ", invalidRefs.Take(10))}";
1049
+ \`\`\`
1050
+
1051
+ `,
1052
+ 'examples/material-operations.md': `# Material Operations
1053
+
1054
+ Code examples for Material operations using \`execute-dynamic-code\`.
1055
+
1056
+ ## Create a New Material
1057
+
1058
+ \`\`\`csharp
1059
+ using UnityEditor;
1060
+
1061
+ Shader shader = Shader.Find("Standard");
1062
+ Material mat = new Material(shader);
1063
+ mat.name = "MyMaterial";
1064
+ string path = "Assets/Materials/MyMaterial.mat";
1065
+ AssetDatabase.CreateAsset(mat, path);
1066
+ AssetDatabase.SaveAssets();
1067
+ return $"Material created at {path}";
1068
+ \`\`\`
1069
+
1070
+ ## Set Material Color
1071
+
1072
+ \`\`\`csharp
1073
+ using UnityEditor;
1074
+
1075
+ string matPath = "Assets/Materials/MyMaterial.mat";
1076
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
1077
+ mat.SetColor("_Color", new Color(1f, 0.5f, 0f, 1f));
1078
+ EditorUtility.SetDirty(mat);
1079
+ AssetDatabase.SaveAssets();
1080
+ return "Material color set to orange";
1081
+ \`\`\`
1082
+
1083
+ ## Set Material Properties (Float, Vector)
1084
+
1085
+ \`\`\`csharp
1086
+ using UnityEditor;
1087
+
1088
+ string matPath = "Assets/Materials/MyMaterial.mat";
1089
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
1090
+
1091
+ mat.SetFloat("_Metallic", 0.8f);
1092
+ mat.SetFloat("_Glossiness", 0.6f);
1093
+ mat.SetVector("_EmissionColor", new Vector4(1, 1, 0, 1));
1094
+
1095
+ EditorUtility.SetDirty(mat);
1096
+ AssetDatabase.SaveAssets();
1097
+ return "Material properties updated";
1098
+ \`\`\`
1099
+
1100
+ ## Assign Texture to Material
1101
+
1102
+ \`\`\`csharp
1103
+ using UnityEditor;
1104
+
1105
+ string matPath = "Assets/Materials/MyMaterial.mat";
1106
+ string texPath = "Assets/Textures/MyTexture.png";
1107
+
1108
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
1109
+ Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(texPath);
1110
+
1111
+ mat.SetTexture("_MainTex", tex);
1112
+ EditorUtility.SetDirty(mat);
1113
+ AssetDatabase.SaveAssets();
1114
+ return $"Assigned {tex.name} to material";
1115
+ \`\`\`
1116
+
1117
+ ## Assign Material to GameObject
1118
+
1119
+ \`\`\`csharp
1120
+ using UnityEditor;
1121
+
1122
+ string matPath = "Assets/Materials/MyMaterial.mat";
1123
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
1124
+
1125
+ GameObject selected = Selection.activeGameObject;
1126
+ if (selected == null)
1127
+ {
1128
+ return "No GameObject selected";
1129
+ }
1130
+
1131
+ Renderer renderer = selected.GetComponent<Renderer>();
1132
+ if (renderer == null)
1133
+ {
1134
+ return "Selected object has no Renderer";
1135
+ }
1136
+
1137
+ renderer.sharedMaterial = mat;
1138
+ EditorUtility.SetDirty(selected);
1139
+ return $"Assigned {mat.name} to {selected.name}";
1140
+ \`\`\`
1141
+
1142
+ ## Enable/Disable Material Keywords
1143
+
1144
+ \`\`\`csharp
1145
+ using UnityEditor;
1146
+
1147
+ string matPath = "Assets/Materials/MyMaterial.mat";
1148
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
1149
+
1150
+ mat.EnableKeyword("_EMISSION");
1151
+ mat.globalIlluminationFlags = MaterialGlobalIlluminationFlags.RealtimeEmissive;
1152
+
1153
+ EditorUtility.SetDirty(mat);
1154
+ AssetDatabase.SaveAssets();
1155
+ return "Emission enabled on material";
1156
+ \`\`\`
1157
+
1158
+ ## Find All Materials Using a Shader
1159
+
1160
+ \`\`\`csharp
1161
+ using UnityEditor;
1162
+
1163
+ string shaderName = "Standard";
1164
+ string[] guids = AssetDatabase.FindAssets("t:Material");
1165
+ List<string> matchingMaterials = new List<string>();
1166
+
1167
+ foreach (string guid in guids)
1168
+ {
1169
+ string path = AssetDatabase.GUIDToAssetPath(guid);
1170
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
1171
+ if (mat != null && mat.shader != null && mat.shader.name == shaderName)
1172
+ {
1173
+ matchingMaterials.Add(path);
1174
+ }
1175
+ }
1176
+ return $"Found {matchingMaterials.Count} materials using {shaderName}";
1177
+ \`\`\`
1178
+
1179
+ ## Duplicate Material
1180
+
1181
+ \`\`\`csharp
1182
+ using UnityEditor;
1183
+
1184
+ string sourcePath = "Assets/Materials/MyMaterial.mat";
1185
+ string destPath = "Assets/Materials/MyMaterial_Copy.mat";
1186
+
1187
+ Material source = AssetDatabase.LoadAssetAtPath<Material>(sourcePath);
1188
+ Material copy = new Material(source);
1189
+ AssetDatabase.CreateAsset(copy, destPath);
1190
+ AssetDatabase.SaveAssets();
1191
+ return $"Material duplicated to {destPath}";
1192
+ \`\`\`
1193
+ `,
1194
+ 'examples/prefab-operations.md': `# Prefab Operations
1195
+
1196
+ Code examples for Prefab operations using \`execute-dynamic-code\`.
1197
+
1198
+ ## Create a Prefab from GameObject
1199
+
1200
+ \`\`\`csharp
1201
+ using UnityEditor;
1202
+
1203
+ GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
1204
+ cube.name = "MyCube";
1205
+ string path = "Assets/Prefabs/MyCube.prefab";
1206
+ PrefabUtility.SaveAsPrefabAsset(cube, path);
1207
+ Object.DestroyImmediate(cube);
1208
+ return $"Prefab created at {path}";
1209
+ \`\`\`
1210
+
1211
+ ## Instantiate a Prefab
1212
+
1213
+ \`\`\`csharp
1214
+ using UnityEditor;
1215
+
1216
+ string prefabPath = "Assets/Prefabs/MyCube.prefab";
1217
+ GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
1218
+ if (prefab == null)
1219
+ {
1220
+ return $"Prefab not found at {prefabPath}";
1221
+ }
1222
+
1223
+ GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
1224
+ instance.transform.position = new Vector3(0, 1, 0);
1225
+ return $"Instantiated {instance.name}";
1226
+ \`\`\`
1227
+
1228
+ ## Add Component to Prefab
1229
+
1230
+ \`\`\`csharp
1231
+ using UnityEditor;
1232
+
1233
+ string prefabPath = "Assets/Prefabs/MyCube.prefab";
1234
+ GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
1235
+ string assetPath = AssetDatabase.GetAssetPath(prefab);
1236
+
1237
+ using (PrefabUtility.EditPrefabContentsScope scope = new PrefabUtility.EditPrefabContentsScope(assetPath))
1238
+ {
1239
+ GameObject root = scope.prefabContentsRoot;
1240
+ if (root.GetComponent<Rigidbody>() == null)
1241
+ {
1242
+ root.AddComponent<Rigidbody>();
1243
+ }
1244
+ }
1245
+ return "Added Rigidbody to prefab";
1246
+ \`\`\`
1247
+
1248
+ ## Modify Prefab Properties
1249
+
1250
+ \`\`\`csharp
1251
+ using UnityEditor;
1252
+
1253
+ string prefabPath = "Assets/Prefabs/MyCube.prefab";
1254
+ GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
1255
+
1256
+ using (PrefabUtility.EditPrefabContentsScope scope = new PrefabUtility.EditPrefabContentsScope(prefabPath))
1257
+ {
1258
+ GameObject root = scope.prefabContentsRoot;
1259
+ root.transform.localScale = new Vector3(2, 2, 2);
1260
+
1261
+ MeshRenderer renderer = root.GetComponent<MeshRenderer>();
1262
+ if (renderer != null)
1263
+ {
1264
+ renderer.sharedMaterial.color = Color.red;
1265
+ }
1266
+ }
1267
+ return "Modified prefab properties";
1268
+ \`\`\`
1269
+
1270
+ ## Find All Prefab Instances in Scene
1271
+
1272
+ \`\`\`csharp
1273
+ using UnityEditor;
1274
+ using System.Collections.Generic;
1275
+
1276
+ string prefabPath = "Assets/Prefabs/MyCube.prefab";
1277
+ GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
1278
+ if (prefab == null)
1279
+ {
1280
+ return $"Prefab not found at {prefabPath}";
1281
+ }
1282
+
1283
+ List<GameObject> instances = new List<GameObject>();
1284
+
1285
+ foreach (GameObject obj in Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None))
1286
+ {
1287
+ if (PrefabUtility.GetCorrespondingObjectFromSource(obj) == prefab)
1288
+ {
1289
+ instances.Add(obj);
1290
+ }
1291
+ }
1292
+ return $"Found {instances.Count} instances of {prefab.name}";
1293
+ \`\`\`
1294
+
1295
+ ## Apply Prefab Overrides
1296
+
1297
+ \`\`\`csharp
1298
+ using UnityEditor;
1299
+
1300
+ GameObject selected = Selection.activeGameObject;
1301
+ if (selected == null)
1302
+ {
1303
+ return "No GameObject selected";
1304
+ }
1305
+
1306
+ if (!PrefabUtility.IsPartOfPrefabInstance(selected))
1307
+ {
1308
+ return "Selected object is not a prefab instance";
1309
+ }
1310
+
1311
+ PrefabUtility.ApplyPrefabInstance(selected, InteractionMode.UserAction);
1312
+ return $"Applied overrides from {selected.name} to prefab";
1313
+ \`\`\`
1314
+ `,
1315
+ 'examples/scene-operations.md': `# Scene Operations
1316
+
1317
+ Code examples for Scene and Hierarchy operations using \`execute-dynamic-code\`.
1318
+
1319
+ ## Create GameObject
1320
+
1321
+ \`\`\`csharp
1322
+ GameObject obj = new GameObject("MyObject");
1323
+ obj.transform.position = new Vector3(0, 1, 0);
1324
+ return $"Created {obj.name}";
1325
+ \`\`\`
1326
+
1327
+ ## Create UI GameObject (under Canvas)
1328
+
1329
+ \`\`\`csharp
1330
+ using UnityEngine.UI;
1331
+
1332
+ // UI objects require RectTransform, which is auto-added when parented to Canvas
1333
+ GameObject canvas = GameObject.Find("Canvas");
1334
+ if (canvas == null)
1335
+ {
1336
+ return "Canvas not found in scene";
1337
+ }
1338
+
1339
+ GameObject uiObj = new GameObject("MyUIElement");
1340
+ uiObj.transform.SetParent(canvas.transform, false);
1341
+ uiObj.AddComponent<RectTransform>();
1342
+ uiObj.AddComponent<Image>();
1343
+ return $"Created UI element: {uiObj.name}";
1344
+ \`\`\`
1345
+
1346
+ ## Create Primitive
1347
+
1348
+ \`\`\`csharp
1349
+ GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
1350
+ cube.name = "MyCube";
1351
+ cube.transform.position = new Vector3(2, 0, 0);
1352
+ return $"Created {cube.name}";
1353
+ \`\`\`
1354
+
1355
+ ## Add Component to GameObject
1356
+
1357
+ \`\`\`csharp
1358
+ GameObject selected = Selection.activeGameObject;
1359
+ if (selected == null)
1360
+ {
1361
+ return "No GameObject selected";
1362
+ }
1363
+
1364
+ Rigidbody rb = selected.AddComponent<Rigidbody>();
1365
+ rb.mass = 2f;
1366
+ rb.useGravity = true;
1367
+ return $"Added Rigidbody to {selected.name}";
1368
+ \`\`\`
1369
+
1370
+ ## Find GameObject by Name
1371
+
1372
+ \`\`\`csharp
1373
+ GameObject obj = GameObject.Find("Player");
1374
+ if (obj == null)
1375
+ {
1376
+ return "GameObject 'Player' not found";
1377
+ }
1378
+ return $"Found: {obj.name} at {obj.transform.position}";
1379
+ \`\`\`
1380
+
1381
+ ## Find GameObjects by Tag
1382
+
1383
+ \`\`\`csharp
1384
+ GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
1385
+ return $"Found {enemies.Length} GameObjects with tag 'Enemy'";
1386
+ \`\`\`
1387
+
1388
+ ## Set Parent
1389
+
1390
+ \`\`\`csharp
1391
+ GameObject child = GameObject.Find("Child");
1392
+ GameObject parent = GameObject.Find("Parent");
1393
+
1394
+ if (child == null || parent == null)
1395
+ {
1396
+ return "Child or Parent not found";
1397
+ }
1398
+
1399
+ child.transform.SetParent(parent.transform);
1400
+ return $"Set {child.name}'s parent to {parent.name}";
1401
+ \`\`\`
1402
+
1403
+ ## Get All Children
1404
+
1405
+ \`\`\`csharp
1406
+ GameObject parent = Selection.activeGameObject;
1407
+ if (parent == null)
1408
+ {
1409
+ return "No GameObject selected";
1410
+ }
1411
+
1412
+ List<string> children = new List<string>();
1413
+ foreach (Transform child in parent.transform)
1414
+ {
1415
+ children.Add(child.name);
1416
+ }
1417
+ return $"Children: {string.Join(", ", children)}";
1418
+ \`\`\`
1419
+
1420
+ ## Wire Component References
1421
+
1422
+ \`\`\`csharp
1423
+ using UnityEditor;
1424
+
1425
+ GameObject player = GameObject.Find("Player");
1426
+ GameObject target = GameObject.Find("Target");
1427
+
1428
+ if (player == null || target == null)
1429
+ {
1430
+ return "Player or Target not found";
1431
+ }
1432
+
1433
+ MonoBehaviour script = player.GetComponent("PlayerController") as MonoBehaviour;
1434
+ if (script == null)
1435
+ {
1436
+ return "PlayerController not found on Player";
1437
+ }
1438
+
1439
+ SerializedObject serializedScript = new SerializedObject(script);
1440
+ SerializedProperty targetProp = serializedScript.FindProperty("target");
1441
+
1442
+ if (targetProp != null)
1443
+ {
1444
+ targetProp.objectReferenceValue = target.transform;
1445
+ serializedScript.ApplyModifiedProperties();
1446
+ return "Target reference wired";
1447
+ }
1448
+ return "Property 'target' not found";
1449
+ \`\`\`
1450
+
1451
+ ## Load Scene (Editor)
1452
+
1453
+ \`\`\`csharp
1454
+ using UnityEditor.SceneManagement;
1455
+
1456
+ string scenePath = "Assets/Scenes/MainMenu.unity";
1457
+ EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
1458
+ return $"Loaded scene: {scenePath}";
1459
+ \`\`\`
1460
+
1461
+ ## Save Current Scene
1462
+
1463
+ \`\`\`csharp
1464
+ using UnityEditor.SceneManagement;
1465
+
1466
+ UnityEngine.SceneManagement.Scene scene = EditorSceneManager.GetActiveScene();
1467
+ EditorSceneManager.SaveScene(scene);
1468
+ return $"Saved scene: {scene.name}";
1469
+ \`\`\`
1470
+
1471
+ ## Create New Scene
1472
+
1473
+ \`\`\`csharp
1474
+ using UnityEditor.SceneManagement;
1475
+
1476
+ UnityEngine.SceneManagement.Scene newScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
1477
+ return $"Created new scene: {newScene.name}";
1478
+ \`\`\`
1479
+
1480
+ ## Get All Root GameObjects in Scene
1481
+
1482
+ \`\`\`csharp
1483
+ UnityEngine.SceneManagement.Scene scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
1484
+ GameObject[] roots = scene.GetRootGameObjects();
1485
+
1486
+ List<string> names = new List<string>();
1487
+ foreach (GameObject root in roots)
1488
+ {
1489
+ names.Add(root.name);
1490
+ }
1491
+ return $"Root objects: {string.Join(", ", names)}";
1492
+ \`\`\`
1493
+
1494
+ ## Destroy GameObject
1495
+
1496
+ \`\`\`csharp
1497
+ GameObject obj = GameObject.Find("OldObject");
1498
+ if (obj == null)
1499
+ {
1500
+ return "GameObject not found";
1501
+ }
1502
+
1503
+ Object.DestroyImmediate(obj);
1504
+ return "GameObject destroyed";
1505
+ \`\`\`
1506
+
1507
+ ## Duplicate GameObject
1508
+
1509
+ \`\`\`csharp
1510
+ GameObject selected = Selection.activeGameObject;
1511
+ if (selected == null)
1512
+ {
1513
+ return "No GameObject selected";
1514
+ }
1515
+
1516
+ GameObject copy = Object.Instantiate(selected);
1517
+ copy.name = selected.name + "_Copy";
1518
+ copy.transform.position = selected.transform.position + Vector3.right * 2;
1519
+ return $"Created duplicate: {copy.name}";
1520
+ \`\`\`
1521
+
1522
+ ## Set Active/Inactive
1523
+
1524
+ \`\`\`csharp
1525
+ GameObject obj = GameObject.Find("MyObject");
1526
+ if (obj == null)
1527
+ {
1528
+ return "GameObject not found";
1529
+ }
1530
+
1531
+ obj.SetActive(!obj.activeSelf);
1532
+ return $"{obj.name} is now {(obj.activeSelf ? "active" : "inactive")}";
1533
+ \`\`\`
1534
+
1535
+ ## Modify Transform
1536
+
1537
+ \`\`\`csharp
1538
+ GameObject selected = Selection.activeGameObject;
1539
+ if (selected == null)
1540
+ {
1541
+ return "No GameObject selected";
1542
+ }
1543
+
1544
+ selected.transform.position = new Vector3(0, 5, 0);
1545
+ selected.transform.rotation = Quaternion.Euler(0, 45, 0);
1546
+ selected.transform.localScale = new Vector3(2, 2, 2);
1547
+ return "Transform modified";
1548
+ \`\`\`
1549
+ `,
1550
+ 'examples/scriptableobject.md': `# ScriptableObject Operations
1551
+
1552
+ Code examples for ScriptableObject operations using \`execute-dynamic-code\`.
1553
+
1554
+ ## Create ScriptableObject Instance
1555
+
1556
+ \`\`\`csharp
1557
+ using UnityEditor;
1558
+
1559
+ ScriptableObject so = ScriptableObject.CreateInstance<ScriptableObject>();
1560
+ string path = "Assets/Data/MyData.asset";
1561
+ AssetDatabase.CreateAsset(so, path);
1562
+ AssetDatabase.SaveAssets();
1563
+ return $"ScriptableObject created at {path}";
1564
+ \`\`\`
1565
+
1566
+ ## Create Custom ScriptableObject
1567
+
1568
+ \`\`\`csharp
1569
+ using UnityEditor;
1570
+
1571
+ ScriptableObject so = ScriptableObject.CreateInstance("MyCustomSO");
1572
+ if (so == null)
1573
+ {
1574
+ return "Type 'MyCustomSO' not found. Ensure the class exists.";
1575
+ }
1576
+
1577
+ string path = "Assets/Data/MyCustomData.asset";
1578
+ AssetDatabase.CreateAsset(so, path);
1579
+ AssetDatabase.SaveAssets();
1580
+ return $"Created {so.GetType().Name} at {path}";
1581
+ \`\`\`
1582
+
1583
+ ## Modify ScriptableObject with SerializedObject
1584
+
1585
+ \`\`\`csharp
1586
+ using UnityEditor;
1587
+
1588
+ string path = "Assets/Data/MyData.asset";
1589
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
1590
+
1591
+ if (so == null)
1592
+ {
1593
+ return $"Asset not found at {path}";
1594
+ }
1595
+
1596
+ SerializedObject serializedObj = new SerializedObject(so);
1597
+ SerializedProperty prop = serializedObj.FindProperty("myField");
1598
+
1599
+ if (prop != null)
1600
+ {
1601
+ prop.stringValue = "New Value";
1602
+ serializedObj.ApplyModifiedProperties();
1603
+ EditorUtility.SetDirty(so);
1604
+ AssetDatabase.SaveAssets();
1605
+ return "Property updated";
1606
+ }
1607
+ return "Property 'myField' not found";
1608
+ \`\`\`
1609
+
1610
+ ## Set Int/Float/Bool Properties
1611
+
1612
+ \`\`\`csharp
1613
+ using UnityEditor;
1614
+
1615
+ string path = "Assets/Data/GameSettings.asset";
1616
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
1617
+
1618
+ SerializedObject serializedObj = new SerializedObject(so);
1619
+
1620
+ SerializedProperty intProp = serializedObj.FindProperty("maxHealth");
1621
+ if (intProp != null) intProp.intValue = 100;
1622
+
1623
+ SerializedProperty floatProp = serializedObj.FindProperty("moveSpeed");
1624
+ if (floatProp != null) floatProp.floatValue = 5.5f;
1625
+
1626
+ SerializedProperty boolProp = serializedObj.FindProperty("isEnabled");
1627
+ if (boolProp != null) boolProp.boolValue = true;
1628
+
1629
+ serializedObj.ApplyModifiedProperties();
1630
+ EditorUtility.SetDirty(so);
1631
+ AssetDatabase.SaveAssets();
1632
+ return "Properties updated";
1633
+ \`\`\`
1634
+
1635
+ ## Set Reference Properties
1636
+
1637
+ \`\`\`csharp
1638
+ using UnityEditor;
1639
+
1640
+ string soPath = "Assets/Data/CharacterData.asset";
1641
+ string prefabPath = "Assets/Prefabs/Player.prefab";
1642
+
1643
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(soPath);
1644
+ GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
1645
+
1646
+ if (so == null)
1647
+ {
1648
+ return $"ScriptableObject not found at {soPath}";
1649
+ }
1650
+ if (prefab == null)
1651
+ {
1652
+ return $"Prefab not found at {prefabPath}";
1653
+ }
1654
+
1655
+ SerializedObject serializedObj = new SerializedObject(so);
1656
+ SerializedProperty prop = serializedObj.FindProperty("playerPrefab");
1657
+
1658
+ if (prop != null)
1659
+ {
1660
+ prop.objectReferenceValue = prefab;
1661
+ serializedObj.ApplyModifiedProperties();
1662
+ EditorUtility.SetDirty(so);
1663
+ AssetDatabase.SaveAssets();
1664
+ return "Reference set successfully";
1665
+ }
1666
+ return "Property not found";
1667
+ \`\`\`
1668
+
1669
+ ## Set Array/List Properties
1670
+
1671
+ \`\`\`csharp
1672
+ using UnityEditor;
1673
+
1674
+ string path = "Assets/Data/ItemDatabase.asset";
1675
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
1676
+
1677
+ if (so == null)
1678
+ {
1679
+ return $"Asset not found at {path}";
1680
+ }
1681
+
1682
+ SerializedObject serializedObj = new SerializedObject(so);
1683
+ SerializedProperty arrayProp = serializedObj.FindProperty("items");
1684
+
1685
+ if (arrayProp != null && arrayProp.isArray)
1686
+ {
1687
+ arrayProp.ClearArray();
1688
+ arrayProp.InsertArrayElementAtIndex(0);
1689
+ arrayProp.GetArrayElementAtIndex(0).stringValue = "Sword";
1690
+ arrayProp.InsertArrayElementAtIndex(1);
1691
+ arrayProp.GetArrayElementAtIndex(1).stringValue = "Shield";
1692
+
1693
+ serializedObj.ApplyModifiedProperties();
1694
+ EditorUtility.SetDirty(so);
1695
+ AssetDatabase.SaveAssets();
1696
+ return "Array updated with 2 items";
1697
+ }
1698
+ return "Array property not found";
1699
+ \`\`\`
1700
+
1701
+ ## Find All ScriptableObjects of Type
1702
+
1703
+ \`\`\`csharp
1704
+ using UnityEditor;
1705
+ using System.Collections.Generic;
1706
+
1707
+ string typeName = "GameSettings";
1708
+ string[] guids = AssetDatabase.FindAssets($"t:{typeName}");
1709
+ List<string> paths = new List<string>();
1710
+
1711
+ foreach (string guid in guids)
1712
+ {
1713
+ paths.Add(AssetDatabase.GUIDToAssetPath(guid));
1714
+ }
1715
+ return $"Found {paths.Count} {typeName} assets";
1716
+ \`\`\`
1717
+
1718
+ ## Duplicate ScriptableObject
1719
+
1720
+ \`\`\`csharp
1721
+ using UnityEditor;
1722
+
1723
+ string sourcePath = "Assets/Data/Template.asset";
1724
+ string destPath = "Assets/Data/NewInstance.asset";
1725
+
1726
+ ScriptableObject source = AssetDatabase.LoadAssetAtPath<ScriptableObject>(sourcePath);
1727
+ if (source == null)
1728
+ {
1729
+ return $"Source asset not found at {sourcePath}";
1730
+ }
1731
+
1732
+ ScriptableObject copy = Object.Instantiate(source);
1733
+ AssetDatabase.CreateAsset(copy, destPath);
1734
+ AssetDatabase.SaveAssets();
1735
+ return $"Duplicated to {destPath}";
1736
+ \`\`\`
1737
+
1738
+ ## List All Properties of ScriptableObject
1739
+
1740
+ \`\`\`csharp
1741
+ using UnityEditor;
1742
+ using System.Collections.Generic;
1743
+
1744
+ string path = "Assets/Data/MyData.asset";
1745
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
1746
+
1747
+ if (so == null)
1748
+ {
1749
+ return $"Asset not found at {path}";
1750
+ }
1751
+
1752
+ SerializedObject serializedObj = new SerializedObject(so);
1753
+ SerializedProperty prop = serializedObj.GetIterator();
1754
+
1755
+ List<string> properties = new List<string>();
1756
+ while (prop.NextVisible(true))
1757
+ {
1758
+ properties.Add($"{prop.name} ({prop.propertyType})");
1759
+ }
1760
+ return string.Join(", ", properties);
1761
+ \`\`\`
1762
+ `,
1763
+ 'examples/selection-operations.md': `# Selection Operations
1764
+
1765
+ Code examples for Selection operations using \`execute-dynamic-code\`.
1766
+
1767
+ ## Get Selected GameObjects
1768
+
1769
+ \`\`\`csharp
1770
+ using UnityEditor;
1771
+ using System.Collections.Generic;
1772
+
1773
+ GameObject[] selected = Selection.gameObjects;
1774
+ if (selected.Length == 0)
1775
+ {
1776
+ return "No GameObjects selected";
1777
+ }
1778
+
1779
+ List<string> names = new List<string>();
1780
+ foreach (GameObject obj in selected)
1781
+ {
1782
+ names.Add(obj.name);
1783
+ }
1784
+ return $"Selected: {string.Join(", ", names)}";
1785
+ \`\`\`
1786
+
1787
+ ## Get Active (Last Selected) GameObject
1788
+
1789
+ \`\`\`csharp
1790
+ using UnityEditor;
1791
+
1792
+ GameObject active = Selection.activeGameObject;
1793
+ if (active == null)
1794
+ {
1795
+ return "No active GameObject";
1796
+ }
1797
+ return $"Active: {active.name}";
1798
+ \`\`\`
1799
+
1800
+ ## Set Selection Programmatically
1801
+
1802
+ \`\`\`csharp
1803
+ using UnityEditor;
1804
+
1805
+ GameObject obj = GameObject.Find("Player");
1806
+ if (obj == null)
1807
+ {
1808
+ return "GameObject 'Player' not found";
1809
+ }
1810
+
1811
+ Selection.activeGameObject = obj;
1812
+ return $"Selected {obj.name}";
1813
+ \`\`\`
1814
+
1815
+ ## Select Multiple GameObjects
1816
+
1817
+ \`\`\`csharp
1818
+ using UnityEditor;
1819
+
1820
+ GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
1821
+ if (enemies.Length == 0)
1822
+ {
1823
+ return "No enemies found";
1824
+ }
1825
+
1826
+ Selection.objects = enemies;
1827
+ return $"Selected {enemies.Length} enemies";
1828
+ \`\`\`
1829
+
1830
+ ## Get Top-Level Transforms Only
1831
+
1832
+ \`\`\`csharp
1833
+ using UnityEditor;
1834
+ using System.Collections.Generic;
1835
+
1836
+ Transform[] transforms = Selection.GetTransforms(SelectionMode.TopLevel);
1837
+ if (transforms.Length == 0)
1838
+ {
1839
+ return "No transforms selected";
1840
+ }
1841
+
1842
+ List<string> names = new List<string>();
1843
+ foreach (Transform t in transforms)
1844
+ {
1845
+ names.Add(t.name);
1846
+ }
1847
+ return $"Top-level: {string.Join(", ", names)}";
1848
+ \`\`\`
1849
+
1850
+ ## Get Deep Selection (Including Children)
1851
+
1852
+ \`\`\`csharp
1853
+ using UnityEditor;
1854
+
1855
+ Transform[] transforms = Selection.GetTransforms(SelectionMode.Deep);
1856
+ if (transforms.Length == 0)
1857
+ {
1858
+ return "No transforms selected";
1859
+ }
1860
+
1861
+ return $"Deep selection count: {transforms.Length}";
1862
+ \`\`\`
1863
+
1864
+ ## Get Editable Objects Only
1865
+
1866
+ \`\`\`csharp
1867
+ using UnityEditor;
1868
+ using System.Collections.Generic;
1869
+
1870
+ Transform[] transforms = Selection.GetTransforms(SelectionMode.Editable);
1871
+ if (transforms.Length == 0)
1872
+ {
1873
+ return "No editable transforms selected";
1874
+ }
1875
+
1876
+ List<string> names = new List<string>();
1877
+ foreach (Transform t in transforms)
1878
+ {
1879
+ names.Add(t.name);
1880
+ }
1881
+ return $"Editable: {string.Join(", ", names)}";
1882
+ \`\`\`
1883
+
1884
+ ## Get Selected Assets
1885
+
1886
+ \`\`\`csharp
1887
+ using UnityEditor;
1888
+ using System.Collections.Generic;
1889
+
1890
+ Object[] selectedAssets = Selection.GetFiltered<Object>(SelectionMode.Assets);
1891
+ if (selectedAssets.Length == 0)
1892
+ {
1893
+ return "No assets selected";
1894
+ }
1895
+
1896
+ List<string> paths = new List<string>();
1897
+ foreach (Object asset in selectedAssets)
1898
+ {
1899
+ paths.Add(AssetDatabase.GetAssetPath(asset));
1900
+ }
1901
+ return $"Assets: {string.Join(", ", paths)}";
1902
+ \`\`\`
1903
+
1904
+ ## Get Selected Asset GUIDs
1905
+
1906
+ \`\`\`csharp
1907
+ using UnityEditor;
1908
+ using System.Collections.Generic;
1909
+
1910
+ string[] guids = Selection.assetGUIDs;
1911
+ if (guids.Length == 0)
1912
+ {
1913
+ return "No assets selected";
1914
+ }
1915
+
1916
+ List<string> paths = new List<string>();
1917
+ foreach (string guid in guids)
1918
+ {
1919
+ paths.Add(AssetDatabase.GUIDToAssetPath(guid));
1920
+ }
1921
+ return $"Selected assets: {string.Join(", ", paths)}";
1922
+ \`\`\`
1923
+
1924
+ ## Select All Children of Selected Object
1925
+
1926
+ \`\`\`csharp
1927
+ using UnityEditor;
1928
+ using UnityEngine;
1929
+ using System.Collections.Generic;
1930
+
1931
+ GameObject parent = Selection.activeGameObject;
1932
+ if (parent == null)
1933
+ {
1934
+ return "No GameObject selected";
1935
+ }
1936
+
1937
+ List<GameObject> children = new List<GameObject>();
1938
+ foreach (Transform child in parent.GetComponentsInChildren<Transform>())
1939
+ {
1940
+ if (child != parent.transform)
1941
+ {
1942
+ children.Add(child.gameObject);
1943
+ }
1944
+ }
1945
+
1946
+ if (children.Count == 0)
1947
+ {
1948
+ return "No children found";
1949
+ }
1950
+
1951
+ Selection.objects = children.ToArray();
1952
+ return $"Selected {children.Count} children";
1953
+ \`\`\`
1954
+
1955
+ ## Filter Selection by Component
1956
+
1957
+ \`\`\`csharp
1958
+ using UnityEditor;
1959
+ using System.Collections.Generic;
1960
+
1961
+ GameObject[] selected = Selection.gameObjects;
1962
+ List<GameObject> withRigidbody = new List<GameObject>();
1963
+
1964
+ foreach (GameObject obj in selected)
1965
+ {
1966
+ if (obj.GetComponent<Rigidbody>() != null)
1967
+ {
1968
+ withRigidbody.Add(obj);
1969
+ }
1970
+ }
1971
+
1972
+ if (withRigidbody.Count == 0)
1973
+ {
1974
+ return "No objects with Rigidbody in selection";
1975
+ }
1976
+
1977
+ Selection.objects = withRigidbody.ToArray();
1978
+ return $"Filtered to {withRigidbody.Count} objects with Rigidbody";
1979
+ \`\`\`
1980
+
1981
+ ## Check if Object is Selected
1982
+
1983
+ \`\`\`csharp
1984
+ using UnityEditor;
1985
+
1986
+ GameObject player = GameObject.Find("Player");
1987
+ if (player == null)
1988
+ {
1989
+ return "Player not found";
1990
+ }
1991
+
1992
+ bool isSelected = Selection.Contains(player);
1993
+ return $"Player is {(isSelected ? "" : "not ")}selected";
1994
+ \`\`\`
1995
+
1996
+ ## Clear Selection
1997
+
1998
+ \`\`\`csharp
1999
+ using UnityEditor;
2000
+
2001
+ Selection.activeObject = null;
2002
+ return "Selection cleared";
2003
+ \`\`\`
2004
+
2005
+ ## Select Objects by Layer
2006
+
2007
+ \`\`\`csharp
2008
+ using UnityEditor;
2009
+ using System.Collections.Generic;
2010
+
2011
+ int layer = LayerMask.NameToLayer("UI");
2012
+ GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
2013
+ List<GameObject> layerObjects = new List<GameObject>();
2014
+
2015
+ foreach (GameObject obj in allObjects)
2016
+ {
2017
+ if (obj.layer == layer)
2018
+ {
2019
+ layerObjects.Add(obj);
2020
+ }
2021
+ }
2022
+
2023
+ if (layerObjects.Count == 0)
2024
+ {
2025
+ return "No objects found on UI layer";
2026
+ }
2027
+
2028
+ Selection.objects = layerObjects.ToArray();
2029
+ return $"Selected {layerObjects.Count} objects on UI layer";
2030
+ \`\`\`
2031
+
2032
+ ## Ping Object in Hierarchy/Project
2033
+
2034
+ \`\`\`csharp
2035
+ using UnityEditor;
2036
+
2037
+ GameObject obj = GameObject.Find("Player");
2038
+ if (obj == null)
2039
+ {
2040
+ return "Player not found";
2041
+ }
2042
+
2043
+ EditorGUIUtility.PingObject(obj);
2044
+ return $"Pinged {obj.name} in Hierarchy";
2045
+ \`\`\`
2046
+
2047
+ ## Focus on Selected Object in Scene View
2048
+
2049
+ \`\`\`csharp
2050
+ using UnityEditor;
2051
+
2052
+ if (Selection.activeGameObject == null)
2053
+ {
2054
+ return "No GameObject selected";
2055
+ }
2056
+
2057
+ SceneView.FrameLastActiveSceneView();
2058
+ return "Focused on selected object";
2059
+ \`\`\`
2060
+
2061
+ `,
2062
+ 'examples/undo-operations.md': `# Undo Operations
2063
+
2064
+ Code examples for Undo-supported operations using \`execute-dynamic-code\`.
2065
+
2066
+ ## Record Property Change (Undo.RecordObject)
2067
+
2068
+ \`\`\`csharp
2069
+ using UnityEditor;
2070
+
2071
+ GameObject selected = Selection.activeGameObject;
2072
+ if (selected == null)
2073
+ {
2074
+ return "No GameObject selected";
2075
+ }
2076
+
2077
+ Undo.RecordObject(selected.transform, "Move Object");
2078
+ selected.transform.position = new Vector3(0, 5, 0);
2079
+ return $"Moved {selected.name} (Undo available)";
2080
+ \`\`\`
2081
+
2082
+ ## Record Multiple Objects
2083
+
2084
+ \`\`\`csharp
2085
+ using UnityEditor;
2086
+
2087
+ GameObject[] selectedObjects = Selection.gameObjects;
2088
+ if (selectedObjects.Length == 0)
2089
+ {
2090
+ return "No GameObjects selected";
2091
+ }
2092
+
2093
+ Object[] transforms = new Object[selectedObjects.Length];
2094
+ for (int i = 0; i < selectedObjects.Length; i++)
2095
+ {
2096
+ transforms[i] = selectedObjects[i].transform;
2097
+ }
2098
+
2099
+ Undo.RecordObjects(transforms, "Move Multiple Objects");
2100
+ foreach (GameObject obj in selectedObjects)
2101
+ {
2102
+ obj.transform.position += Vector3.up * 2;
2103
+ }
2104
+ return $"Moved {selectedObjects.Length} objects (Undo available)";
2105
+ \`\`\`
2106
+
2107
+ ## Complete Object Undo (For Complex Changes)
2108
+
2109
+ \`\`\`csharp
2110
+ using UnityEditor;
2111
+
2112
+ GameObject selected = Selection.activeGameObject;
2113
+ if (selected == null)
2114
+ {
2115
+ return "No GameObject selected";
2116
+ }
2117
+
2118
+ Undo.RegisterCompleteObjectUndo(selected, "Complete Object Change");
2119
+ selected.name = "RenamedObject";
2120
+ selected.layer = LayerMask.NameToLayer("Default");
2121
+ selected.tag = "Untagged";
2122
+ return $"Modified object completely (Undo available)";
2123
+ \`\`\`
2124
+
2125
+ ## Add Component with Undo
2126
+
2127
+ \`\`\`csharp
2128
+ using UnityEditor;
2129
+
2130
+ GameObject selected = Selection.activeGameObject;
2131
+ if (selected == null)
2132
+ {
2133
+ return "No GameObject selected";
2134
+ }
2135
+
2136
+ Rigidbody rb = Undo.AddComponent<Rigidbody>(selected);
2137
+ rb.mass = 2f;
2138
+ rb.useGravity = true;
2139
+ return $"Added Rigidbody to {selected.name} (Undo available)";
2140
+ \`\`\`
2141
+
2142
+ ## Set Parent with Undo
2143
+
2144
+ \`\`\`csharp
2145
+ using UnityEditor;
2146
+
2147
+ GameObject child = GameObject.Find("Child");
2148
+ GameObject parent = GameObject.Find("Parent");
2149
+
2150
+ if (child == null || parent == null)
2151
+ {
2152
+ return "Child or Parent not found";
2153
+ }
2154
+
2155
+ Undo.SetTransformParent(child.transform, parent.transform, "Set Parent");
2156
+ return $"Set {child.name}'s parent to {parent.name} (Undo available)";
2157
+ \`\`\`
2158
+
2159
+ ## Create GameObject with Undo
2160
+
2161
+ \`\`\`csharp
2162
+ using UnityEditor;
2163
+
2164
+ GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
2165
+ cube.name = "UndoableCube";
2166
+ cube.transform.position = new Vector3(0, 1, 0);
2167
+ Undo.RegisterCreatedObjectUndo(cube, "Create Cube");
2168
+ return $"Created {cube.name} (Undo available)";
2169
+ \`\`\`
2170
+
2171
+ ## Destroy GameObject with Undo
2172
+
2173
+ \`\`\`csharp
2174
+ using UnityEditor;
2175
+
2176
+ GameObject obj = GameObject.Find("ObjectToDelete");
2177
+ if (obj == null)
2178
+ {
2179
+ return "GameObject not found";
2180
+ }
2181
+
2182
+ Undo.DestroyObjectImmediate(obj);
2183
+ return "GameObject destroyed (Undo available)";
2184
+ \`\`\`
2185
+
2186
+ ## Named Undo Group
2187
+
2188
+ \`\`\`csharp
2189
+ using UnityEditor;
2190
+
2191
+ GameObject selected = Selection.activeGameObject;
2192
+ if (selected == null)
2193
+ {
2194
+ return "No GameObject selected";
2195
+ }
2196
+
2197
+ Undo.SetCurrentGroupName("Complex Transform Operation");
2198
+
2199
+ Undo.RecordObject(selected.transform, "");
2200
+ selected.transform.position = Vector3.zero;
2201
+ selected.transform.rotation = Quaternion.identity;
2202
+ selected.transform.localScale = Vector3.one;
2203
+
2204
+ return "Reset transform (Single undo step)";
2205
+ \`\`\`
2206
+
2207
+ ## Collapse Multiple Operations into One Undo
2208
+
2209
+ \`\`\`csharp
2210
+ using UnityEditor;
2211
+
2212
+ int undoGroup = Undo.GetCurrentGroup();
2213
+ Undo.SetCurrentGroupName("Batch Operation");
2214
+
2215
+ GameObject cube1 = GameObject.CreatePrimitive(PrimitiveType.Cube);
2216
+ cube1.name = "Cube1";
2217
+ Undo.RegisterCreatedObjectUndo(cube1, "");
2218
+
2219
+ GameObject cube2 = GameObject.CreatePrimitive(PrimitiveType.Cube);
2220
+ cube2.name = "Cube2";
2221
+ cube2.transform.position = Vector3.right * 2;
2222
+ Undo.RegisterCreatedObjectUndo(cube2, "");
2223
+
2224
+ GameObject cube3 = GameObject.CreatePrimitive(PrimitiveType.Cube);
2225
+ cube3.name = "Cube3";
2226
+ cube3.transform.position = Vector3.right * 4;
2227
+ Undo.RegisterCreatedObjectUndo(cube3, "");
2228
+
2229
+ Undo.CollapseUndoOperations(undoGroup);
2230
+ return "Created 3 cubes (Single undo step)";
2231
+ \`\`\`
2232
+
2233
+ ## Modify ScriptableObject with Undo
2234
+
2235
+ \`\`\`csharp
2236
+ using UnityEditor;
2237
+
2238
+ string path = "Assets/Data/GameSettings.asset";
2239
+ ScriptableObject so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
2240
+ if (so == null)
2241
+ {
2242
+ return $"Asset not found at {path}";
2243
+ }
2244
+
2245
+ Undo.RecordObject(so, "Modify Settings");
2246
+ SerializedObject serializedObj = new SerializedObject(so);
2247
+ SerializedProperty prop = serializedObj.FindProperty("maxHealth");
2248
+ if (prop != null)
2249
+ {
2250
+ prop.intValue = 200;
2251
+ serializedObj.ApplyModifiedProperties();
2252
+ }
2253
+ return "Modified ScriptableObject (Undo available)";
2254
+ \`\`\`
2255
+
2256
+ ## Modify Material with Undo
2257
+
2258
+ \`\`\`csharp
2259
+ using UnityEditor;
2260
+
2261
+ string path = "Assets/Materials/MyMaterial.mat";
2262
+ Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
2263
+ if (mat == null)
2264
+ {
2265
+ return $"Material not found at {path}";
2266
+ }
2267
+
2268
+ Undo.RecordObject(mat, "Change Material Color");
2269
+ mat.color = Color.red;
2270
+ return "Changed material color (Undo available)";
2271
+ \`\`\`
2272
+
2273
+ `,
2274
+ },
59
2275
  },
60
2276
  {
61
2277
  name: 'uloop-execute-menu-item',