@alpsckr/unitycli 0.4.3 → 0.4.4
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.
- package/README.md +5 -5
- package/contracts/command-contract.json +109 -217
- package/contracts/package-files.json +374 -294
- package/contracts/stable-session/direct-call-semantics.json +8 -2
- package/contracts/tool-completion-contract.json +148 -672
- package/dist/bridge/admission.d.ts +17 -1
- package/dist/bridge/admission.js +2 -0
- package/dist/bridge/admission.js.map +1 -1
- package/dist/bridge/domains/asset.js +3 -1
- package/dist/bridge/domains/asset.js.map +1 -1
- package/dist/bridge/domains/camera.js +39 -7
- package/dist/bridge/domains/camera.js.map +1 -1
- package/dist/bridge/domains/console.js +2 -1
- package/dist/bridge/domains/console.js.map +1 -1
- package/dist/bridge/domains/doctor.d.ts +3 -0
- package/dist/bridge/domains/doctor.js +8 -0
- package/dist/bridge/domains/doctor.js.map +1 -0
- package/dist/bridge/domains/editor.js +0 -4
- package/dist/bridge/domains/editor.js.map +1 -1
- package/dist/bridge/domains/game-object.js +4 -12
- package/dist/bridge/domains/game-object.js.map +1 -1
- package/dist/bridge/domains/graphics.js +1 -16
- package/dist/bridge/domains/graphics.js.map +1 -1
- package/dist/bridge/domains/object.js +3 -0
- package/dist/bridge/domains/object.js.map +1 -1
- package/dist/bridge/domains/physics.js +1 -2
- package/dist/bridge/domains/physics.js.map +1 -1
- package/dist/bridge/domains/profiler.js +18 -7
- package/dist/bridge/domains/profiler.js.map +1 -1
- package/dist/bridge/domains/project-tool.js +4 -0
- package/dist/bridge/domains/project-tool.js.map +1 -1
- package/dist/bridge/domains/reflection.js +10 -2
- package/dist/bridge/domains/reflection.js.map +1 -1
- package/dist/bridge/domains/runtime-tool.js +3 -0
- package/dist/bridge/domains/runtime-tool.js.map +1 -1
- package/dist/bridge/domains/scene.js +3 -8
- package/dist/bridge/domains/scene.js.map +1 -1
- package/dist/bridge/domains/screenshot.js +30 -6
- package/dist/bridge/domains/screenshot.js.map +1 -1
- package/dist/bridge/domains/ui.js +3 -1
- package/dist/bridge/domains/ui.js.map +1 -1
- package/dist/bridge/index.d.ts +5 -5
- package/dist/bridge/index.js +6 -9
- package/dist/bridge/index.js.map +1 -1
- package/dist/bridge/registry.js +3 -5
- package/dist/bridge/registry.js.map +1 -1
- package/dist/bridge/session-supervisor.d.ts +6 -3
- package/dist/bridge/session-supervisor.js +122 -34
- package/dist/bridge/session-supervisor.js.map +1 -1
- package/dist/bridge/types.d.ts +6 -5
- package/dist/bridge/types.js +16 -2
- package/dist/bridge/types.js.map +1 -1
- package/dist/catalog-protocol.d.ts +64 -0
- package/dist/catalog-protocol.js +460 -0
- package/dist/catalog-protocol.js.map +1 -0
- package/dist/cli-commands/command.js +84 -61
- package/dist/cli-commands/command.js.map +1 -1
- package/dist/cli-commands/extensions.js +70 -50
- package/dist/cli-commands/extensions.js.map +1 -1
- package/dist/cli-commands/instances.js +1 -1
- package/dist/cli-commands/instances.js.map +1 -1
- package/dist/cli-process-owners.d.ts +6 -0
- package/dist/cli-process-owners.js +27 -0
- package/dist/cli-process-owners.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +20 -5
- package/dist/cli.js.map +1 -1
- package/dist/contracts/command-contract.js +14 -4
- package/dist/contracts/command-contract.js.map +1 -1
- package/dist/doctor.d.ts +4 -6
- package/dist/doctor.js +429 -398
- package/dist/doctor.js.map +1 -1
- package/dist/editor-blocker-observer.d.ts +2 -1
- package/dist/editor-blocker-observer.js +40 -13
- package/dist/editor-blocker-observer.js.map +1 -1
- package/dist/extension-availability.d.ts +27 -9
- package/dist/extension-availability.js +96 -56
- package/dist/extension-availability.js.map +1 -1
- package/dist/extensions/descriptor-loader.d.ts +2 -2
- package/dist/extensions/descriptor-loader.js +3 -4
- package/dist/extensions/descriptor-loader.js.map +1 -1
- package/dist/extensions/index.d.ts +1 -1
- package/dist/extensions/index.js +1 -1
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/installer.d.ts +24 -7
- package/dist/extensions/installer.js +142 -66
- package/dist/extensions/installer.js.map +1 -1
- package/dist/extensions/registry.js +3 -5
- package/dist/extensions/registry.js.map +1 -1
- package/dist/extensions/state-contract.d.ts +11 -0
- package/dist/extensions/state-contract.js +50 -0
- package/dist/extensions/state-contract.js.map +1 -0
- package/dist/instances.d.ts +13 -1
- package/dist/instances.js +26 -0
- package/dist/instances.js.map +1 -1
- package/dist/package-manager.d.ts +0 -24
- package/dist/package-manager.js +5 -58
- package/dist/package-manager.js.map +1 -1
- package/dist/project-tool-discovery.d.ts +5 -2
- package/dist/project-tool-discovery.js +22 -18
- package/dist/project-tool-discovery.js.map +1 -1
- package/dist/runtime-code.js +1 -1
- package/dist/runtime-code.js.map +1 -1
- package/dist/tool-name.d.ts +4 -0
- package/dist/tool-name.js +15 -0
- package/dist/tool-name.js.map +1 -0
- package/dist/tools/.generated-completion-registry.d.ts +2 -0
- package/dist/tools/.generated-completion-registry.js +763 -325
- package/dist/tools/.generated-completion-registry.js.map +1 -1
- package/dist/tools/.generated-registry.d.ts +6 -11
- package/dist/tools/.generated-registry.js +6 -11
- package/dist/tools/.generated-registry.js.map +1 -1
- package/dist/tools/.generated-schemas.js +11 -16
- package/dist/tools/.generated-schemas.js.map +1 -1
- package/dist/tools/asset/refresh-status.d.ts +3 -0
- package/dist/tools/asset/refresh-status.js +12 -0
- package/dist/tools/asset/refresh-status.js.map +1 -0
- package/dist/tools/asset/refresh.js +7 -3
- package/dist/tools/asset/refresh.js.map +1 -1
- package/dist/tools/build/player-status.d.ts +3 -0
- package/dist/tools/build/player-status.js +12 -0
- package/dist/tools/build/player-status.js.map +1 -0
- package/dist/tools/build/run.js +1 -1
- package/dist/tools/build/run.js.map +1 -1
- package/dist/tools/catalog-control.d.ts +22 -0
- package/dist/tools/catalog-control.js +335 -0
- package/dist/tools/catalog-control.js.map +1 -0
- package/dist/tools/catalog.d.ts +7 -9
- package/dist/tools/catalog.js +66 -45
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/commands.d.ts +1 -1
- package/dist/tools/commands.js +44 -11
- package/dist/tools/commands.js.map +1 -1
- package/dist/tools/define.js +3 -2
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/dispatcher.d.ts +53 -6
- package/dist/tools/dispatcher.js +277 -108
- package/dist/tools/dispatcher.js.map +1 -1
- package/dist/tools/editor/compile.js +1 -1
- package/dist/tools/editor/compile.js.map +1 -1
- package/dist/tools/editor/play-mode-status.d.ts +3 -0
- package/dist/tools/editor/play-mode-status.js +12 -0
- package/dist/tools/editor/play-mode-status.js.map +1 -0
- package/dist/tools/editor/readiness.d.ts +0 -1
- package/dist/tools/editor/readiness.js +0 -1
- package/dist/tools/editor/readiness.js.map +1 -1
- package/dist/tools/editor/refresh.d.ts +7 -3
- package/dist/tools/editor/refresh.js +20 -15
- package/dist/tools/editor/refresh.js.map +1 -1
- package/dist/tools/editor/state.d.ts +2 -2
- package/dist/tools/editor/state.js +13 -12
- package/dist/tools/editor/state.js.map +1 -1
- package/dist/tools/metadata/derived.js +1 -7
- package/dist/tools/metadata/derived.js.map +1 -1
- package/dist/tools/metadata/status.js +1 -12
- package/dist/tools/metadata/status.js.map +1 -1
- package/dist/tools/metadata/types.d.ts +0 -2
- package/dist/tools/navmesh/live.js +1 -1
- package/dist/tools/navmesh/live.js.map +1 -1
- package/dist/tools/occlusion/live.js +1 -1
- package/dist/tools/occlusion/live.js.map +1 -1
- package/dist/tools/package/deploy.js +2 -2
- package/dist/tools/package/deploy.js.map +1 -1
- package/dist/tools/package/embed.js +1 -1
- package/dist/tools/package/embed.js.map +1 -1
- package/dist/tools/package/install-status.d.ts +3 -0
- package/dist/tools/package/install-status.js +12 -0
- package/dist/tools/package/install-status.js.map +1 -0
- package/dist/tools/package/install.js +3 -3
- package/dist/tools/package/install.js.map +1 -1
- package/dist/tools/package/live-resolve.js +45 -12
- package/dist/tools/package/live-resolve.js.map +1 -1
- package/dist/tools/package/registry-clear.js.map +1 -1
- package/dist/tools/package/registry-set.js.map +1 -1
- package/dist/tools/package/remove-status.d.ts +3 -0
- package/dist/tools/package/remove-status.js +12 -0
- package/dist/tools/package/remove-status.js.map +1 -0
- package/dist/tools/package/remove.js +3 -3
- package/dist/tools/package/remove.js.map +1 -1
- package/dist/tools/package/resolve.js +3 -3
- package/dist/tools/package/resolve.js.map +1 -1
- package/dist/tools/package/restore.js +2 -2
- package/dist/tools/package/restore.js.map +1 -1
- package/dist/tools/package/scoped-registry-add.js.map +1 -1
- package/dist/tools/status/support.d.ts +13 -0
- package/dist/tools/status/support.js +28 -0
- package/dist/tools/status/support.js.map +1 -0
- package/dist/tools/test/cancel.js +2 -2
- package/dist/tools/test/cancel.js.map +1 -1
- package/dist/tools/test/run-status.d.ts +3 -0
- package/dist/tools/test/run-status.js +12 -0
- package/dist/tools/test/run-status.js.map +1 -0
- package/dist/tools/test/run.js +7 -4
- package/dist/tools/test/run.js.map +1 -1
- package/dist/tools/tools/group-summaries.js +10 -14
- package/dist/tools/tools/group-summaries.js.map +1 -1
- package/docs/architecture.md +4 -4
- package/docs/availability-differences.md +4 -4
- package/docs/command-execution.md +4 -3
- package/docs/error-codes.md +13 -5
- package/docs/extensions.md +1 -7
- package/docs/risk-and-side-effects.md +4 -3
- package/docs/safety-boundaries.md +3 -1
- package/docs/target-and-instance.md +1 -1
- package/docs/tool-discovery.md +17 -10
- package/docs/tool-execution.md +18 -7
- package/extensions/cinemachine/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/hdrp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/probuilder/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/urp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/vfx-graph/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/package.json +2 -4
- package/skills/unitycli/SKILL.md +11 -2
- package/skills/unitycli/manifest.json +1 -1
- package/skills/unitycli/references/operation-protocol.md +3 -3
- package/unitypkg/Editor/AssemblyInfo.cs +5 -0
- package/unitypkg/Editor/Bridge/BridgeCommandRegistry.cs +49 -14
- package/unitypkg/Editor/Bridge/BridgeHttpServer.cs +9 -35
- package/unitypkg/Editor/Bridge/BridgeQueueState.cs +672 -0
- package/unitypkg/Editor/Bridge/BridgeWorkQueue.cs +970 -120
- package/unitypkg/Editor/BridgeStartupStateMachine.cs +59 -1
- package/unitypkg/Editor/Commands/ProjectToolCommands.cs +4 -0
- package/unitypkg/Editor/Commands/RuntimeToolCommands.cs +3 -0
- package/unitypkg/Editor/Generated/UnityCliToolCompletionRegistry.g.cs +379 -14
- package/unitypkg/Editor/Infrastructure/CodeExecSupport.cs +28 -13
- package/unitypkg/Editor/Infrastructure/RegistryOwnershipResolver.cs +132 -105
- package/unitypkg/Editor/Infrastructure/UnityCliActiveOperation.cs +138 -29
- package/unitypkg/Editor/Infrastructure/UnityCliAdmission.cs +1856 -237
- package/unitypkg/Editor/Infrastructure/UnityCliDoctorDiagnostics.cs +220 -0
- package/unitypkg/Editor/Infrastructure/UnityCliDurableStatusCoordinator.cs +118 -0
- package/unitypkg/Editor/Infrastructure/UnityCliEditorStateSnapshot.cs +2 -1
- package/unitypkg/Editor/Infrastructure/UnityCliHierarchyPager.cs +203 -0
- package/unitypkg/Editor/Infrastructure/UnityCliInstanceCleanup.cs +2 -1
- package/unitypkg/Editor/Infrastructure/UnityCliInstanceRegistry.cs +201 -63
- package/unitypkg/Editor/Infrastructure/UnityCliJson.cs +2 -3
- package/unitypkg/Editor/Infrastructure/UnityCliLiveBuildCoordinator.cs +289 -46
- package/unitypkg/Editor/Infrastructure/UnityCliLiveRefreshCoordinator.cs +87 -53
- package/unitypkg/Editor/Infrastructure/UnityCliNavMeshBakeCoordinator.cs +4 -4
- package/unitypkg/Editor/Infrastructure/UnityCliObjectRef.cs +128 -25
- package/unitypkg/Editor/Infrastructure/UnityCliObjectSerializer.cs +435 -327
- package/unitypkg/Editor/Infrastructure/UnityCliOcclusionBakeCoordinator.cs +4 -4
- package/unitypkg/Editor/Infrastructure/UnityCliOperationCoordinator.cs +351 -53
- package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveCoordinator.cs +118 -18
- package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveState.cs +20 -1
- package/unitypkg/Editor/Infrastructure/UnityCliReadGeneration.cs +97 -0
- package/unitypkg/Editor/Infrastructure/UnityCliReflection.cs +644 -133
- package/unitypkg/Editor/Infrastructure/UnityCliReloadOperation.cs +128 -41
- package/unitypkg/Editor/Infrastructure/UnityCliRuntimeExecutor.cs +14 -84
- package/unitypkg/Editor/Infrastructure/UnityCliSerializer.cs +220 -0
- package/unitypkg/Editor/Infrastructure/UnityCliSessionMutationLease.cs +69 -29
- package/unitypkg/Editor/Infrastructure/UnityCliTestRunCoordinator.cs +440 -54
- package/unitypkg/Editor/Infrastructure/UnityCliWaiter.cs +128 -35
- package/unitypkg/Editor/ProjectTools/IUnityCliTool.cs +9 -1
- package/unitypkg/Editor/ProjectTools/OfficialAttributeToolRegistry.cs +32 -31
- package/unitypkg/Editor/ProjectTools/ProjectToolRegistry.cs +607 -458
- package/unitypkg/Editor/ProjectTools/ProjectToolSchemaValidator.cs +35 -7
- package/unitypkg/Editor/ProjectTools/RegisteredTool.cs +501 -60
- package/unitypkg/Editor/ProjectTools/UnityCliProjectToolContext.cs +21 -0
- package/unitypkg/Editor/ProjectTools/UnityCliSchemaDeriver.cs +36 -7
- package/unitypkg/Editor/ProjectTools/UnityCliToolName.cs +30 -0
- package/unitypkg/Editor/Properties/AssemblyInfo.cs +3 -0
- package/unitypkg/Editor/Tools/asset/get-data.cs +16 -7
- package/unitypkg/Editor/Tools/build/BuildSceneStateTool.cs +23 -3
- package/unitypkg/Editor/Tools/build/BuildToolDtos.cs +2 -1
- package/unitypkg/Editor/Tools/build/scene/add.cs +6 -3
- package/unitypkg/Editor/Tools/build/scene/disable.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/enable.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/list.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/remove.cs +13 -3
- package/unitypkg/Editor/Tools/camera/CameraToolSupport.cs +38 -38
- package/unitypkg/Editor/Tools/camera/multiview.cs +13 -6
- package/unitypkg/Editor/Tools/camera/screenshot.cs +14 -7
- package/unitypkg/Editor/Tools/component/get.cs +16 -9
- package/unitypkg/Editor/Tools/component/modify.cs +6 -4
- package/unitypkg/Editor/Tools/console/clear.cs +7 -6
- package/unitypkg/Editor/Tools/console/get.cs +48 -16
- package/unitypkg/Editor/Tools/editor/EditorToolSupport.cs +143 -28
- package/unitypkg/Editor/Tools/editor/menu-items.cs +1 -1
- package/unitypkg/Editor/Tools/editor/play.cs +2 -11
- package/unitypkg/Editor/Tools/editor/selection.cs +1 -1
- package/unitypkg/Editor/Tools/editor/stop.cs +2 -11
- package/unitypkg/Editor/Tools/editor/windows.cs +1 -1
- package/unitypkg/Editor/Tools/go/GameObjectToolSupport.cs +54 -4
- package/unitypkg/Editor/Tools/go/delete.cs +1 -1
- package/unitypkg/Editor/Tools/go/find.cs +167 -70
- package/unitypkg/Editor/Tools/graphics/GraphicsToolSupport.cs +25 -0
- package/unitypkg/Editor/Tools/graphics/light-probe-group.cs +9 -3
- package/unitypkg/Editor/Tools/graphics/pipeline-info.cs +1 -1
- package/unitypkg/Editor/Tools/graphics/pipeline-settings.cs +1 -1
- package/unitypkg/Editor/Tools/graphics/quality.cs +2 -2
- package/unitypkg/Editor/Tools/graphics/reflection-probe.cs +3 -3
- package/unitypkg/Editor/Tools/graphics/stats.cs +1 -1
- package/unitypkg/Editor/Tools/object/ObjectToolSupport.cs +4 -4
- package/unitypkg/Editor/Tools/object/get-data.cs +9 -7
- package/unitypkg/Editor/Tools/object/modify.cs +7 -5
- package/unitypkg/Editor/Tools/physics/raycast.cs +24 -6
- package/unitypkg/Editor/Tools/prefab/stage.cs +1 -1
- package/unitypkg/Editor/Tools/profiler/ProfilerFrameDebuggerSupport.cs +94 -21
- package/unitypkg/Editor/Tools/profiler/ProfilerMemorySnapshotSupport.cs +397 -10
- package/unitypkg/Editor/Tools/profiler/ProfilerToolSupport.cs +18 -4
- package/unitypkg/Editor/Tools/profiler/frame-debugger/enable.cs +1 -1
- package/unitypkg/Editor/Tools/profiler/frame-debugger/events.cs +88 -87
- package/unitypkg/Editor/Tools/profiler/hierarchy.cs +278 -112
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/compare.cs +9 -5
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/list.cs +37 -35
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/take.cs +99 -97
- package/unitypkg/Editor/Tools/project/info.cs +1 -1
- package/unitypkg/Editor/Tools/project/layers.cs +1 -1
- package/unitypkg/Editor/Tools/project/tags.cs +1 -1
- package/unitypkg/Editor/Tools/reflection/method/call.cs +9 -7
- package/unitypkg/Editor/Tools/reflection/method/find.cs +27 -37
- package/unitypkg/Editor/Tools/reflection/type/schema.cs +24 -28
- package/unitypkg/Editor/Tools/scene/gameobject/component.cs +8 -5
- package/unitypkg/Editor/Tools/scene/gameobject/components.cs +10 -7
- package/unitypkg/Editor/Tools/scene/gameobject-support.cs +104 -8
- package/unitypkg/Editor/Tools/scene/gameobject.cs +37 -16
- package/unitypkg/Editor/Tools/scene/hierarchy.cs +146 -142
- package/unitypkg/Editor/Tools/screenshot/EditorElementCaptureToolSupport.cs +77 -25
- package/unitypkg/Editor/Tools/screenshot/ScreenshotToolSupport.cs +315 -95
- package/unitypkg/Editor/Tools/screenshot/editor-element.cs +7 -5
- package/unitypkg/Editor/Tools/screenshot/game-view.cs +35 -21
- package/unitypkg/Editor/Tools/screenshot/isolated-object.cs +29 -23
- package/unitypkg/Editor/Tools/screenshot/orbit.cs +37 -25
- package/unitypkg/Editor/Tools/screenshot/scene-view.cs +25 -18
- package/unitypkg/Editor/Tools/screenshot/screen.cs +177 -17
- package/unitypkg/Editor/Tools/screenshot/surround.cs +83 -79
- package/unitypkg/Editor/Tools/ui/render-preview.cs +16 -11
- package/unitypkg/Editor/UnityCliBridge.cs +97 -34
- package/unitypkg/Runtime/Infrastructure/UnityCliRuntimeBridge.cs +753 -122
- package/unitypkg/Runtime/Properties/AssemblyInfo.cs +5 -0
- package/unitypkg/Runtime/UnityCli.Runtime.asmdef +1 -1
- package/unitypkg/Shared/AssemblyInfo.cs +4 -0
- package/unitypkg/Shared/UnityCliAdmissionPool.cs +265 -75
- package/unitypkg/Shared/UnityCliBridgeQueuePolicy.cs +410 -0
- package/unitypkg/Shared/UnityCliBridgeWorkItemState.cs +47 -0
- package/unitypkg/Shared/UnityCliExceptionProjection.cs +151 -0
- package/unitypkg/Shared/UnityCliQueuePublication.cs +30 -0
- package/unitypkg/Shared/UnityCliRequestBudget.cs +352 -0
- package/unitypkg/Shared/UnityCliRuntimeRequestPublication.cs +107 -0
- package/unitypkg/Tests/Editor/UnityCli.Editor.Tests.asmdef +2 -2
- package/unitypkg/Tests/Editor/UnityCliAdmissionCoordinatorIntegrationTests.cs +1329 -0
- package/unitypkg/Tests/Editor/UnityCliAdmissionPoolTests.cs +311 -114
- package/unitypkg/Tests/Editor/UnityCliAdmissionRepairStateTests.cs +94 -0
- package/unitypkg/Tests/Editor/UnityCliBridgeAdmissionIntegrationTests.cs +1229 -0
- package/unitypkg/Tests/Editor/UnityCliBridgeQueuePolicyTests.cs +412 -0
- package/unitypkg/Tests/Editor/UnityCliContinuationIntegrationTests.cs +292 -0
- package/unitypkg/Tests/Editor/UnityCliDiagnosticBoundaryTests.cs +120 -0
- package/unitypkg/Tests/Editor/UnityCliDurableStatusTests.cs +84 -0
- package/unitypkg/Tests/Editor/UnityCliExceptionProjectionTests.cs +72 -0
- package/unitypkg/Tests/Editor/UnityCliInstancePublicationRetryTests.cs +180 -97
- package/unitypkg/Tests/Editor/UnityCliMemoryReflectionIntegrationTests.cs +434 -0
- package/unitypkg/Tests/Editor/UnityCliRequestBudgetTests.cs +615 -0
- package/unitypkg/Tests/Editor/UnityCliRuntimeBridgeIntegrationTests.cs +520 -0
- package/unitypkg/Tests/Editor/UnityCliToolCatalogTests.cs +562 -0
- package/unitypkg/Tests/Runtime/UnityCli.Runtime.Tests.asmdef +23 -0
- package/unitypkg/Tests/Runtime/UnityCliRuntimeCatalogValidationTests.cs +29 -0
- package/unitypkg/package.json +1 -1
- package/contracts/static-capability-catalog.json +0 -48226
- package/dist/bridge/domains/diagnose.d.ts +0 -2
- package/dist/bridge/domains/diagnose.js +0 -11
- package/dist/bridge/domains/diagnose.js.map +0 -1
- package/dist/bridge/domains/extension.d.ts +0 -8
- package/dist/bridge/domains/extension.js +0 -20
- package/dist/bridge/domains/extension.js.map +0 -1
- package/dist/capabilities.d.ts +0 -5
- package/dist/capabilities.js +0 -84
- package/dist/capabilities.js.map +0 -1
- package/dist/static-capability-catalog.d.ts +0 -13
- package/dist/static-capability-catalog.js +0 -41
- package/dist/static-capability-catalog.js.map +0 -1
- package/dist/tools/diagnose/capabilities.d.ts +0 -13
- package/dist/tools/diagnose/capabilities.js +0 -34
- package/dist/tools/diagnose/capabilities.js.map +0 -1
- package/dist/tools/package/info.d.ts +0 -19
- package/dist/tools/package/info.js +0 -27
- package/dist/tools/package/info.js.map +0 -1
- package/dist/tools/package/list.d.ts +0 -27
- package/dist/tools/package/list.js +0 -21
- package/dist/tools/package/list.js.map +0 -1
- package/dist/tools/package/registry-get.d.ts +0 -10
- package/dist/tools/package/registry-get.js +0 -22
- package/dist/tools/package/registry-get.js.map +0 -1
- package/dist/tools/package/scoped-registry-list.d.ts +0 -14
- package/dist/tools/package/scoped-registry-list.js +0 -22
- package/dist/tools/package/scoped-registry-list.js.map +0 -1
- package/dist/tools/package/search.d.ts +0 -17
- package/dist/tools/package/search.js +0 -39
- package/dist/tools/package/search.js.map +0 -1
- package/dist/tools/package/status.d.ts +0 -21
- package/dist/tools/package/status.js +0 -37
- package/dist/tools/package/status.js.map +0 -1
- package/dist/tools/tools/describe.d.ts +0 -27
- package/dist/tools/tools/describe.js +0 -35
- package/dist/tools/tools/describe.js.map +0 -1
- package/dist/tools/tools/group-list.d.ts +0 -16
- package/dist/tools/tools/group-list.js +0 -38
- package/dist/tools/tools/group-list.js.map +0 -1
- package/dist/tools/tools/group.d.ts +0 -13
- package/dist/tools/tools/group.js +0 -34
- package/dist/tools/tools/group.js.map +0 -1
- package/dist/tools/tools/pagination.d.ts +0 -17
- package/dist/tools/tools/pagination.js +0 -28
- package/dist/tools/tools/pagination.js.map +0 -1
- package/dist/tools/tools/search.d.ts +0 -15
- package/dist/tools/tools/search.js +0 -42
- package/dist/tools/tools/search.js.map +0 -1
- package/unitypkg/Editor/Tools/diagnose/preflight.cs +0 -269
- package/unitypkg/Editor/Tools/editor/console.cs +0 -26
- package/unitypkg/Editor/Tools/extension/status.cs +0 -87
- package/unitypkg/Editor/Tools/go/inspect.cs +0 -49
- package/unitypkg/Editor/Tools/graphics/pipeline-quality.cs +0 -24
- package/unitypkg/Editor/Tools/graphics/probe-positions.cs +0 -58
- package/unitypkg/Editor/Tools/graphics/settings.cs +0 -104
- package/unitypkg/Editor/Tools/graphics/stats-counters.cs +0 -28
- package/unitypkg/Editor/Tools/graphics/stats-memory.cs +0 -21
- package/unitypkg/Editor/Tools/instances/list.cs +0 -71
- package/unitypkg/Editor/Tools/physics/raycast-all.cs +0 -67
- package/unitypkg/Editor/Tools/scene/build-settings.cs +0 -69
- package/unitypkg/Editor/Tools/scene/data.cs +0 -125
- package/unitypkg/Editor/Tools/tests/list.cs +0 -98
|
@@ -1,182 +1,348 @@
|
|
|
1
1
|
#if UNITY_EDITOR
|
|
2
2
|
using System;
|
|
3
3
|
using System.Collections.Generic;
|
|
4
|
+
using System.Globalization;
|
|
4
5
|
using System.Reflection;
|
|
5
6
|
|
|
6
7
|
namespace UnityCli
|
|
7
8
|
{
|
|
9
|
+
/// <summary>profiler.hierarchy — 使用 RawFrameDataView 扁平先序索引做全局节点续页。</summary>
|
|
8
10
|
public class ProfilerHierarchyTool : IUnityCliTool<ProfilerHierarchyTool.Request, ProfilerHierarchyTool.Result>
|
|
9
11
|
{
|
|
10
12
|
public sealed class Request
|
|
11
13
|
{
|
|
12
|
-
public int? Frame { get; set; }
|
|
13
|
-
public int? Thread { get; set; }
|
|
14
|
-
public int?
|
|
15
|
-
public int? Depth { get; set; }
|
|
14
|
+
[UnityCliRange(-1L, int.MaxValue)] public int? Frame { get; set; }
|
|
15
|
+
[UnityCliRange(0L, 1024L)] public int? Thread { get; set; }
|
|
16
|
+
[UnityCliRange(1L, 500L)] public int? PageSize { get; set; }
|
|
17
|
+
[UnityCliRange(0L, 32L)] public int? Depth { get; set; }
|
|
18
|
+
public string Cursor { get; set; }
|
|
19
|
+
public UnityCliReadBudgetInput Budget { get; set; }
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
public sealed class Result
|
|
19
23
|
{
|
|
20
|
-
public
|
|
24
|
+
public long Frame { get; set; }
|
|
25
|
+
public long Thread { get; set; }
|
|
26
|
+
[UnityCliItemsRange(0, 500)] public List<HierarchyItem> Items { get; set; }
|
|
27
|
+
public PageInfo PageInfo { get; set; }
|
|
28
|
+
public UnityCliRequestBudgetUsage Budget { get; set; }
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
public sealed class HierarchyItem
|
|
24
32
|
{
|
|
25
33
|
public long Id { get; set; }
|
|
34
|
+
public long ParentId { get; set; }
|
|
26
35
|
public string Name { get; set; }
|
|
27
36
|
public long Depth { get; set; }
|
|
28
37
|
public double Ms { get; set; }
|
|
29
|
-
public long SiblingCount { get; set; }
|
|
30
38
|
public long ChildCount { get; set; }
|
|
31
39
|
public bool ChildrenTruncated { get; set; }
|
|
32
|
-
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public sealed class PageInfo
|
|
43
|
+
{
|
|
44
|
+
public long PageSize { get; set; }
|
|
45
|
+
public long ReturnedCount { get; set; }
|
|
46
|
+
public string Cursor { get; set; }
|
|
47
|
+
public string NextCursor { get; set; }
|
|
48
|
+
public bool Complete { get; set; }
|
|
49
|
+
public bool Truncated { get; set; }
|
|
50
|
+
public string Generation { get; set; }
|
|
33
51
|
}
|
|
34
52
|
|
|
35
53
|
public ToolDescriptor Describe() => new()
|
|
36
54
|
{
|
|
37
55
|
Name = "profiler.hierarchy",
|
|
38
|
-
Summary = "
|
|
39
|
-
Description = "Read the
|
|
40
|
-
Group = "profiler",DestructiveHint = false, Target = "editor", PlayModeSupport = "supported",
|
|
56
|
+
Summary = "Page one profiler frame/thread call hierarchy with a global raw-node budget and stable continuation.",
|
|
57
|
+
Description = "Read a flat preorder page from Unity RawFrameDataView without copying the full hierarchy. frame defaults to the latest recorded frame, thread is 0..1024, pageSize is 1..500 (default 50), and depth is 0..32 (default 5). The DFS stack is carried by opaque nextCursor, so later pages resume in O(depth). All nodes share request scan/node/reflection/time/UTF-8 budgets; defaults are 10000/4096/4096/250 ms/1 MiB and public maxima are 100000/20000/20000/2000 ms/8 MiB. complete=false identifies truncation. Read-only in Edit and Play Mode.",
|
|
58
|
+
Group = "profiler", DestructiveHint = false, Target = "editor", PlayModeSupport = "supported",
|
|
41
59
|
DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000,
|
|
42
|
-
Examples = new[]
|
|
43
|
-
{
|
|
44
|
-
new ToolExample { Description = "Latest frame main-thread top markers", Input = new Request { Top = 20, Depth = 5 } },
|
|
45
|
-
new ToolExample { Description = "Latest frame on the main thread", Input = new Request { Frame = -1, Thread = 0 } }
|
|
46
|
-
}
|
|
60
|
+
Examples = new[] { new ToolExample { Description = "Read latest-frame nodes", Input = new Request { PageSize = 50, Depth = 5 } } }
|
|
47
61
|
};
|
|
48
62
|
|
|
49
63
|
public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
|
|
50
64
|
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
throw new UnityCliBridge.BridgeCommandException("E_PROFILER_HIERARCHY_UNAVAILABLE",
|
|
55
|
-
"UnityEditorInternal.ProfilerDriver is not available; hierarchy requires the Editor Profiler.",
|
|
56
|
-
"Capture Profiler data in the selected Live Editor, then retry.");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// 省略 frame 时读取最新已采集帧
|
|
65
|
+
request = request ?? new Request();
|
|
66
|
+
var budget = ctx.UseReadBudget(request.Budget);
|
|
67
|
+
if (!request.Frame.HasValue && (!budget.TryConsumeReflectionCall() || !budget.TryConsumeGetter())) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
60
68
|
var frame = request.Frame ?? ProfilerToolSupport.ProfilerDriverIntProperty("lastFrameIndex", -1);
|
|
61
69
|
var threadIndex = request.Thread ?? 0;
|
|
62
|
-
var
|
|
63
|
-
var maxDepth =
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
?? ProfilerToolSupport.FindType("UnityEditorInternal.HierarchyFrameDataView")
|
|
67
|
-
?? ProfilerToolSupport.FindType("UnityEngine.Profiling.HierarchyFrameDataView");
|
|
68
|
-
if (hierarchyViewType == null)
|
|
70
|
+
var pageSize = request.PageSize ?? 50;
|
|
71
|
+
var maxDepth = request.Depth ?? 5;
|
|
72
|
+
var accessor = RawHierarchyAccessor.Open(frame, threadIndex, budget);
|
|
73
|
+
try
|
|
69
74
|
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
var generation = UnityCliContinuationToken.Fingerprint(UnityCliReadGeneration.Session("profiler.hierarchy") + "\0" + accessor.CaptureIdentity);
|
|
76
|
+
var stack = string.IsNullOrEmpty(request.Cursor)
|
|
77
|
+
? new List<TraversalFrame> { new TraversalFrame { ParentId = 0, NextSample = 1, Depth = 0 } }
|
|
78
|
+
: ParseCursor(request.Cursor, generation, accessor, maxDepth, budget);
|
|
79
|
+
var items = new List<HierarchyItem>();
|
|
80
|
+
while (stack.Count > 0 && items.Count < pageSize)
|
|
81
|
+
{
|
|
82
|
+
var before = EncodeStack(stack);
|
|
83
|
+
if (!TryNext(accessor, stack, maxDepth, budget, out var item))
|
|
84
|
+
{
|
|
85
|
+
if (budget.IsExhausted) stack = DecodeStack(before);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
items.Add(item);
|
|
89
|
+
}
|
|
90
|
+
if (items.Count == 0 && stack.Count > 0) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension ?? "scannedRecords");
|
|
91
|
+
var nextCursor = stack.Count == 0 ? null : UnityCliContinuationToken.Create("profiler.hierarchy", generation, EncodeStack(stack));
|
|
92
|
+
return new System.Threading.Tasks.ValueTask<Result>(new Result
|
|
93
|
+
{
|
|
94
|
+
Frame = frame,
|
|
95
|
+
Thread = threadIndex,
|
|
96
|
+
Items = items,
|
|
97
|
+
PageInfo = new PageInfo
|
|
98
|
+
{
|
|
99
|
+
PageSize = pageSize, ReturnedCount = items.Count, Cursor = request.Cursor, NextCursor = nextCursor,
|
|
100
|
+
Complete = nextCursor == null, Truncated = nextCursor != null, Generation = generation
|
|
101
|
+
},
|
|
102
|
+
Budget = budget.Usage()
|
|
103
|
+
});
|
|
73
104
|
}
|
|
105
|
+
finally { accessor.Dispose(); }
|
|
106
|
+
}
|
|
74
107
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (getHierarchy == null)
|
|
81
|
-
{
|
|
82
|
-
getHierarchy = driverType.GetMethod("GetHierarchyFrameDataView", new[] { typeof(int), typeof(int) });
|
|
83
|
-
}
|
|
84
|
-
if (getHierarchy == null)
|
|
108
|
+
/// <summary>扁平先序数组中,当前子树后的首个样本就是下一兄弟;栈只保留每层的下一个样本。</summary>
|
|
109
|
+
internal static bool TryNext(RawHierarchyAccessor accessor, List<TraversalFrame> stack, int maxDepth, UnityCliRequestBudget budget, out HierarchyItem item)
|
|
110
|
+
{
|
|
111
|
+
item = null;
|
|
112
|
+
while (stack.Count > 0)
|
|
85
113
|
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
114
|
+
var frame = stack[stack.Count - 1];
|
|
115
|
+
var parentEnd = accessor.SubtreeEndExclusive(frame.ParentId, budget);
|
|
116
|
+
if (budget.IsExhausted) return false;
|
|
117
|
+
if (frame.NextSample >= parentEnd) { stack.RemoveAt(stack.Count - 1); continue; }
|
|
118
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeNode()) return false;
|
|
119
|
+
var child = frame.NextSample;
|
|
120
|
+
var childEnd = accessor.SubtreeEndExclusive(child, budget);
|
|
121
|
+
if (budget.IsExhausted) return false;
|
|
122
|
+
var grandChildren = accessor.ChildCount(child, budget);
|
|
123
|
+
if (budget.IsExhausted) return false;
|
|
124
|
+
if ((grandChildren > 0) != (childEnd > child + 1)) throw RawHierarchyAccessor.InvalidPreorder();
|
|
125
|
+
var name = accessor.Name(child, budget) ?? "(unknown)";
|
|
126
|
+
var milliseconds = accessor.Milliseconds(child, budget);
|
|
127
|
+
if (budget.IsExhausted || !budget.TryReserveSerializedUtf8(name)) return false;
|
|
128
|
+
frame.NextSample = childEnd;
|
|
129
|
+
item = new HierarchyItem
|
|
130
|
+
{
|
|
131
|
+
Id = child, ParentId = frame.ParentId, Name = name, Depth = frame.Depth,
|
|
132
|
+
Ms = milliseconds, ChildCount = grandChildren,
|
|
133
|
+
ChildrenTruncated = grandChildren > 0 && frame.Depth >= maxDepth
|
|
134
|
+
};
|
|
135
|
+
if (grandChildren > 0 && frame.Depth < maxDepth)
|
|
136
|
+
stack.Add(new TraversalFrame { ParentId = child, NextSample = child + 1, Depth = frame.Depth + 1 });
|
|
137
|
+
return true;
|
|
89
138
|
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
90
141
|
|
|
91
|
-
|
|
142
|
+
private static List<TraversalFrame> ParseCursor(string cursor, string generation, RawHierarchyAccessor accessor, int maxDepth, UnityCliRequestBudget budget)
|
|
143
|
+
{
|
|
144
|
+
string position;
|
|
145
|
+
if (!UnityCliContinuationToken.TryParse(cursor, "profiler.hierarchy", generation, out position)) throw Stale();
|
|
92
146
|
try
|
|
93
147
|
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
148
|
+
var stack = DecodeStack(position);
|
|
149
|
+
if (stack.Count == 0 || stack.Count > maxDepth + 1) throw Stale();
|
|
150
|
+
for (var index = 0; index < stack.Count; index++)
|
|
151
|
+
{
|
|
152
|
+
var frame = stack[index];
|
|
153
|
+
if (frame.Depth != index || frame.ParentId < 0 || frame.ParentId >= accessor.SampleCount) throw Stale();
|
|
154
|
+
var parentEnd = accessor.SubtreeEndExclusive(frame.ParentId, budget);
|
|
155
|
+
if (budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
156
|
+
if (frame.NextSample < frame.ParentId + 1 || frame.NextSample > parentEnd) throw Stale();
|
|
157
|
+
if (index + 1 < stack.Count)
|
|
158
|
+
{
|
|
159
|
+
var activeChild = stack[index + 1].ParentId;
|
|
160
|
+
if (activeChild <= frame.ParentId || activeChild >= parentEnd) throw Stale();
|
|
161
|
+
var activeChildEnd = accessor.SubtreeEndExclusive(activeChild, budget);
|
|
162
|
+
if (budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
163
|
+
if (activeChildEnd != frame.NextSample) throw Stale();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return stack;
|
|
97
167
|
}
|
|
98
|
-
catch (
|
|
168
|
+
catch (UnityCliRequestBudgetExceededException) { throw; }
|
|
169
|
+
catch (UnityCliBridge.BridgeCommandException) { throw; }
|
|
170
|
+
catch { throw Stale(); }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private static string EncodeStack(List<TraversalFrame> stack)
|
|
174
|
+
{
|
|
175
|
+
var values = new List<string>();
|
|
176
|
+
foreach (var frame in stack) values.Add(frame.ParentId.ToString(CultureInfo.InvariantCulture) + "," + frame.NextSample.ToString(CultureInfo.InvariantCulture) + "," + frame.Depth.ToString(CultureInfo.InvariantCulture));
|
|
177
|
+
return string.Join(";", values.ToArray());
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private static List<TraversalFrame> DecodeStack(string value)
|
|
181
|
+
{
|
|
182
|
+
var result = new List<TraversalFrame>();
|
|
183
|
+
if (string.IsNullOrEmpty(value)) return result;
|
|
184
|
+
foreach (var token in value.Split(';'))
|
|
99
185
|
{
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
186
|
+
var parts = token.Split(',');
|
|
187
|
+
if (parts.Length != 3) throw new FormatException();
|
|
188
|
+
result.Add(new TraversalFrame
|
|
189
|
+
{
|
|
190
|
+
ParentId = int.Parse(parts[0], CultureInfo.InvariantCulture),
|
|
191
|
+
NextSample = int.Parse(parts[1], CultureInfo.InvariantCulture),
|
|
192
|
+
Depth = int.Parse(parts[2], CultureInfo.InvariantCulture)
|
|
193
|
+
});
|
|
104
194
|
}
|
|
105
|
-
if (
|
|
195
|
+
if (result.Count > 33) throw new FormatException();
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private static UnityCliBridge.BridgeCommandException Stale()
|
|
200
|
+
{
|
|
201
|
+
return new UnityCliBridge.BridgeCommandException("E_CONTINUATION_STALE", "The profiler hierarchy continuation does not match the same frame/thread generation.", "Start a new profiler.hierarchy read without cursor.");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
internal sealed class TraversalFrame { internal int ParentId; internal int NextSample; internal int Depth; }
|
|
205
|
+
|
|
206
|
+
internal sealed class RawHierarchyAccessor : IDisposable
|
|
207
|
+
{
|
|
208
|
+
private readonly object view;
|
|
209
|
+
private readonly PropertyInfo validProperty;
|
|
210
|
+
private readonly int sampleCount;
|
|
211
|
+
private readonly MethodInfo childCountMethod;
|
|
212
|
+
private readonly MethodInfo recursiveChildCountMethod;
|
|
213
|
+
private readonly MethodInfo nameMethod;
|
|
214
|
+
private readonly MethodInfo millisecondsMethod;
|
|
215
|
+
private readonly string captureIdentity;
|
|
216
|
+
|
|
217
|
+
private RawHierarchyAccessor(object view, Type type, UnityCliRequestBudget budget)
|
|
106
218
|
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
219
|
+
this.view = view;
|
|
220
|
+
validProperty = ReflectProperty(type, "valid", budget);
|
|
221
|
+
var sampleCountProperty = ReflectProperty(type, "sampleCount", budget);
|
|
222
|
+
var frameIndexProperty = ReflectProperty(type, "frameIndex", budget);
|
|
223
|
+
var threadIndexProperty = ReflectProperty(type, "threadIndex", budget);
|
|
224
|
+
var frameStartTimeProperty = ReflectProperty(type, "frameStartTimeMs", budget);
|
|
225
|
+
var frameTimeProperty = ReflectProperty(type, "frameTimeMs", budget);
|
|
226
|
+
childCountMethod = ReflectMethod(type, "GetSampleChildrenCount", new[] { typeof(int) }, budget);
|
|
227
|
+
recursiveChildCountMethod = ReflectMethod(type, "GetSampleChildrenCountRecursive", new[] { typeof(int) }, budget);
|
|
228
|
+
nameMethod = ReflectMethod(type, "GetSampleName", new[] { typeof(int) }, budget);
|
|
229
|
+
millisecondsMethod = ReflectMethod(type, "GetSampleTimeMs", new[] { typeof(int) }, budget);
|
|
230
|
+
if (sampleCountProperty == null || frameIndexProperty == null || threadIndexProperty == null || frameStartTimeProperty == null || frameTimeProperty == null
|
|
231
|
+
|| childCountMethod == null || recursiveChildCountMethod == null || nameMethod == null || millisecondsMethod == null)
|
|
232
|
+
throw Unavailable("RawFrameDataView capture identity or preorder hierarchy members are unavailable.");
|
|
233
|
+
if (validProperty != null && !ReadBool(validProperty, view, budget)) throw NoData();
|
|
234
|
+
var identityValues = new object[5];
|
|
235
|
+
var identityProperties = new[] { frameIndexProperty, threadIndexProperty, frameStartTimeProperty, frameTimeProperty, sampleCountProperty };
|
|
236
|
+
for (var index = 0; index < identityProperties.Length; index++)
|
|
237
|
+
{
|
|
238
|
+
if (!budget.TryConsumeGetter() || !budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
239
|
+
identityValues[index] = identityProperties[index].GetValue(view, null);
|
|
240
|
+
}
|
|
241
|
+
sampleCount = Convert.ToInt32(identityValues[4], CultureInfo.InvariantCulture);
|
|
242
|
+
if (sampleCount <= 0) throw NoData();
|
|
243
|
+
captureIdentity = string.Join("\0", Array.ConvertAll(identityValues, value => Convert.ToString(value, CultureInfo.InvariantCulture)));
|
|
244
|
+
if (!budget.TryReserveSerializedUtf8(captureIdentity)) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
110
245
|
}
|
|
111
246
|
|
|
112
|
-
|
|
113
|
-
|
|
247
|
+
internal int SampleCount { get { return sampleCount; } }
|
|
248
|
+
internal string CaptureIdentity { get { return captureIdentity; } }
|
|
249
|
+
|
|
250
|
+
internal static RawHierarchyAccessor Open(int frame, int thread, UnityCliRequestBudget budget)
|
|
114
251
|
{
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
252
|
+
var driver = UnityCliBridge.TypeSchemaGenerator.ResolveType("UnityEditorInternal.ProfilerDriver", budget);
|
|
253
|
+
if (driver == null) throw Unavailable("ProfilerDriver is unavailable.");
|
|
254
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
255
|
+
var method = driver.GetMethod("GetRawFrameDataView", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new[] { typeof(int), typeof(int) }, null);
|
|
256
|
+
if (method == null) throw Unavailable("ProfilerDriver.GetRawFrameDataView is unavailable.");
|
|
257
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
258
|
+
object view;
|
|
259
|
+
try { view = method.Invoke(null, new object[] { frame, thread }); }
|
|
260
|
+
catch (Exception exception) { throw Unavailable("Failed to open RawFrameDataView: " + exception.Message); }
|
|
261
|
+
return InitializeOwnedView(view, value => new RawHierarchyAccessor(value, value.GetType(), budget));
|
|
118
262
|
}
|
|
119
263
|
|
|
120
|
-
|
|
264
|
+
/// <summary>raw view 初始化成功才转移 ownership;成员绑定失败必须立即释放原 view。</summary>
|
|
265
|
+
internal static T InitializeOwnedView<T>(object view, Func<object, T> initialize)
|
|
121
266
|
{
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
267
|
+
if (view == null) throw NoData();
|
|
268
|
+
if (initialize == null) throw new ArgumentNullException("initialize");
|
|
269
|
+
try { return initialize(view); }
|
|
270
|
+
catch
|
|
271
|
+
{
|
|
272
|
+
(view as IDisposable)?.Dispose();
|
|
273
|
+
throw;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
131
276
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
277
|
+
internal static RawHierarchyAccessor InitializeForTests(object view, UnityCliRequestBudget budget)
|
|
278
|
+
{
|
|
279
|
+
return InitializeOwnedView(view, value => new RawHierarchyAccessor(value, value.GetType(), budget));
|
|
280
|
+
}
|
|
135
281
|
|
|
136
|
-
|
|
137
|
-
try { if (childrenMethod != null) childrenMethod.Invoke(view, new object[] { itemId, childIds }); }
|
|
138
|
-
catch { return result; }
|
|
282
|
+
internal int ChildCount(int sample, UnityCliRequestBudget budget) { return Convert.ToInt32(Invoke(childCountMethod, new object[] { sample }, budget), CultureInfo.InvariantCulture); }
|
|
139
283
|
|
|
140
|
-
|
|
141
|
-
|
|
284
|
+
/// <summary>Unity 的 raw samples 是先序扁平数组,递归后代数可直接确定子树右边界。</summary>
|
|
285
|
+
internal int SubtreeEndExclusive(int sample, UnityCliRequestBudget budget)
|
|
142
286
|
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
287
|
+
var recursiveChildren = Convert.ToInt32(Invoke(recursiveChildCountMethod, new object[] { sample }, budget), CultureInfo.InvariantCulture);
|
|
288
|
+
if (budget.IsExhausted) return sample + 1;
|
|
289
|
+
var end = (long)sample + recursiveChildren + 1L;
|
|
290
|
+
if (sample < 0 || sample >= sampleCount || recursiveChildren < 0 || end > sampleCount) throw InvalidPreorder();
|
|
291
|
+
return (int)end;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
internal string Name(int sample, UnityCliRequestBudget budget) { return Invoke(nameMethod, new object[] { sample }, budget) as string; }
|
|
295
|
+
internal double Milliseconds(int sample, UnityCliRequestBudget budget) { return Convert.ToDouble(Invoke(millisecondsMethod, new object[] { sample }, budget), CultureInfo.InvariantCulture); }
|
|
148
296
|
|
|
149
|
-
|
|
150
|
-
try { if (childrenMethod != null) childrenMethod.Invoke(view, new object[] { childId, grandChildren }); } catch { }
|
|
297
|
+
public void Dispose() { (view as IDisposable)?.Dispose(); }
|
|
151
298
|
|
|
152
|
-
|
|
299
|
+
private object Invoke(MethodInfo method, object[] args, UnityCliRequestBudget budget)
|
|
300
|
+
{
|
|
301
|
+
if (!budget.TryConsumeReflectionCall()) return null;
|
|
302
|
+
try { return method.Invoke(view, args); }
|
|
303
|
+
catch (TargetInvocationException exception)
|
|
153
304
|
{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
SiblingCount = childIds.Count,
|
|
159
|
-
ChildCount = grandChildren.Count,
|
|
160
|
-
ChildrenTruncated = grandChildren.Count > top || (grandChildren.Count > 0 && depth + 1 > maxDepth)
|
|
161
|
-
};
|
|
162
|
-
if (grandChildren.Count > 0 && depth + 1 <= maxDepth)
|
|
305
|
+
var inner = exception.InnerException ?? exception;
|
|
306
|
+
throw new UnityCliBridge.BridgeCommandException("E_PROFILER_HIERARCHY_READ_FAILED", "Raw profiler hierarchy read failed: " + inner.GetType().Name + ".", "Record a fresh frame and restart pagination.");
|
|
307
|
+
}
|
|
308
|
+
catch (Exception exception)
|
|
163
309
|
{
|
|
164
|
-
|
|
310
|
+
throw new UnityCliBridge.BridgeCommandException("E_PROFILER_HIERARCHY_READ_FAILED", "Raw profiler hierarchy read failed: " + exception.GetType().Name + ".", "Record a fresh frame and restart pagination.");
|
|
165
311
|
}
|
|
166
|
-
result.Add(item);
|
|
167
|
-
emitted++;
|
|
168
312
|
}
|
|
169
|
-
return result;
|
|
170
|
-
}
|
|
171
313
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
314
|
+
private static PropertyInfo ReflectProperty(Type type, string name, UnityCliRequestBudget budget)
|
|
315
|
+
{
|
|
316
|
+
if (!budget.TryConsumeReflectionCall()) return null;
|
|
317
|
+
return type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private static MethodInfo ReflectMethod(Type type, string name, Type[] parameters, UnityCliRequestBudget budget)
|
|
321
|
+
{
|
|
322
|
+
if (!budget.TryConsumeReflectionCall()) return null;
|
|
323
|
+
return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private static bool ReadBool(PropertyInfo property, object target, UnityCliRequestBudget budget)
|
|
327
|
+
{
|
|
328
|
+
if (!budget.TryConsumeGetter() || !budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
329
|
+
return Convert.ToBoolean(property.GetValue(target, null), CultureInfo.InvariantCulture);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
private static UnityCliBridge.BridgeCommandException Unavailable(string message)
|
|
333
|
+
{
|
|
334
|
+
return new UnityCliBridge.BridgeCommandException("E_PROFILER_HIERARCHY_UNAVAILABLE", message, "Use an Editor exposing RawFrameDataView and record profiler frames before retrying.");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
internal static UnityCliBridge.BridgeCommandException InvalidPreorder()
|
|
175
338
|
{
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
339
|
+
return new UnityCliBridge.BridgeCommandException("E_PROFILER_HIERARCHY_READ_FAILED", "Raw profiler hierarchy preorder ranges are inconsistent.", "Record a fresh frame and restart pagination.");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private static UnityCliBridge.BridgeCommandException NoData()
|
|
343
|
+
{
|
|
344
|
+
return new UnityCliBridge.BridgeCommandException("E_PROFILER_HIERARCHY_NO_DATA", "No raw hierarchy data is available for the requested frame/thread.", "Record profiler frames, then query a valid frame and thread.");
|
|
345
|
+
}
|
|
180
346
|
}
|
|
181
347
|
}
|
|
182
348
|
}
|
|
@@ -16,6 +16,7 @@ namespace UnityCli
|
|
|
16
16
|
{
|
|
17
17
|
[UnityCliRequired] public string SnapshotA { get; set; }
|
|
18
18
|
[UnityCliRequired] public string SnapshotB { get; set; }
|
|
19
|
+
public UnityCliReadBudgetInput Budget { get; set; }
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
public sealed class Result
|
|
@@ -30,7 +31,7 @@ namespace UnityCli
|
|
|
30
31
|
{
|
|
31
32
|
Name = "profiler.memory-snapshot.compare",
|
|
32
33
|
Summary = "Compare two .snap memory snapshots at file-level metadata (size delta, time delta).",
|
|
33
|
-
Description = "Compare two
|
|
34
|
+
Description = "Compare file metadata for two snapshot file names under Library/UnityCli/memory-snapshots. Arbitrary paths are rejected. Reads share the request node/getter/time/UTF-8 budget. For object-level diff, open both governed artifacts in the Memory Profiler window. Read-only in Edit and Play Mode.",
|
|
34
35
|
Group = "profiler",DestructiveHint = false, Target = "editor", PlayModeSupport = "supported",
|
|
35
36
|
DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000,
|
|
36
37
|
Examples = new[] { new ToolExample { Description = "Compare two snapshots", Input = new Request { SnapshotA = "snap1.snap", SnapshotB = "snap2.snap" } } }
|
|
@@ -38,14 +39,14 @@ namespace UnityCli
|
|
|
38
39
|
|
|
39
40
|
public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
|
|
40
41
|
{
|
|
41
|
-
|
|
42
|
-
var snapshotBPath = request.SnapshotB;
|
|
43
|
-
if (string.IsNullOrEmpty(snapshotAPath) || string.IsNullOrEmpty(snapshotBPath))
|
|
42
|
+
if (string.IsNullOrEmpty(request.SnapshotA) || string.IsNullOrEmpty(request.SnapshotB))
|
|
44
43
|
{
|
|
45
44
|
throw new UnityCliBridge.BridgeCommandException("E_PROFILER_SNAPSHOT_PATH_REQUIRED",
|
|
46
45
|
"profiler.memory-snapshot.compare requires --snapshot-a and --snapshot-b.",
|
|
47
|
-
"Pass two .snap file
|
|
46
|
+
"Pass two .snap file names.");
|
|
48
47
|
}
|
|
48
|
+
var snapshotAPath = ProfilerMemorySnapshotSupport.ResolveFinalPath(request.SnapshotA, ctx.RequestId);
|
|
49
|
+
var snapshotBPath = ProfilerMemorySnapshotSupport.ResolveFinalPath(request.SnapshotB, ctx.RequestId);
|
|
49
50
|
if (!File.Exists(snapshotAPath))
|
|
50
51
|
{
|
|
51
52
|
throw new UnityCliBridge.BridgeCommandException("E_PROFILER_SNAPSHOT_NOT_FOUND",
|
|
@@ -59,6 +60,9 @@ namespace UnityCli
|
|
|
59
60
|
"Check the path or run profiler.memory-snapshot.list.");
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
var budget = ctx.UseReadBudget(request.Budget);
|
|
64
|
+
if (!budget.TryConsumeNode() || !budget.TryConsumeNode() || !budget.TryConsumeGetter() || !budget.TryConsumeGetter())
|
|
65
|
+
throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
62
66
|
var fiA = new FileInfo(snapshotAPath);
|
|
63
67
|
var fiB = new FileInfo(snapshotBPath);
|
|
64
68
|
return new System.Threading.Tasks.ValueTask<Result>(new Result
|
|
@@ -2,70 +2,72 @@
|
|
|
2
2
|
using System;
|
|
3
3
|
using System.Collections.Generic;
|
|
4
4
|
using System.Globalization;
|
|
5
|
-
using System.IO;
|
|
6
|
-
using System.Reflection;
|
|
7
|
-
using UnityEditor;
|
|
8
|
-
using UnityEngine;
|
|
9
|
-
using UnityEngine.Profiling;
|
|
10
5
|
|
|
11
6
|
namespace UnityCli
|
|
12
7
|
{
|
|
8
|
+
/// <summary>profiler.memory-snapshot.list — governed latest-100 catalog 的稳定续页。</summary>
|
|
13
9
|
public class ProfilerMemorySnapshotListTool : IUnityCliTool<ProfilerMemorySnapshotListTool.Request, ProfilerMemorySnapshotListTool.Result>
|
|
14
10
|
{
|
|
15
11
|
public sealed class Request
|
|
16
12
|
{
|
|
17
|
-
public
|
|
13
|
+
[UnityCliRange(1L, 100L)] public int? PageSize { get; set; }
|
|
14
|
+
public string Cursor { get; set; }
|
|
15
|
+
public UnityCliReadBudgetInput Budget { get; set; }
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
public sealed class Result
|
|
21
19
|
{
|
|
22
20
|
public List<MemorySnapshotEntry> Snapshots { get; set; }
|
|
23
|
-
public
|
|
21
|
+
public string Root { get; set; }
|
|
22
|
+
public long Total { get; set; }
|
|
23
|
+
public string NextCursor { get; set; }
|
|
24
|
+
public bool Truncated { get; set; }
|
|
25
|
+
public string Generation { get; set; }
|
|
26
|
+
public UnityCliRequestBudgetUsage Budget { get; set; }
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
public ToolDescriptor Describe() => new()
|
|
27
30
|
{
|
|
28
31
|
Name = "profiler.memory-snapshot.list",
|
|
29
|
-
Summary = "
|
|
30
|
-
Description = "List .snap memory
|
|
31
|
-
Group = "profiler",DestructiveHint = false, Target = "editor", PlayModeSupport = "supported",
|
|
32
|
+
Summary = "Page the governed latest-100 memory snapshot catalog with stable generation continuation.",
|
|
33
|
+
Description = "List only .snap artifacts under Library/UnityCli/memory-snapshots. pageSize is 1..100 (default 25); nextCursor binds the exact bounded catalog generation and stale cursors return E_CONTINUATION_STALE. total is exact because the product catalog is capped at 100 snapshots and 8 GiB. Metadata reads and UTF-8 output use the shared request budget. Read-only in Edit and Play Mode and never scans arbitrary directories.",
|
|
34
|
+
Group = "profiler", DestructiveHint = false, Target = "editor", PlayModeSupport = "supported",
|
|
32
35
|
DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000,
|
|
33
|
-
Examples = new[] { new ToolExample { Description = "List
|
|
36
|
+
Examples = new[] { new ToolExample { Description = "List the first snapshot page", Input = new Request { PageSize = 25 } } }
|
|
34
37
|
};
|
|
35
38
|
|
|
36
39
|
public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
|
|
37
40
|
{
|
|
38
|
-
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
+
request = request ?? new Request();
|
|
42
|
+
var budget = ctx.UseReadBudget(request.Budget);
|
|
43
|
+
var files = ProfilerMemorySnapshotSupport.Catalog(budget);
|
|
44
|
+
var generation = ProfilerMemorySnapshotSupport.CatalogGeneration(files, budget);
|
|
45
|
+
var offset = 0;
|
|
46
|
+
if (!string.IsNullOrEmpty(request.Cursor))
|
|
41
47
|
{
|
|
42
|
-
|
|
48
|
+
string position;
|
|
49
|
+
if (!UnityCliContinuationToken.TryParse(request.Cursor, "profiler.memory-snapshot.list", generation, out position)
|
|
50
|
+
|| !int.TryParse(position, NumberStyles.Integer, CultureInfo.InvariantCulture, out offset) || offset < 0 || offset > files.Count)
|
|
51
|
+
throw new UnityCliBridge.BridgeCommandException("E_CONTINUATION_STALE", "The memory snapshot continuation does not match the current catalog generation.", "Start a new snapshot list without cursor.");
|
|
43
52
|
}
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
dirs.Add(Path.Combine(Application.temporaryCachePath, "MemoryCaptures"));
|
|
47
|
-
dirs.Add(Path.Combine(Application.dataPath, "..", "MemoryCaptures"));
|
|
48
|
-
}
|
|
49
|
-
|
|
53
|
+
var pageSize = request.PageSize ?? 25;
|
|
50
54
|
var snapshots = new List<MemorySnapshotEntry>();
|
|
51
|
-
|
|
55
|
+
var index = offset;
|
|
56
|
+
while (index < files.Count && snapshots.Count < pageSize)
|
|
52
57
|
{
|
|
53
|
-
if (!
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
Path = fi.FullName,
|
|
60
|
-
SizeBytes = fi.Length,
|
|
61
|
-
Created = fi.CreationTimeUtc.ToString("O", CultureInfo.InvariantCulture)
|
|
62
|
-
});
|
|
63
|
-
}
|
|
58
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeNode() || !budget.TryConsumeGetter() || !budget.TryConsumeGetter()) break;
|
|
59
|
+
var item = MemorySnapshotEntry.FromFileInfo(files[index]);
|
|
60
|
+
if (!budget.TryReserveSerializedUtf8(item.Path) || !budget.TryReserveSerializedUtf8(item.Created)) break;
|
|
61
|
+
snapshots.Add(item);
|
|
62
|
+
index++;
|
|
64
63
|
}
|
|
64
|
+
if (index == offset && index < files.Count)
|
|
65
|
+
throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension ?? "scannedRecords");
|
|
66
|
+
var next = index < files.Count ? UnityCliContinuationToken.Create("profiler.memory-snapshot.list", generation, index.ToString(CultureInfo.InvariantCulture)) : null;
|
|
65
67
|
return new System.Threading.Tasks.ValueTask<Result>(new Result
|
|
66
68
|
{
|
|
67
|
-
Snapshots = snapshots,
|
|
68
|
-
|
|
69
|
+
Snapshots = snapshots, Root = ProfilerMemorySnapshotSupport.Root, Total = files.Count,
|
|
70
|
+
NextCursor = next, Truncated = next != null, Generation = generation, Budget = budget.Usage()
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
73
|
}
|