@alpsckr/unitycli 0.4.3 → 0.4.5
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 +145 -39
- package/dist/bridge/session-supervisor.js.map +1 -1
- package/dist/bridge/start-diagnostics.d.ts +19 -0
- package/dist/bridge/start-diagnostics.js +96 -0
- package/dist/bridge/start-diagnostics.js.map +1 -0
- 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-commands/package.js +10 -2
- package/dist/cli-commands/package.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 +451 -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 +57 -5
- package/dist/extensions/installer.js +263 -64
- 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 +19 -1
- package/dist/instances.js +39 -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
|
@@ -38,7 +38,7 @@ namespace UnityCli
|
|
|
38
38
|
return new Dictionary<string, object> { { "type", "object" }, { "additionalProperties", AnyJsonSchema() } };
|
|
39
39
|
Type anyElement;
|
|
40
40
|
if (TryElementType(rawType, out anyElement))
|
|
41
|
-
return new Dictionary<string, object> { { "type", "array" }, { "items", AnyJsonSchema() } };
|
|
41
|
+
return ItemsRangeSchema(new Dictionary<string, object> { { "type", "array" }, { "items", AnyJsonSchema() } }, member, path);
|
|
42
42
|
return AnyJsonSchema();
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -46,10 +46,10 @@ namespace UnityCli
|
|
|
46
46
|
if (nullableType != null)
|
|
47
47
|
{
|
|
48
48
|
if (member != null && member.IsDefined(typeof(UnityCliRequiredAttribute), true))
|
|
49
|
-
return BuildSchema(nullableType, path, definitions,
|
|
49
|
+
return BuildSchema(nullableType, path, definitions, member, false);
|
|
50
50
|
return new Dictionary<string, object>
|
|
51
51
|
{
|
|
52
|
-
{ "oneOf", new object[] { BuildSchema(nullableType, path, definitions,
|
|
52
|
+
{ "oneOf", new object[] { BuildSchema(nullableType, path, definitions, member, false), new Dictionary<string, object> { { "type", "null" } } } }
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -67,8 +67,8 @@ namespace UnityCli
|
|
|
67
67
|
}
|
|
68
68
|
if (rawType == typeof(char)) return TypeSchema("string");
|
|
69
69
|
if (rawType == typeof(bool)) return TypeSchema("boolean");
|
|
70
|
-
if (IsInteger(rawType)) return IntegerSchema(rawType);
|
|
71
|
-
if (IsNumber(rawType)) return TypeSchema("number");
|
|
70
|
+
if (IsInteger(rawType)) return NumericRangeSchema(IntegerSchema(rawType), member, path);
|
|
71
|
+
if (IsNumber(rawType)) return NumericRangeSchema(TypeSchema("number"), member, path);
|
|
72
72
|
if (rawType.IsEnum)
|
|
73
73
|
{
|
|
74
74
|
return new Dictionary<string, object>
|
|
@@ -91,11 +91,11 @@ namespace UnityCli
|
|
|
91
91
|
Type elementType;
|
|
92
92
|
if (TryElementType(rawType, out elementType))
|
|
93
93
|
{
|
|
94
|
-
return new Dictionary<string, object>
|
|
94
|
+
return ItemsRangeSchema(new Dictionary<string, object>
|
|
95
95
|
{
|
|
96
96
|
{ "type", "array" },
|
|
97
97
|
{ "items", BuildSchema(elementType, path + "[]", definitions, member, false) }
|
|
98
|
-
};
|
|
98
|
+
}, member, path);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
if (rawType.IsPointer || rawType.IsByRef || rawType.IsGenericTypeDefinition || rawType.IsInterface || rawType.IsAbstract)
|
|
@@ -260,6 +260,35 @@ namespace UnityCli
|
|
|
260
260
|
};
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
/// <summary>将声明式集合范围投影为 JSON Schema;非法特性使 descriptor 派生失败。</summary>
|
|
264
|
+
private static Dictionary<string, object> ItemsRangeSchema(Dictionary<string, object> schema, MemberInfo member, string path)
|
|
265
|
+
{
|
|
266
|
+
var range = member == null ? null : member.GetCustomAttributes(typeof(UnityCliItemsRangeAttribute), true).Cast<UnityCliItemsRangeAttribute>().SingleOrDefault();
|
|
267
|
+
if (range == null) return schema;
|
|
268
|
+
if (range.Minimum < 0 || range.Minimum > range.Maximum) throw Unsupported(path, "items range is invalid");
|
|
269
|
+
schema["minItems"] = range.Minimum;
|
|
270
|
+
schema["maxItems"] = range.Maximum;
|
|
271
|
+
return schema;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/// <summary>将声明式业务范围收窄到 CLR 可表示范围;非法特性使 descriptor 派生失败。</summary>
|
|
275
|
+
private static Dictionary<string, object> NumericRangeSchema(Dictionary<string, object> schema, MemberInfo member, string path)
|
|
276
|
+
{
|
|
277
|
+
var range = member == null ? null : member.GetCustomAttributes(typeof(UnityCliRangeAttribute), true).Cast<UnityCliRangeAttribute>().SingleOrDefault();
|
|
278
|
+
if (range == null) return schema;
|
|
279
|
+
if (range.Minimum > range.Maximum) throw Unsupported(path, "numeric range minimum exceeds maximum");
|
|
280
|
+
decimal existingMinimum;
|
|
281
|
+
decimal existingMaximum;
|
|
282
|
+
var minimum = schema.TryGetValue("minimum", out var rawMinimum) ? Convert.ToDecimal(rawMinimum) : decimal.MinValue;
|
|
283
|
+
var maximum = schema.TryGetValue("maximum", out var rawMaximum) ? Convert.ToDecimal(rawMaximum) : decimal.MaxValue;
|
|
284
|
+
existingMinimum = Math.Max(minimum, range.Minimum);
|
|
285
|
+
existingMaximum = Math.Min(maximum, range.Maximum);
|
|
286
|
+
if (existingMinimum > existingMaximum) throw Unsupported(path, "numeric range is outside CLR range");
|
|
287
|
+
schema["minimum"] = existingMinimum;
|
|
288
|
+
schema["maximum"] = existingMaximum;
|
|
289
|
+
return schema;
|
|
290
|
+
}
|
|
291
|
+
|
|
263
292
|
internal static void IntegerRange(Type type, out decimal minimum, out decimal maximum)
|
|
264
293
|
{
|
|
265
294
|
if (type == typeof(byte)) { minimum = byte.MinValue; maximum = byte.MaxValue; return; }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#if UNITY_EDITOR
|
|
2
|
+
using System;
|
|
3
|
+
using System.Text;
|
|
4
|
+
using System.Text.RegularExpressions;
|
|
5
|
+
|
|
6
|
+
namespace UnityCli
|
|
7
|
+
{
|
|
8
|
+
/// <summary>按公开 contract profile 校验精确 Tool identity 与统一 UTF-8 byte 预算。</summary>
|
|
9
|
+
internal static class UnityCliToolName
|
|
10
|
+
{
|
|
11
|
+
internal const int MaxUtf8Bytes = 128;
|
|
12
|
+
private const string OfficialPrefix = "UnityPipeline_";
|
|
13
|
+
private static readonly Regex NativePattern = new Regex("^[a-z][a-z0-9-]*(?:\\.[a-z0-9][a-z0-9-]*)*\\z", RegexOptions.CultureInvariant);
|
|
14
|
+
private static readonly Regex OfficialSuffixPattern = new Regex("^[a-z][a-z0-9_-]*(?:\\.[a-z0-9][a-z0-9_-]*)*\\z", RegexOptions.CultureInvariant);
|
|
15
|
+
|
|
16
|
+
internal static void Validate(string name, string contractProfile)
|
|
17
|
+
{
|
|
18
|
+
var validProfile = string.Equals(contractProfile, "native", StringComparison.Ordinal)
|
|
19
|
+
|| string.Equals(contractProfile, "official-attribute", StringComparison.Ordinal);
|
|
20
|
+
var validSyntax = string.Equals(contractProfile, "official-attribute", StringComparison.Ordinal)
|
|
21
|
+
? name != null && name.StartsWith(OfficialPrefix, StringComparison.Ordinal)
|
|
22
|
+
&& OfficialSuffixPattern.IsMatch(name.Substring(OfficialPrefix.Length))
|
|
23
|
+
: string.Equals(contractProfile, "native", StringComparison.Ordinal)
|
|
24
|
+
&& name != null && NativePattern.IsMatch(name);
|
|
25
|
+
if (!validProfile || string.IsNullOrEmpty(name) || Encoding.UTF8.GetByteCount(name) > MaxUtf8Bytes || !validSyntax)
|
|
26
|
+
throw new InvalidOperationException("Tool name must use the registered Tool syntax and fit 128 UTF-8 bytes.");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
#endif
|
|
@@ -12,14 +12,15 @@ namespace UnityCli
|
|
|
12
12
|
{
|
|
13
13
|
public string AssetPath { get; set; }
|
|
14
14
|
public string Path { get; set; }
|
|
15
|
-
public int? MaxDepth { get; set; }
|
|
16
|
-
public int? MaxArrayItems { get; set; }
|
|
15
|
+
[UnityCliRange(0L, 16L)] public int? MaxDepth { get; set; }
|
|
16
|
+
[UnityCliRange(1L, 1000L)] public int? MaxArrayItems { get; set; }
|
|
17
17
|
public bool? IncludeFields { get; set; }
|
|
18
18
|
public bool? IncludeProperties { get; set; }
|
|
19
19
|
public bool? DeepSerialization { get; set; }
|
|
20
|
-
public System.Collections.Generic.List<string> Paths { get; set; }
|
|
20
|
+
[UnityCliItemsRange(0, 128)] public System.Collections.Generic.List<string> Paths { get; set; }
|
|
21
21
|
[UnityCliAnyJson] public object ViewQuery { get; set; }
|
|
22
22
|
public string NamePattern { get; set; }
|
|
23
|
+
public UnityCliReadBudgetInput Budget { get; set; }
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
public sealed class Result
|
|
@@ -33,7 +34,7 @@ namespace UnityCli
|
|
|
33
34
|
{
|
|
34
35
|
Name = "asset.get-data",
|
|
35
36
|
Summary = "Deep-read an Assets/* asset's members via ObjectSerializer; use paths or viewQuery for token-safe fields.",
|
|
36
|
-
Description = "Deep-read
|
|
37
|
+
Description = "Deep-read one loaded Assets/* object without importing. maxDepth is 0..16, maxArrayItems is 1..1000, and paths accepts at most 128 ordered exact reads. Every path and recursive branch shares the request scan/node/getter/reflection/monotonic-time/UTF-8 budget; defaults are 10000/4096/2048/4096/250 ms/1 MiB and maxima are 100000/20000/10000/20000/2000 ms/8 MiB. Truncated nodes return nextPath. Read-only in Edit and Play Mode.",
|
|
37
38
|
Group = "asset",
|
|
38
39
|
DestructiveHint = false,
|
|
39
40
|
Target = "editor",
|
|
@@ -48,22 +49,30 @@ namespace UnityCli
|
|
|
48
49
|
|
|
49
50
|
public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
|
|
50
51
|
{
|
|
52
|
+
var budget = ctx.UseReadBudget(request.Budget);
|
|
53
|
+
budget.CheckpointOrThrow();
|
|
51
54
|
var path = AssetToolSupport.RequireAssetPath(request.AssetPath ?? request.Path);
|
|
55
|
+
if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
52
56
|
if (!AssetToolSupport.AssetExists(path))
|
|
53
57
|
{
|
|
54
58
|
throw new UnityCliBridge.BridgeCommandException("E_ASSET_NOT_FOUND", "Asset not found: " + path, "Run tools run asset.search --input '{\"query\":\"<keyword>\"}' to discover the path.");
|
|
55
59
|
}
|
|
60
|
+
if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
56
61
|
var asset = AssetDatabase.LoadMainAssetAtPath(path);
|
|
57
62
|
if (asset == null)
|
|
58
63
|
{
|
|
59
64
|
throw new UnityCliBridge.BridgeCommandException("E_ASSET_LOAD_FAILED", "Asset main object could not be loaded: " + path, "Run asset.info to confirm the asset type, or use a more specific tool for folders/importers.");
|
|
60
65
|
}
|
|
61
66
|
var options = GameObjectToolSupport.BuildSerializerOptions(request);
|
|
62
|
-
var data = UnityCliBridge.ObjectSerializer.Serialize(asset, options);
|
|
67
|
+
var data = UnityCliBridge.ObjectSerializer.Serialize(asset, options, budget);
|
|
68
|
+
if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
69
|
+
var guid = AssetDatabase.AssetPathToGUID(path);
|
|
70
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
71
|
+
var typeName = asset.GetType().FullName;
|
|
63
72
|
return new System.Threading.Tasks.ValueTask<Result>(new Result
|
|
64
73
|
{
|
|
65
|
-
Guid =
|
|
66
|
-
TypeName =
|
|
74
|
+
Guid = guid,
|
|
75
|
+
TypeName = typeName,
|
|
67
76
|
// ObjectSerializer 输出为动态 JSON 树);解析为嵌套结构供框架序列化(IDictionary 支持)
|
|
68
77
|
Data = data
|
|
69
78
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#if UNITY_EDITOR
|
|
2
|
+
using System.Collections.Generic;
|
|
2
3
|
using System.Linq;
|
|
3
4
|
using UnityEditor;
|
|
4
5
|
|
|
@@ -16,22 +17,41 @@ namespace UnityCli
|
|
|
16
17
|
var index = scenes.ToList().FindIndex(scene => scene.path == path);
|
|
17
18
|
if (index < 0)
|
|
18
19
|
throw new UnityCliBridge.BridgeCommandException("E_BUILD_SCENE_NOT_FOUND", "Build Settings does not contain scene: " + path, "Run build.scene.list and pass a listed path.");
|
|
19
|
-
|
|
20
|
+
var changed = scenes[index].enabled != enabled;
|
|
21
|
+
var plannedEffects = changed
|
|
22
|
+
? new List<BuildScenePlannedEffect> { new BuildScenePlannedEffect { Type = toolName, Path = path, Enabled = enabled } }
|
|
23
|
+
: new List<BuildScenePlannedEffect>();
|
|
24
|
+
if (!ctx.DryRun && changed)
|
|
20
25
|
{
|
|
21
26
|
ctx.CommitEffect();
|
|
22
27
|
scenes[index] = new EditorBuildSettingsScene(path, enabled);
|
|
23
28
|
EditorBuildSettings.scenes = scenes;
|
|
24
29
|
scenes = ReadScenes();
|
|
25
|
-
|
|
30
|
+
index = scenes.ToList().FindIndex(scene => scene.path == path);
|
|
31
|
+
if (index < 0 || scenes[index].enabled != enabled)
|
|
26
32
|
throw new UnityCliBridge.BridgeCommandException("E_BUILD_SCENE_STATE_MISMATCH", "Build Settings did not apply the requested enabled state for " + path + ".", "Inspect build.scene.list and retry.");
|
|
27
33
|
}
|
|
28
|
-
return new(new BuildSceneMutationResult
|
|
34
|
+
return new(new BuildSceneMutationResult
|
|
35
|
+
{
|
|
36
|
+
Count = scenes.LongLength,
|
|
37
|
+
Scene = BuildEntry(scenes[index], index),
|
|
38
|
+
Changed = !ctx.DryRun && changed,
|
|
39
|
+
NoOpReason = !changed ? "scene-already-" + (enabled ? "enabled" : "disabled") : null,
|
|
40
|
+
DryRun = ctx.DryRun,
|
|
41
|
+
PlannedEffects = plannedEffects
|
|
42
|
+
});
|
|
29
43
|
}
|
|
30
44
|
|
|
31
45
|
public static EditorBuildSettingsScene[] ReadScenes()
|
|
32
46
|
{
|
|
33
47
|
return EditorBuildSettings.scenes ?? new EditorBuildSettingsScene[0];
|
|
34
48
|
}
|
|
49
|
+
|
|
50
|
+
// 将 fresh EditorBuildSettings 读回投影为公开条目。
|
|
51
|
+
public static BuildSceneEntry BuildEntry(EditorBuildSettingsScene scene, int index)
|
|
52
|
+
{
|
|
53
|
+
return new BuildSceneEntry { Path = BuildToolSupport.NormalizeAssetPath(scene.path), Enabled = scene.enabled, BuildIndex = index };
|
|
54
|
+
}
|
|
35
55
|
}
|
|
36
56
|
}
|
|
37
57
|
#endif
|
|
@@ -8,7 +8,8 @@ namespace UnityCli
|
|
|
8
8
|
public sealed class BuildProfileMutationResult { public bool Available { get; set; } public string Action { get; set; } public string ActivePath { get; set; } public bool DryRun { get; set; } }
|
|
9
9
|
public sealed class BuildSceneEntry { public string Path { get; set; } public bool Enabled { get; set; } public long BuildIndex { get; set; } }
|
|
10
10
|
public sealed class BuildSceneListResult { public long Count { get; set; } public List<BuildSceneEntry> Scenes { get; set; } }
|
|
11
|
-
public sealed class
|
|
11
|
+
public sealed class BuildScenePlannedEffect { public string Type { get; set; } public string Path { get; set; } public bool? Enabled { get; set; } }
|
|
12
|
+
public sealed class BuildSceneMutationResult { public long Count { get; set; } public BuildSceneEntry Scene { get; set; } public bool Changed { get; set; } public string NoOpReason { get; set; } public bool DryRun { get; set; } public List<BuildScenePlannedEffect> PlannedEffects { get; set; } }
|
|
12
13
|
public sealed class BuildSettingsResult { public string ProductName { get; set; } public string BundleVersion { get; set; } public string CompanyId { get; set; } public string ApplicationIdentifier { get; set; } public string ScriptingBackend { get; set; } public string ApiCompatibilityLevel { get; set; } public List<string> Changed { get; set; } public bool DryRun { get; set; } }
|
|
13
14
|
public sealed class BuildSettingsMutationResult { public List<string> Changed { get; set; } public bool DryRun { get; set; } }
|
|
14
15
|
}
|
|
@@ -7,7 +7,7 @@ namespace UnityCli
|
|
|
7
7
|
public class BuildSceneAddTool : IUnityCliTool<BuildSceneAddTool.Request, BuildSceneMutationResult>
|
|
8
8
|
{
|
|
9
9
|
public sealed class Request { [UnityCliRequired] public string Path { get; set; } }
|
|
10
|
-
public ToolDescriptor Describe() => new() { Name = "build.scene.add", Summary = "Add an enabled scene to persistent Unity Build Settings.", Description = "Adds
|
|
10
|
+
public ToolDescriptor Describe() => new() { Name = "build.scene.add", Summary = "Add an enabled scene to persistent Unity Build Settings.", Description = "Adds one existing Assets/*.unity scene to EditorBuildSettings as enabled. Available in Edit and Play mode. dryRun previews the exact path; success returns the fresh scene entry, count, changed state, and no-op reason.", Group = "build",DestructiveHint = true, SupportsDryRun = true, SideEffects = new[] { "project-settings-write" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Add main scene", Input = new Request { Path = "Assets/Scenes/Main.unity" }, Execution = new ToolExampleExecution { DryRun = true } } } };
|
|
11
11
|
public System.Threading.Tasks.ValueTask<BuildSceneMutationResult> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
|
|
12
12
|
{
|
|
13
13
|
var path = BuildToolSupport.NormalizeAssetPath(request.Path);
|
|
@@ -32,12 +32,15 @@ namespace UnityCli
|
|
|
32
32
|
if (!scenes.Any(scene => scene.path == path && scene.enabled))
|
|
33
33
|
throw new UnityCliBridge.BridgeCommandException("E_BUILD_SCENE_ADD_MISMATCH", "Build Settings did not add enabled scene: " + path, "Inspect build.scene.list and retry.");
|
|
34
34
|
}
|
|
35
|
+
var observedIndex = System.Array.FindIndex(scenes, scene => scene.path == path);
|
|
35
36
|
return new(new BuildSceneMutationResult
|
|
36
37
|
{
|
|
37
38
|
Count = scenes.LongLength,
|
|
39
|
+
Scene = observedIndex < 0 ? null : BuildSceneStateTool.BuildEntry(scenes[observedIndex], observedIndex),
|
|
38
40
|
Changed = !ctx.DryRun && changed,
|
|
39
|
-
NoOpReason = !
|
|
40
|
-
DryRun = ctx.DryRun
|
|
41
|
+
NoOpReason = !changed ? "scene-already-enabled" : null,
|
|
42
|
+
DryRun = ctx.DryRun,
|
|
43
|
+
PlannedEffects = changed ? new System.Collections.Generic.List<BuildScenePlannedEffect> { new BuildScenePlannedEffect { Type = "build.scene.add", Path = path, Enabled = true } } : new System.Collections.Generic.List<BuildScenePlannedEffect>()
|
|
41
44
|
});
|
|
42
45
|
}
|
|
43
46
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#if UNITY_EDITOR
|
|
2
|
-
namespace UnityCli { public class BuildSceneDisableTool : IUnityCliTool<BuildSceneDisableTool.Request, BuildSceneMutationResult> { public sealed class Request { [UnityCliRequired] public string Path { get; set; } } public ToolDescriptor Describe() => new() { Name = "build.scene.disable", Summary = "Disable a scene in persistent Unity Build Settings.", Description = "Marks
|
|
2
|
+
namespace UnityCli { public class BuildSceneDisableTool : IUnityCliTool<BuildSceneDisableTool.Request, BuildSceneMutationResult> { public sealed class Request { [UnityCliRequired] public string Path { get; set; } } public ToolDescriptor Describe() => new() { Name = "build.scene.disable", Summary = "Disable a scene in persistent Unity Build Settings.", Description = "Marks one existing EditorBuildSettings scene as disabled. Available in Edit and Play mode. dryRun previews the exact path; success returns a fresh scene entry, changed state, and no-op reason.", Group = "build",DestructiveHint = true, SupportsDryRun = true, SideEffects = new[] { "project-settings-write" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Disable main scene", Input = new Request { Path = "Assets/Scenes/Main.unity" }, Execution = new ToolExampleExecution { DryRun = true } } } }; public System.Threading.Tasks.ValueTask<BuildSceneMutationResult> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default) { return BuildSceneStateTool.Execute(request.Path, false, "build.scene.disable", ctx); } } }
|
|
3
3
|
#endif
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#if UNITY_EDITOR
|
|
2
2
|
using System.Linq; using UnityEditor;
|
|
3
|
-
namespace UnityCli { public class BuildSceneEnableTool : IUnityCliTool<BuildSceneEnableTool.Request, BuildSceneMutationResult> { public sealed class Request { [UnityCliRequired] public string Path { get; set; } } public ToolDescriptor Describe() => new() { Name = "build.scene.enable", Summary = "Enable a scene in persistent Unity Build Settings.", Description = "Marks
|
|
3
|
+
namespace UnityCli { public class BuildSceneEnableTool : IUnityCliTool<BuildSceneEnableTool.Request, BuildSceneMutationResult> { public sealed class Request { [UnityCliRequired] public string Path { get; set; } } public ToolDescriptor Describe() => new() { Name = "build.scene.enable", Summary = "Enable a scene in persistent Unity Build Settings.", Description = "Marks one existing EditorBuildSettings scene as enabled. Available in Edit and Play mode. dryRun previews the exact path; success returns a fresh scene entry, changed state, and no-op reason.", Group = "build",DestructiveHint = true, SupportsDryRun = true, SideEffects = new[] { "project-settings-write" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Enable main scene", Input = new Request { Path = "Assets/Scenes/Main.unity" }, Execution = new ToolExampleExecution { DryRun = true } } } }; public System.Threading.Tasks.ValueTask<BuildSceneMutationResult> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default) { return BuildSceneStateTool.Execute(request.Path, true, "build.scene.enable", ctx); } } }
|
|
4
4
|
#endif
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#if UNITY_EDITOR
|
|
2
2
|
using System.Collections.Generic; using UnityEditor;
|
|
3
|
-
namespace UnityCli { public class BuildSceneListTool : IUnityCliTool<BuildSceneListTool.Request, BuildSceneListResult> { public sealed class Request { } public ToolDescriptor Describe() => new() { Name = "build.scene.list", Summary = "List scenes registered in Unity Build Settings.", Description = "Returns every
|
|
3
|
+
namespace UnityCli { public class BuildSceneListTool : IUnityCliTool<BuildSceneListTool.Request, BuildSceneListResult> { public sealed class Request { } public ToolDescriptor Describe() => new() { Name = "build.scene.list", Summary = "List scenes registered in Unity Build Settings.", Description = "Returns every EditorBuildSettings scene with normalized path, enabled state, and build index. Read-only and available in Edit and Play mode; use the dedicated add/remove/enable/disable Tools for writes.", Group = "build",Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "List build scenes", Input = new Request() } } }; public System.Threading.Tasks.ValueTask<BuildSceneListResult> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default) { var scenes = EditorBuildSettings.scenes ?? new EditorBuildSettingsScene[0]; var entries = new List<BuildSceneEntry>(); for (var i = 0; i < scenes.Length; i++) entries.Add(new BuildSceneEntry { Path = BuildToolSupport.NormalizeAssetPath(scenes[i].path), Enabled = scenes[i].enabled, BuildIndex = i }); return new(new BuildSceneListResult { Count = scenes.Length, Scenes = entries }); } } }
|
|
4
4
|
#endif
|
|
@@ -7,14 +7,16 @@ namespace UnityCli
|
|
|
7
7
|
public class BuildSceneRemoveTool : IUnityCliTool<BuildSceneRemoveTool.Request, BuildSceneMutationResult>
|
|
8
8
|
{
|
|
9
9
|
public sealed class Request { [UnityCliRequired] public string Path { get; set; } }
|
|
10
|
-
public ToolDescriptor Describe() => new() { Name = "build.scene.remove", Summary = "Remove a scene from persistent Unity Build Settings.", Description = "Removes path from EditorBuildSettings. dryRun
|
|
10
|
+
public ToolDescriptor Describe() => new() { Name = "build.scene.remove", Summary = "Remove a scene from persistent Unity Build Settings.", Description = "Removes one exact scene path from EditorBuildSettings. Available in Edit and Play mode. dryRun previews the path; success returns the fresh remaining count, changed state, and no-op reason.", Group = "build",DestructiveHint = true, SupportsDryRun = true, SideEffects = new[] { "project-settings-write" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Remove main scene", Input = new Request { Path = "Assets/Scenes/Main.unity" }, Execution = new ToolExampleExecution { DryRun = true } } } };
|
|
11
11
|
public System.Threading.Tasks.ValueTask<BuildSceneMutationResult> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
|
|
12
12
|
{
|
|
13
13
|
var path = BuildToolSupport.NormalizeAssetPath(request.Path);
|
|
14
14
|
if (string.IsNullOrEmpty(path))
|
|
15
15
|
throw new UnityCliBridge.BridgeCommandException("E_BUILD_SCENE_PATH_REQUIRED", "build.scene.remove requires path.", "Pass a scene path such as Assets/Scenes/Main.unity.");
|
|
16
16
|
var scenes = BuildSceneStateTool.ReadScenes();
|
|
17
|
-
|
|
17
|
+
var existingIndex = System.Array.FindIndex(scenes, scene => scene.path == path);
|
|
18
|
+
var changed = existingIndex >= 0;
|
|
19
|
+
if (!ctx.DryRun && changed)
|
|
18
20
|
{
|
|
19
21
|
ctx.CommitEffect();
|
|
20
22
|
EditorBuildSettings.scenes = scenes.Where(scene => scene.path != path).ToArray();
|
|
@@ -22,7 +24,15 @@ namespace UnityCli
|
|
|
22
24
|
if (scenes.Any(scene => scene.path == path))
|
|
23
25
|
throw new UnityCliBridge.BridgeCommandException("E_BUILD_SCENE_REMOVE_MISMATCH", "Build Settings did not remove scene: " + path, "Inspect build.scene.list and retry.");
|
|
24
26
|
}
|
|
25
|
-
return new(new BuildSceneMutationResult
|
|
27
|
+
return new(new BuildSceneMutationResult
|
|
28
|
+
{
|
|
29
|
+
Count = scenes.LongLength,
|
|
30
|
+
Scene = ctx.DryRun && changed ? BuildSceneStateTool.BuildEntry(scenes[existingIndex], existingIndex) : null,
|
|
31
|
+
Changed = !ctx.DryRun && changed,
|
|
32
|
+
NoOpReason = !changed ? "scene-not-registered" : null,
|
|
33
|
+
DryRun = ctx.DryRun,
|
|
34
|
+
PlannedEffects = changed ? new System.Collections.Generic.List<BuildScenePlannedEffect> { new BuildScenePlannedEffect { Type = "build.scene.remove", Path = path } } : new System.Collections.Generic.List<BuildScenePlannedEffect>()
|
|
35
|
+
});
|
|
26
36
|
}
|
|
27
37
|
}
|
|
28
38
|
}
|
|
@@ -3,7 +3,6 @@ using System;
|
|
|
3
3
|
using System.Collections.Generic;
|
|
4
4
|
using System.Globalization;
|
|
5
5
|
using System.IO;
|
|
6
|
-
using System.Security.Cryptography;
|
|
7
6
|
using UnityEditor;
|
|
8
7
|
using UnityEngine;
|
|
9
8
|
|
|
@@ -57,6 +56,27 @@ namespace UnityCli
|
|
|
57
56
|
return null;
|
|
58
57
|
}
|
|
59
58
|
|
|
59
|
+
/// <summary>读取型截图解析复用一次 Camera snapshot,并把每个候选计入请求 scan/getter 预算。</summary>
|
|
60
|
+
public static Camera ResolveCamera(string target, UnityCliRequestBudget budget)
|
|
61
|
+
{
|
|
62
|
+
if (budget == null) throw new ArgumentNullException("budget");
|
|
63
|
+
if (string.IsNullOrEmpty(target))
|
|
64
|
+
{
|
|
65
|
+
if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
66
|
+
var main = Camera.main;
|
|
67
|
+
if (main != null) return main;
|
|
68
|
+
}
|
|
69
|
+
var cameras = Camera.allCameras;
|
|
70
|
+
foreach (var camera in cameras)
|
|
71
|
+
{
|
|
72
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
73
|
+
if (string.IsNullOrEmpty(target) || camera.name == target || camera.GetInstanceID().ToString(CultureInfo.InvariantCulture) == target) return camera;
|
|
74
|
+
var path = UnityCliHierarchyPager.Path(camera.gameObject, budget);
|
|
75
|
+
if (path == target) return camera;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
60
80
|
/// <summary>构造 Camera 摘要信息 DTO。</summary>
|
|
61
81
|
public static CameraInfo BuildCameraInfo(Camera camera)
|
|
62
82
|
{
|
|
@@ -143,45 +163,25 @@ namespace UnityCli
|
|
|
143
163
|
}
|
|
144
164
|
}
|
|
145
165
|
|
|
146
|
-
/// <summary
|
|
147
|
-
public static
|
|
148
|
-
{
|
|
149
|
-
if (bytes == null || bytes.Length == 0)
|
|
150
|
-
throw new UnityCliBridge.BridgeCommandException("E_SCREENSHOT_ENCODE_FAILED", "Screenshot encoder returned no bytes.", "Check the Camera render state and retry.");
|
|
151
|
-
try { File.WriteAllBytes(outputPath, bytes); }
|
|
152
|
-
catch (Exception exception) { throw new UnityCliBridge.BridgeCommandException("E_IO_ERROR", "Failed to write screenshot output: " + exception.Message); }
|
|
153
|
-
return VerifyScreenshotArtifact(outputPath, Path.GetExtension(outputPath).TrimStart('.'));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/// <summary>artifact proof 必须来自写后 fresh readback,不能只依赖 Exists 或原始编码 bytes。</summary>
|
|
157
|
-
public static CameraArtifactProof VerifyScreenshotArtifact(string outputPath, string format)
|
|
158
|
-
{
|
|
159
|
-
if (!File.Exists(outputPath)) throw new UnityCliBridge.BridgeCommandException("E_SCREENSHOT_WRITE_PROOF_MISSING", "Screenshot output was not written: " + outputPath, "Check destination path and permissions, then retry.");
|
|
160
|
-
var bytes = File.ReadAllBytes(outputPath);
|
|
161
|
-
var normalized = NormalizeFormat(format, outputPath);
|
|
162
|
-
var valid = normalized == "png"
|
|
163
|
-
? bytes.Length >= 8 && bytes[0] == 0x89 && bytes[1] == 0x50 && bytes[2] == 0x4e && bytes[3] == 0x47 && bytes[4] == 0x0d && bytes[5] == 0x0a && bytes[6] == 0x1a && bytes[7] == 0x0a
|
|
164
|
-
: bytes.Length >= 3 && bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff;
|
|
165
|
-
if (!valid) throw new UnityCliBridge.BridgeCommandException("E_SCREENSHOT_WRITE_PROOF_MISSING", "Screenshot output is empty or does not match its requested format: " + outputPath, "Use a .png or .jpg output path and retry.");
|
|
166
|
-
using (var sha = SHA256.Create()) return new CameraArtifactProof { SizeBytes = bytes.LongLength, Sha256 = string.Concat(Array.ConvertAll(sha.ComputeHash(bytes), value => value.ToString("x2"))) };
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/// <summary>渲染指定 Camera 到 RenderTexture 并编码为图片字节,返回捕获结果。捕获后恢复相机状态。</summary>
|
|
170
|
-
public static CameraCapture CaptureCamera(Camera camera, int width, int height, bool transparent, int quality, string outputPath, string format, bool overwrite, bool inlineBase64)
|
|
166
|
+
/// <summary>按冻结 aggregate plan 渲染、编码与证明单张 Camera artifact,并在 finally 恢复纹理状态。</summary>
|
|
167
|
+
public static CameraCapture CaptureCamera(Camera camera, int width, int height, bool transparent, int quality, string outputPath, string format, bool overwrite, bool inlineBase64, ScreenshotCaptureBudget budget)
|
|
171
168
|
{
|
|
172
169
|
if (File.Exists(outputPath) && !overwrite)
|
|
173
170
|
{
|
|
174
171
|
throw new UnityCliBridge.BridgeCommandException("E_OUTPUT_EXISTS", "Screenshot output already exists: " + outputPath, "Pass overwrite=true or choose a different output path.");
|
|
175
172
|
}
|
|
173
|
+
budget.BeginCapture(width, height);
|
|
176
174
|
CreateScreenshotDirectory(outputPath);
|
|
177
175
|
var previousTarget = camera.targetTexture;
|
|
178
176
|
var previousActive = RenderTexture.active;
|
|
179
177
|
var previousClearFlags = camera.clearFlags;
|
|
180
178
|
var previousBackground = camera.backgroundColor;
|
|
181
|
-
|
|
182
|
-
|
|
179
|
+
RenderTexture renderTexture = null;
|
|
180
|
+
Texture2D texture = null;
|
|
183
181
|
try
|
|
184
182
|
{
|
|
183
|
+
renderTexture = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32);
|
|
184
|
+
texture = new Texture2D(width, height, transparent ? TextureFormat.ARGB32 : TextureFormat.RGB24, false);
|
|
185
185
|
camera.targetTexture = renderTexture;
|
|
186
186
|
if (transparent)
|
|
187
187
|
{
|
|
@@ -193,20 +193,22 @@ namespace UnityCli
|
|
|
193
193
|
texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
|
|
194
194
|
texture.Apply();
|
|
195
195
|
var bytes = format == "jpg" ? texture.EncodeToJPG(quality) : texture.EncodeToPNG();
|
|
196
|
-
var artifact = WriteScreenshotBytes(outputPath, bytes);
|
|
196
|
+
var artifact = ScreenshotToolSupport.WriteScreenshotBytes(outputPath, bytes, budget);
|
|
197
197
|
var capture = new CameraCapture
|
|
198
198
|
{
|
|
199
199
|
ScreenshotPath = outputPath,
|
|
200
200
|
ArtifactPath = outputPath,
|
|
201
201
|
Source = "camera",
|
|
202
202
|
SizeBytes = artifact.SizeBytes,
|
|
203
|
-
Sha256 = artifact.Sha256
|
|
203
|
+
Sha256 = artifact.Sha256,
|
|
204
|
+
CapturePlan = budget.Plan
|
|
204
205
|
};
|
|
205
|
-
// inlineBase64
|
|
206
|
+
// inlineBase64 同时受固定图片上限与请求级 UTF-8 预算约束。
|
|
206
207
|
const int InlineImageMaxBytes = 512 * 1024;
|
|
207
|
-
|
|
208
|
+
string encoded;
|
|
209
|
+
if (inlineBase64 && bytes != null && bytes.Length <= InlineImageMaxBytes && budget.TryCreateInlineBase64(bytes, out encoded))
|
|
208
210
|
{
|
|
209
|
-
capture.ImageBase64 =
|
|
211
|
+
capture.ImageBase64 = encoded;
|
|
210
212
|
capture.ImageWidth = width;
|
|
211
213
|
capture.ImageHeight = height;
|
|
212
214
|
capture.ImageMimeType = format == "jpg" ? "image/jpeg" : "image/png";
|
|
@@ -219,9 +221,8 @@ namespace UnityCli
|
|
|
219
221
|
camera.targetTexture = previousTarget;
|
|
220
222
|
camera.clearFlags = previousClearFlags;
|
|
221
223
|
camera.backgroundColor = previousBackground;
|
|
222
|
-
UnityEngine.Object.DestroyImmediate(texture);
|
|
223
|
-
renderTexture.Release();
|
|
224
|
-
UnityEngine.Object.DestroyImmediate(renderTexture);
|
|
224
|
+
if (texture != null) UnityEngine.Object.DestroyImmediate(texture);
|
|
225
|
+
if (renderTexture != null) { renderTexture.Release(); UnityEngine.Object.DestroyImmediate(renderTexture); }
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
228
|
|
|
@@ -275,10 +276,9 @@ namespace UnityCli
|
|
|
275
276
|
public string ImageMimeType { get; set; }
|
|
276
277
|
public long SizeBytes { get; set; }
|
|
277
278
|
public string Sha256 { get; set; }
|
|
279
|
+
public ScreenshotCapturePlan CapturePlan { get; set; }
|
|
278
280
|
}
|
|
279
281
|
|
|
280
|
-
public sealed class CameraArtifactProof { public long SizeBytes { get; set; } public string Sha256 { get; set; } }
|
|
281
|
-
|
|
282
282
|
/// <summary>计划副作用项,camera 域 mutation 工具 Result 共享。</summary>
|
|
283
283
|
public sealed class CameraPlannedEffect
|
|
284
284
|
{
|
|
@@ -16,9 +16,11 @@ namespace UnityCli
|
|
|
16
16
|
{
|
|
17
17
|
public string Targets { get; set; }
|
|
18
18
|
public string Output { get; set; }
|
|
19
|
-
public int? Width { get; set; }
|
|
20
|
-
public int? Height { get; set; }
|
|
19
|
+
[UnityCliRange(1L, 8192L)] public int? Width { get; set; }
|
|
20
|
+
[UnityCliRange(1L, 8192L)] public int? Height { get; set; }
|
|
21
21
|
public string Format { get; set; }
|
|
22
|
+
public ScreenshotBudgetInput Limits { get; set; }
|
|
23
|
+
public UnityCliReadBudgetInput Budget { get; set; }
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
public sealed class Result
|
|
@@ -26,13 +28,14 @@ namespace UnityCli
|
|
|
26
28
|
public List<CameraCapture> Captures { get; set; }
|
|
27
29
|
public long Count { get; set; }
|
|
28
30
|
public List<CameraPlannedEffect> PlannedEffects { get; set; }
|
|
31
|
+
public ScreenshotCapturePlan CapturePlan { get; set; }
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
public ToolDescriptor Describe() => new()
|
|
32
35
|
{
|
|
33
36
|
Name = "camera.multiview",
|
|
34
37
|
Summary = "Capture one PNG/JPG artifact per named Camera into an output directory for multiview review.",
|
|
35
|
-
Description = "Capture
|
|
38
|
+
Description = "Capture 1..16 named Cameras to PNG/JPG artifacts. Each dimension is 1..8192 and each image is at most 16777216 pixels. Before the first effect, the aggregate plan must fit default ceilings of 33554432 total pixels, 128 MiB temporary memory and 64 MiB artifacts; public maxima are 67108864, 256 MiB and 256 MiB. All textures are released after each capture. Available in Edit and Play Mode with session render effects.",
|
|
36
39
|
Group = "camera",
|
|
37
40
|
DestructiveHint = true,
|
|
38
41
|
SideEffects = new[] { "artifact-write", "render-texture" },
|
|
@@ -52,11 +55,14 @@ namespace UnityCli
|
|
|
52
55
|
{
|
|
53
56
|
throw new UnityCliBridge.BridgeCommandException("E_TARGET_NOT_FOUND", "camera.multiview requires targets.", "Run tools run camera.list, then pass comma-separated camera names, hierarchy paths, or instance ids.");
|
|
54
57
|
}
|
|
58
|
+
var requestBudget = ctx.UseReadBudget(request.Budget);
|
|
55
59
|
var names = request.Targets.Split(new[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
|
|
60
|
+
if (names.Length < 1 || names.Length > 16)
|
|
61
|
+
throw new UnityCliBridge.BridgeCommandException("E_SCREENSHOT_LIMIT_INVALID", "camera.multiview targets must contain 1..16 cameras.", "Reduce the target list before retrying.");
|
|
56
62
|
var cameras = new List<Camera>();
|
|
57
63
|
foreach (var name in names)
|
|
58
64
|
{
|
|
59
|
-
var camera = CameraToolSupport.ResolveCamera(name.Trim());
|
|
65
|
+
var camera = CameraToolSupport.ResolveCamera(name.Trim(), requestBudget);
|
|
60
66
|
if (camera == null)
|
|
61
67
|
{
|
|
62
68
|
throw new UnityCliBridge.BridgeCommandException("E_CAMERA_NOT_FOUND", "Camera not found: " + name.Trim(), "Run tools run camera.list, then retry with camera names, hierarchy paths, or instance ids from the result.");
|
|
@@ -67,6 +73,7 @@ namespace UnityCli
|
|
|
67
73
|
var width = CameraToolSupport.ClampScreenshotDimension(request.Width ?? 1280, "width");
|
|
68
74
|
var height = CameraToolSupport.ClampScreenshotDimension(request.Height ?? 720, "height");
|
|
69
75
|
var format = CameraToolSupport.NormalizeFormat(request.Format, Path.Combine(outputDir, "capture.png"));
|
|
76
|
+
var captureBudget = ScreenshotToolSupport.PrepareCaptureBudget(width, height, cameras.Count, false, request.Limits, requestBudget);
|
|
70
77
|
var captures = new List<CameraCapture>();
|
|
71
78
|
var effects = new List<CameraPlannedEffect>();
|
|
72
79
|
var plans = new List<KeyValuePair<int, string>>();
|
|
@@ -83,13 +90,13 @@ namespace UnityCli
|
|
|
83
90
|
{
|
|
84
91
|
var camera = EditorUtility.InstanceIDToObject(plan.Key) as Camera;
|
|
85
92
|
if (camera == null) throw new UnityCliBridge.BridgeCommandException("E_CAMERA_NOT_FOUND", "Camera disappeared before capture.", "Retry after the Editor is idle.");
|
|
86
|
-
var capture = CameraToolSupport.CaptureCamera(camera, width, height, false, 95, plan.Value, format, true, false);
|
|
93
|
+
var capture = CameraToolSupport.CaptureCamera(camera, width, height, false, 95, plan.Value, format, true, false, captureBudget);
|
|
87
94
|
if (!File.Exists(plan.Value) || new FileInfo(plan.Value).Length == 0)
|
|
88
95
|
throw new UnityCliBridge.BridgeCommandException("E_MULTIVIEW_ARTIFACT_MISSING", "Camera capture artifact was not observed: " + plan.Value, "Check the output directory and retry.");
|
|
89
96
|
captures.Add(capture);
|
|
90
97
|
effects.Add(new CameraPlannedEffect { Type = "camera.multiview", Property = "capture", Path = plan.Value });
|
|
91
98
|
}
|
|
92
|
-
return new System.Threading.Tasks.ValueTask<Result>(new Result { Captures = captures, Count = captures.Count, PlannedEffects = effects });
|
|
99
|
+
return new System.Threading.Tasks.ValueTask<Result>(new Result { Captures = captures, Count = captures.Count, PlannedEffects = effects, CapturePlan = captureBudget.Plan });
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#if UNITY_EDITOR
|
|
2
|
+
using System.IO;
|
|
2
3
|
using UnityEngine;
|
|
3
4
|
|
|
4
5
|
namespace UnityCli
|
|
@@ -13,20 +14,22 @@ namespace UnityCli
|
|
|
13
14
|
public string Target { get; set; }
|
|
14
15
|
public string Path { get; set; }
|
|
15
16
|
public string Output { get; set; }
|
|
16
|
-
public int? Width { get; set; }
|
|
17
|
-
public int? Height { get; set; }
|
|
17
|
+
[UnityCliRange(1L, 8192L)] public int? Width { get; set; }
|
|
18
|
+
[UnityCliRange(1L, 8192L)] public int? Height { get; set; }
|
|
18
19
|
public string Format { get; set; }
|
|
19
20
|
public bool Transparent { get; set; }
|
|
20
|
-
public int? Quality { get; set; }
|
|
21
|
+
[UnityCliRange(1L, 100L)] public int? Quality { get; set; }
|
|
21
22
|
public bool Overwrite { get; set; }
|
|
22
23
|
public bool InlineBase64 { get; set; }
|
|
24
|
+
public ScreenshotBudgetInput Limits { get; set; }
|
|
25
|
+
public UnityCliReadBudgetInput Budget { get; set; }
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
public ToolDescriptor Describe() => new()
|
|
26
29
|
{
|
|
27
30
|
Name = "camera.screenshot",
|
|
28
31
|
Summary = "Render a PNG/JPG artifact from one specific Camera; use screenshot.* for view-based captures.",
|
|
29
|
-
Description = "Render
|
|
32
|
+
Description = "Render one Camera to PNG/JPG. Before the first effect, dimensions must be 1..8192 with at most 16777216 pixels, and the aggregate plan must fit default ceilings of 33554432 total pixels, 128 MiB temporary memory and 64 MiB artifacts (public maxima 67108864, 256 MiB and 256 MiB). limits may only tighten or raise within those maxima; zero, negative and excessive values fail before capture. The texture and Camera state are released/restored in finally. Available in Edit and Play Mode with session render effects.",
|
|
30
33
|
Group = "camera",
|
|
31
34
|
DestructiveHint = true,
|
|
32
35
|
SideEffects = new[] { "artifact-write", "render-texture" },
|
|
@@ -47,7 +50,8 @@ namespace UnityCli
|
|
|
47
50
|
{
|
|
48
51
|
throw new UnityCliBridge.BridgeCommandException("E_TARGET_NOT_FOUND", "Camera screenshot requires a target Camera.", "Pass a Camera name, hierarchy path or instance id. Run tools run camera.list before retrying.");
|
|
49
52
|
}
|
|
50
|
-
var
|
|
53
|
+
var requestBudget = ctx.UseReadBudget(request.Budget);
|
|
54
|
+
var camera = CameraToolSupport.ResolveCamera(target, requestBudget);
|
|
51
55
|
if (camera == null)
|
|
52
56
|
{
|
|
53
57
|
throw new UnityCliBridge.BridgeCommandException("E_TARGET_NOT_FOUND", "Camera not found: " + target, "Run tools run camera.list, then retry with a camera name, hierarchy path, or instance id from the result.");
|
|
@@ -56,9 +60,12 @@ namespace UnityCli
|
|
|
56
60
|
var format = CameraToolSupport.NormalizeFormat(request.Format, outputPath);
|
|
57
61
|
var width = CameraToolSupport.ClampScreenshotDimension(request.Width ?? (camera.pixelWidth > 0 ? camera.pixelWidth : 1280), "width");
|
|
58
62
|
var height = CameraToolSupport.ClampScreenshotDimension(request.Height ?? (camera.pixelHeight > 0 ? camera.pixelHeight : 720), "height");
|
|
59
|
-
var quality =
|
|
63
|
+
var quality = request.Quality ?? 95;
|
|
64
|
+
if (File.Exists(outputPath) && !request.Overwrite)
|
|
65
|
+
throw new UnityCliBridge.BridgeCommandException("E_OUTPUT_EXISTS", "Screenshot output already exists: " + outputPath, "Pass overwrite=true or choose a different output path.");
|
|
66
|
+
var captureBudget = ScreenshotToolSupport.PrepareCaptureBudget(width, height, 1, false, request.Limits, requestBudget);
|
|
60
67
|
ctx.CommitEffect();
|
|
61
|
-
return new System.Threading.Tasks.ValueTask<CameraCapture>(CameraToolSupport.CaptureCamera(camera, width, height, request.Transparent, quality, outputPath, format, request.Overwrite, request.InlineBase64));
|
|
68
|
+
return new System.Threading.Tasks.ValueTask<CameraCapture>(CameraToolSupport.CaptureCamera(camera, width, height, request.Transparent, quality, outputPath, format, request.Overwrite, request.InlineBase64, captureBudget));
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
71
|
}
|