@alpsckr/unitycli 0.4.2 → 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 +35 -42
- 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
|
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|
|
5
5
|
using System.Globalization;
|
|
6
6
|
using System.Linq;
|
|
7
7
|
using System.Reflection;
|
|
8
|
+
using System.Text;
|
|
8
9
|
using UnityEditor;
|
|
9
10
|
using UnityEngine;
|
|
10
11
|
|
|
@@ -15,26 +16,100 @@ namespace UnityCli
|
|
|
15
16
|
/// <summary>类型 JSON Schema 生成器:为 live C# / Unity 类型生成带 $defs 的结构化 schema。</summary>
|
|
16
17
|
internal static class TypeSchemaGenerator
|
|
17
18
|
{
|
|
18
|
-
|
|
19
|
+
private const int MaximumSchemaMemberCandidates = 1024;
|
|
20
|
+
private const int MaximumSchemaMemberMetadataUtf8Bytes = 64 * 1024;
|
|
21
|
+
private const int MaximumSchemaCachedTypes = 128;
|
|
22
|
+
private const int MaximumTypeHierarchyDepth = 32;
|
|
23
|
+
private const int MaximumInterfaces = 256;
|
|
24
|
+
private static readonly Dictionary<string, Type> ResolvedTypeCache = new Dictionary<string, Type>(StringComparer.Ordinal);
|
|
25
|
+
private static readonly Dictionary<Type, SchemaMemberCandidate[]> SchemaMemberCache = new Dictionary<Type, SchemaMemberCandidate[]>();
|
|
26
|
+
private static string cacheGeneration;
|
|
27
|
+
|
|
28
|
+
internal sealed class Page
|
|
19
29
|
{
|
|
20
|
-
|
|
30
|
+
internal Dictionary<string, object> Data;
|
|
31
|
+
internal bool Truncated;
|
|
32
|
+
internal string NextCursor;
|
|
33
|
+
internal string Generation;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// <summary>根类型先走统一分类;只有 object member 才按 generation-bound raw ordinal 分页。</summary>
|
|
37
|
+
public static Page Generate(string typeName, int maxDepth, int maxMembers, int maxDefinitions, int pageSize, string cursor, UnityCliRequestBudget budget)
|
|
38
|
+
{
|
|
39
|
+
var type = ResolveType(typeName, budget);
|
|
21
40
|
if (type == null)
|
|
22
41
|
{
|
|
23
|
-
throw new
|
|
24
|
-
|
|
42
|
+
if (budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
43
|
+
throw new BridgeCommandException("E_TYPE_NOT_FOUND", "Type not found: " + typeName, "Pass a full type name such as UnityEngine.Transform or UnityEngine.Rigidbody.");
|
|
44
|
+
}
|
|
45
|
+
var context = new SchemaContext(type, maxDepth, maxMembers, maxDefinitions, budget);
|
|
46
|
+
var generation = UnityCliContinuationToken.Fingerprint(UnityCliReadGeneration.Reflection() + "\0" + type.AssemblyQualifiedName + "\0"
|
|
47
|
+
+ maxDepth.ToString(CultureInfo.InvariantCulture) + "\0" + maxMembers.ToString(CultureInfo.InvariantCulture) + "\0" + maxDefinitions.ToString(CultureInfo.InvariantCulture));
|
|
48
|
+
if (!IsObjectSchemaRoot(type, context))
|
|
49
|
+
{
|
|
50
|
+
if (!string.IsNullOrEmpty(cursor)) throw StaleSchemaCursor();
|
|
51
|
+
var rootSchema = BuildSchema(type, context, 0, true);
|
|
52
|
+
return new Page
|
|
53
|
+
{
|
|
54
|
+
Truncated = context.Truncated,
|
|
55
|
+
NextCursor = null,
|
|
56
|
+
Generation = generation,
|
|
57
|
+
Data = new Dictionary<string, object>
|
|
58
|
+
{
|
|
59
|
+
{ "command", "type.schema" }, { "typeName", FriendlyTypeName(type, context) }, { "schema", rootSchema },
|
|
60
|
+
{ "memberCount", 0L }, { "returnedMemberCount", 0L }, { "definitionCount", (long)context.Definitions.Count }
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var members = GetSchemaMemberCandidates(type, budget);
|
|
66
|
+
generation = UnityCliContinuationToken.Fingerprint(generation + "\0" + SchemaMemberFingerprint(members));
|
|
67
|
+
var index = 0;
|
|
68
|
+
if (!string.IsNullOrEmpty(cursor)) ParseSchemaCursor(cursor, generation, members.Length, out index);
|
|
69
|
+
var rootProperties = new Dictionary<string, object>();
|
|
70
|
+
while (index < members.Length && rootProperties.Count < pageSize)
|
|
71
|
+
{
|
|
72
|
+
if (!context.TryMember()) break;
|
|
73
|
+
var member = members[index];
|
|
74
|
+
if (!budget.TryConsumeReflectionCall() || !budget.TryReserveSerializedUtf8(member.Name)) break;
|
|
75
|
+
rootProperties[member.Name] = SchemaFor(member.ValueType, context, 1);
|
|
76
|
+
index++;
|
|
77
|
+
if (budget.IsExhausted) break;
|
|
25
78
|
}
|
|
26
|
-
|
|
27
|
-
var
|
|
28
|
-
|
|
79
|
+
if (rootProperties.Count == 0 && index < members.Length) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension ?? "scannedRecords");
|
|
80
|
+
var typeDisplayName = FriendlyTypeName(type, context);
|
|
81
|
+
var schema = new Dictionary<string, object> { { "type", "object" }, { "typeName", typeDisplayName }, { "properties", rootProperties } };
|
|
82
|
+
if (context.Definitions.Count > 0) schema["$defs"] = context.Definitions;
|
|
83
|
+
var next = index < members.Length ? UnityCliContinuationToken.Create("type.schema", generation, "member:" + index.ToString(CultureInfo.InvariantCulture)) : null;
|
|
84
|
+
return new Page
|
|
29
85
|
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
{
|
|
86
|
+
Truncated = next != null || context.Truncated,
|
|
87
|
+
NextCursor = next,
|
|
88
|
+
Generation = generation,
|
|
89
|
+
Data = new Dictionary<string, object>
|
|
90
|
+
{
|
|
91
|
+
{ "command", "type.schema" }, { "typeName", typeDisplayName }, { "schema", schema },
|
|
92
|
+
{ "memberCount", (long)members.Length }, { "returnedMemberCount", (long)rootProperties.Count },
|
|
93
|
+
{ "definitionCount", (long)context.Definitions.Count }
|
|
94
|
+
}
|
|
35
95
|
};
|
|
36
96
|
}
|
|
37
97
|
|
|
98
|
+
private static void ParseSchemaCursor(string cursor, string generation, int memberCount, out int index)
|
|
99
|
+
{
|
|
100
|
+
string position;
|
|
101
|
+
index = -1;
|
|
102
|
+
if (!UnityCliContinuationToken.TryParse(cursor, "type.schema", generation, out position)
|
|
103
|
+
|| !position.StartsWith("member:", StringComparison.Ordinal)
|
|
104
|
+
|| !int.TryParse(position.Substring(7), NumberStyles.Integer, CultureInfo.InvariantCulture, out index)
|
|
105
|
+
|| index < 0 || index > memberCount) throw StaleSchemaCursor();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private static BridgeCommandException StaleSchemaCursor()
|
|
109
|
+
{
|
|
110
|
+
return new BridgeCommandException("E_CONTINUATION_STALE", "The type.schema continuation does not match the current assembly generation and limits.", "Start a new type.schema read without cursor.");
|
|
111
|
+
}
|
|
112
|
+
|
|
38
113
|
/// <summary>递归生成 schema;复杂嵌套类型通过 $defs/$ref 去重,避免循环类型无限展开。</summary>
|
|
39
114
|
private static Dictionary<string, object> BuildSchema(Type type, SchemaContext context, int depth, bool isRoot)
|
|
40
115
|
{
|
|
@@ -46,55 +121,71 @@ namespace UnityCli
|
|
|
46
121
|
/// <summary>按类型类别构造 JSON Schema 字段。</summary>
|
|
47
122
|
private static Dictionary<string, object> SchemaProperties(Type type, SchemaContext context, int depth)
|
|
48
123
|
{
|
|
124
|
+
if (!context.Budget.TryConsumeNode()) { context.Truncated = true; return TruncatedSchema(type, context); }
|
|
49
125
|
if (type == null) return new Dictionary<string, object> { { "type", "null" } };
|
|
50
|
-
if (type.IsByRef || type.IsPointer) return new Dictionary<string, object> { { "type", "string" }, { "typeName", FriendlyTypeName(type) } };
|
|
126
|
+
if (type.IsByRef || type.IsPointer) return new Dictionary<string, object> { { "type", "string" }, { "typeName", FriendlyTypeName(type, context) } };
|
|
51
127
|
if (type.IsGenericParameter) return new Dictionary<string, object> { { "type", "object" }, { "typeName", type.Name }, { "genericParameter", true } };
|
|
52
128
|
if (IsNullable(type))
|
|
53
129
|
{
|
|
54
130
|
return new Dictionary<string, object>
|
|
55
131
|
{
|
|
56
132
|
{ "anyOf", new List<object> { SchemaFor(Nullable.GetUnderlyingType(type), context, depth + 1), new Dictionary<string, object> { { "type", "null" } } } },
|
|
57
|
-
{ "typeName", FriendlyTypeName(type) }
|
|
133
|
+
{ "typeName", FriendlyTypeName(type, context) }
|
|
58
134
|
};
|
|
59
135
|
}
|
|
60
|
-
if (IsPrimitiveLike(type)) return new Dictionary<string, object> { { "type", JsonTypeFor(type) }, { "typeName", FriendlyTypeName(type) } };
|
|
61
|
-
if (type.IsEnum)
|
|
136
|
+
if (IsPrimitiveLike(type)) return new Dictionary<string, object> { { "type", JsonTypeFor(type) }, { "typeName", FriendlyTypeName(type, context) } };
|
|
137
|
+
if (type.IsEnum)
|
|
138
|
+
{
|
|
139
|
+
if (!context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; return TruncatedSchema(type, context); }
|
|
140
|
+
var values = new List<object>();
|
|
141
|
+
foreach (var value in UnityCliReflectionSnapshot.EnumNames(type, context.Budget, MaximumSchemaMemberCandidates))
|
|
142
|
+
{
|
|
143
|
+
if (!context.TryMember() || !context.Budget.TryReserveSerializedUtf8(value)) { context.Truncated = true; break; }
|
|
144
|
+
values.Add(value);
|
|
145
|
+
}
|
|
146
|
+
var enumSchema = new Dictionary<string, object>
|
|
147
|
+
{
|
|
148
|
+
{ "type", "string" }, { "typeName", FriendlyTypeName(type, context) }, { "enum", values },
|
|
149
|
+
{ "truncated", context.Truncated }, { "continuationSupported", false }
|
|
150
|
+
};
|
|
151
|
+
if (context.Truncated) enumSchema["truncationReason"] = "non-resumable-enum-truncation";
|
|
152
|
+
return enumSchema;
|
|
153
|
+
}
|
|
62
154
|
|
|
63
|
-
if (TryGetDictionaryTypes(type, out var keyType, out var dictionaryValueType))
|
|
155
|
+
if (TryGetDictionaryTypes(type, context, out var keyType, out var dictionaryValueType))
|
|
64
156
|
{
|
|
65
|
-
var dictionarySchema = new Dictionary<string, object> { { "type", "object" }, { "typeName", FriendlyTypeName(type) } };
|
|
66
|
-
WriteGenericMetadata(dictionarySchema, type);
|
|
67
|
-
dictionarySchema["propertyNames"] = DictionaryKeySchema(keyType);
|
|
68
|
-
dictionarySchema["additionalProperties"] = depth >= context.MaxDepth ? TruncatedSchema(dictionaryValueType) : SchemaFor(dictionaryValueType, context, depth + 1);
|
|
157
|
+
var dictionarySchema = new Dictionary<string, object> { { "type", "object" }, { "typeName", FriendlyTypeName(type, context) } };
|
|
158
|
+
WriteGenericMetadata(dictionarySchema, type, context);
|
|
159
|
+
dictionarySchema["propertyNames"] = DictionaryKeySchema(keyType, context);
|
|
160
|
+
dictionarySchema["additionalProperties"] = depth >= context.MaxDepth ? TruncatedSchema(dictionaryValueType, context) : SchemaFor(dictionaryValueType, context, depth + 1);
|
|
69
161
|
return dictionarySchema;
|
|
70
162
|
}
|
|
71
163
|
|
|
72
|
-
var elementType = GetEnumerableElementType(type);
|
|
164
|
+
var elementType = GetEnumerableElementType(type, context);
|
|
73
165
|
if (elementType != null)
|
|
74
166
|
{
|
|
75
|
-
var arraySchema = new Dictionary<string, object> { { "type", "array" }, { "typeName", FriendlyTypeName(type) } };
|
|
167
|
+
var arraySchema = new Dictionary<string, object> { { "type", "array" }, { "typeName", FriendlyTypeName(type, context) } };
|
|
76
168
|
if (type.IsArray) arraySchema["arrayRank"] = (long)type.GetArrayRank();
|
|
77
|
-
WriteGenericMetadata(arraySchema, type);
|
|
78
|
-
arraySchema["items"] = depth >= context.MaxDepth ? TruncatedSchema(elementType) : SchemaFor(elementType, context, depth + 1);
|
|
169
|
+
WriteGenericMetadata(arraySchema, type, context);
|
|
170
|
+
arraySchema["items"] = depth >= context.MaxDepth ? TruncatedSchema(elementType, context) : SchemaFor(elementType, context, depth + 1);
|
|
79
171
|
return arraySchema;
|
|
80
172
|
}
|
|
81
173
|
|
|
82
|
-
var objectSchema = new Dictionary<string, object> { { "type", "object" }, { "typeName", FriendlyTypeName(type) } };
|
|
83
|
-
WriteGenericMetadata(objectSchema, type);
|
|
174
|
+
var objectSchema = new Dictionary<string, object> { { "type", "object" }, { "typeName", FriendlyTypeName(type, context) } };
|
|
175
|
+
WriteGenericMetadata(objectSchema, type, context);
|
|
84
176
|
if (depth >= context.MaxDepth)
|
|
85
177
|
{
|
|
86
178
|
objectSchema["truncated"] = true;
|
|
87
179
|
return objectSchema;
|
|
88
180
|
}
|
|
89
181
|
var properties = new Dictionary<string, object>();
|
|
90
|
-
foreach (var
|
|
91
|
-
{
|
|
92
|
-
properties[field.Name] = SchemaFor(field.FieldType, context, depth + 1);
|
|
93
|
-
}
|
|
94
|
-
foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public).OrderBy(p => p.Name, StringComparer.Ordinal))
|
|
182
|
+
foreach (var member in GetSchemaMemberCandidates(type, context.Budget))
|
|
95
183
|
{
|
|
96
|
-
if (
|
|
184
|
+
if (!context.TryMember() || !context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; break; }
|
|
185
|
+
properties[member.Name] = SchemaFor(member.ValueType, context, depth + 1);
|
|
186
|
+
if (context.Budget.IsExhausted) break;
|
|
97
187
|
}
|
|
188
|
+
if (context.Truncated) objectSchema["truncated"] = true;
|
|
98
189
|
objectSchema["properties"] = properties;
|
|
99
190
|
return objectSchema;
|
|
100
191
|
}
|
|
@@ -102,14 +193,21 @@ namespace UnityCli
|
|
|
102
193
|
/// <summary>复杂类型使用 $ref,基础/集合类型直接内联。</summary>
|
|
103
194
|
private static object SchemaFor(Type type, SchemaContext context, int depth)
|
|
104
195
|
{
|
|
105
|
-
if (type == null || IsPrimitiveLike(type) || type.IsEnum || type.IsByRef || type.IsPointer || type.IsGenericParameter || IsNullable(type)
|
|
196
|
+
if (type == null || IsPrimitiveLike(type) || type.IsEnum || type.IsByRef || type.IsPointer || type.IsGenericParameter || IsNullable(type)
|
|
197
|
+
|| TryGetDictionaryTypes(type, context, out _, out _) || GetEnumerableElementType(type, context) != null)
|
|
106
198
|
{
|
|
107
199
|
return BuildSchema(type, context, depth, false);
|
|
108
200
|
}
|
|
109
201
|
if (type == context.RootType) return new Dictionary<string, object> { { "$ref", "#" } };
|
|
110
|
-
var key = DefinitionKey(type);
|
|
202
|
+
var key = DefinitionKey(type, context);
|
|
111
203
|
if (!context.Definitions.ContainsKey(key) && !context.BuildingDefinitions.Contains(key))
|
|
112
204
|
{
|
|
205
|
+
if (!context.Budget.TryReserveSerializedUtf8(key)) { context.Truncated = true; return TruncatedSchema(type, context); }
|
|
206
|
+
if (context.Definitions.Count >= context.MaxDefinitions || !context.Budget.TryConsumeReflectionCall())
|
|
207
|
+
{
|
|
208
|
+
context.Truncated = true;
|
|
209
|
+
return TruncatedSchema(type, context);
|
|
210
|
+
}
|
|
113
211
|
context.BuildingDefinitions.Add(key);
|
|
114
212
|
context.Definitions[key] = BuildSchema(type, context, depth, false);
|
|
115
213
|
context.BuildingDefinitions.Remove(key);
|
|
@@ -117,59 +215,101 @@ namespace UnityCli
|
|
|
117
215
|
return new Dictionary<string, object> { { "$ref", "#/$defs/" + key } };
|
|
118
216
|
}
|
|
119
217
|
|
|
120
|
-
private static Dictionary<string, object> DictionaryKeySchema(Type keyType)
|
|
218
|
+
private static Dictionary<string, object> DictionaryKeySchema(Type keyType, SchemaContext context)
|
|
121
219
|
{
|
|
122
220
|
var schema = new Dictionary<string, object> { { "type", "string" } };
|
|
123
|
-
if (keyType != null && keyType.IsEnum)
|
|
124
|
-
|
|
221
|
+
if (keyType != null && keyType.IsEnum)
|
|
222
|
+
{
|
|
223
|
+
if (!context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; schema["truncated"] = true; return schema; }
|
|
224
|
+
var values = new List<object>();
|
|
225
|
+
foreach (var value in UnityCliReflectionSnapshot.EnumNames(keyType, context.Budget, MaximumSchemaMemberCandidates))
|
|
226
|
+
{
|
|
227
|
+
if (!context.TryMember() || !context.Budget.TryReserveSerializedUtf8(value)) { context.Truncated = true; schema["truncated"] = true; break; }
|
|
228
|
+
values.Add(value);
|
|
229
|
+
}
|
|
230
|
+
schema["enum"] = values;
|
|
231
|
+
}
|
|
232
|
+
else if (keyType != null) schema["typeName"] = FriendlyTypeName(keyType, context);
|
|
125
233
|
return schema;
|
|
126
234
|
}
|
|
127
235
|
|
|
128
|
-
private static Dictionary<string, object> TruncatedSchema(Type type)
|
|
236
|
+
private static Dictionary<string, object> TruncatedSchema(Type type, SchemaContext context)
|
|
129
237
|
{
|
|
130
|
-
return new Dictionary<string, object> { { "type", "object" }, { "typeName", FriendlyTypeName(type) }, { "truncated", true } };
|
|
238
|
+
return new Dictionary<string, object> { { "type", "object" }, { "typeName", FriendlyTypeName(type, context) }, { "truncated", true } };
|
|
131
239
|
}
|
|
132
240
|
|
|
133
|
-
private static void WriteGenericMetadata(Dictionary<string, object> schema, Type type)
|
|
241
|
+
private static void WriteGenericMetadata(Dictionary<string, object> schema, Type type, SchemaContext context)
|
|
134
242
|
{
|
|
135
243
|
if (!type.IsGenericType) return;
|
|
136
|
-
schema["
|
|
137
|
-
schema["
|
|
244
|
+
if (!context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; schema["truncated"] = true; return; }
|
|
245
|
+
schema["genericTypeDefinition"] = FriendlyTypeName(type.GetGenericTypeDefinition(), context);
|
|
246
|
+
var values = new List<object>();
|
|
247
|
+
foreach (var argument in UnityCliReflectionSnapshot.GenericArguments(type, context.Budget, MaximumTypeHierarchyDepth))
|
|
248
|
+
{
|
|
249
|
+
if (!context.TryMember()) { context.Truncated = true; schema["truncated"] = true; break; }
|
|
250
|
+
values.Add(FriendlyTypeName(argument, context));
|
|
251
|
+
if (context.Budget.IsExhausted) { context.Truncated = true; schema["truncated"] = true; break; }
|
|
252
|
+
}
|
|
253
|
+
schema["genericArguments"] = values;
|
|
138
254
|
}
|
|
139
255
|
|
|
140
|
-
private static bool TryGetDictionaryTypes(Type type, out Type keyType, out Type valueType)
|
|
256
|
+
private static bool TryGetDictionaryTypes(Type type, SchemaContext context, out Type keyType, out Type valueType)
|
|
141
257
|
{
|
|
142
258
|
keyType = null;
|
|
143
259
|
valueType = null;
|
|
144
260
|
if (type == null || type == typeof(string)) return false;
|
|
145
|
-
|
|
261
|
+
if (!context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; return false; }
|
|
262
|
+
if (TryGetDictionaryCandidate(type, context, out keyType, out valueType)) return true;
|
|
263
|
+
var examined = 0;
|
|
264
|
+
foreach (var candidate in UnityCliReflectionSnapshot.Interfaces(type, context.Budget, MaximumInterfaces))
|
|
146
265
|
{
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (
|
|
150
|
-
{
|
|
151
|
-
var args = candidate.GetGenericArguments();
|
|
152
|
-
keyType = args[0];
|
|
153
|
-
valueType = args[1];
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
266
|
+
examined++;
|
|
267
|
+
if (!context.Budget.TryConsumeScannedRecord() || !context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; return false; }
|
|
268
|
+
if (TryGetDictionaryCandidate(candidate, context, out keyType, out valueType)) return true;
|
|
156
269
|
}
|
|
157
270
|
return false;
|
|
158
271
|
}
|
|
159
272
|
|
|
160
|
-
private static
|
|
273
|
+
private static bool TryGetDictionaryCandidate(Type candidate, SchemaContext context, out Type keyType, out Type valueType)
|
|
274
|
+
{
|
|
275
|
+
keyType = null;
|
|
276
|
+
valueType = null;
|
|
277
|
+
if (!candidate.IsGenericType) return false;
|
|
278
|
+
var definition = candidate.GetGenericTypeDefinition();
|
|
279
|
+
if (definition != typeof(IDictionary<,>) && definition != typeof(IReadOnlyDictionary<,>)) return false;
|
|
280
|
+
var arguments = UnityCliReflectionSnapshot.GenericArguments(candidate, context.Budget, 2);
|
|
281
|
+
keyType = arguments[0];
|
|
282
|
+
valueType = arguments[1];
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
private static Type GetEnumerableElementType(Type type, SchemaContext context)
|
|
161
287
|
{
|
|
162
288
|
if (type == null || type == typeof(string)) return null;
|
|
289
|
+
if (!context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; return null; }
|
|
163
290
|
if (type.IsArray) return type.GetElementType();
|
|
164
|
-
|
|
291
|
+
var direct = GetEnumerableCandidate(type, context);
|
|
292
|
+
if (direct != null) return direct;
|
|
293
|
+
var examined = 0;
|
|
294
|
+
foreach (var candidate in UnityCliReflectionSnapshot.Interfaces(type, context.Budget, MaximumInterfaces))
|
|
165
295
|
{
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
296
|
+
examined++;
|
|
297
|
+
if (!context.Budget.TryConsumeScannedRecord() || !context.Budget.TryConsumeReflectionCall()) { context.Truncated = true; return null; }
|
|
298
|
+
var element = GetEnumerableCandidate(candidate, context);
|
|
299
|
+
if (element != null) return element;
|
|
169
300
|
}
|
|
170
301
|
return typeof(IEnumerable).IsAssignableFrom(type) ? typeof(object) : null;
|
|
171
302
|
}
|
|
172
303
|
|
|
304
|
+
private static Type GetEnumerableCandidate(Type candidate, SchemaContext context)
|
|
305
|
+
{
|
|
306
|
+
if (!candidate.IsGenericType) return null;
|
|
307
|
+
var definition = candidate.GetGenericTypeDefinition();
|
|
308
|
+
return definition == typeof(IEnumerable<>) || definition == typeof(IList<>) || definition == typeof(ICollection<>)
|
|
309
|
+
? UnityCliReflectionSnapshot.GenericArguments(candidate, context.Budget, 1)[0]
|
|
310
|
+
: null;
|
|
311
|
+
}
|
|
312
|
+
|
|
173
313
|
private static string JsonTypeFor(Type type)
|
|
174
314
|
{
|
|
175
315
|
if (type == typeof(bool)) return "boolean";
|
|
@@ -182,56 +322,265 @@ namespace UnityCli
|
|
|
182
322
|
private static bool IsPrimitiveLike(Type type) => type.IsPrimitive || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime);
|
|
183
323
|
private static bool IsNullable(Type type) => type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
|
184
324
|
|
|
185
|
-
private static
|
|
325
|
+
private static bool IsObjectSchemaRoot(Type type, SchemaContext context)
|
|
326
|
+
{
|
|
327
|
+
if (!context.Budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(context.Budget.ExhaustedDimension);
|
|
328
|
+
if (type == null || type.IsByRef || type.IsPointer || type.IsGenericParameter || IsNullable(type) || IsPrimitiveLike(type) || type.IsEnum) return false;
|
|
329
|
+
if (TryGetDictionaryTypes(type, context, out _, out _)) return false;
|
|
330
|
+
if (context.Budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(context.Budget.ExhaustedDimension);
|
|
331
|
+
if (GetEnumerableElementType(type, context) != null) return false;
|
|
332
|
+
if (context.Budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(context.Budget.ExhaustedDimension);
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/// <summary>候选 metadata 按 reflection generation 缓存,构建与命中都对每个已检查成员计费。</summary>
|
|
337
|
+
private static SchemaMemberCandidate[] GetSchemaMemberCandidates(Type type, UnityCliRequestBudget budget)
|
|
338
|
+
{
|
|
339
|
+
var generation = UnityCliReadGeneration.Reflection();
|
|
340
|
+
if (!string.Equals(cacheGeneration, generation, StringComparison.Ordinal))
|
|
341
|
+
{
|
|
342
|
+
ResolvedTypeCache.Clear();
|
|
343
|
+
SchemaMemberCache.Clear();
|
|
344
|
+
cacheGeneration = generation;
|
|
345
|
+
}
|
|
346
|
+
SchemaMemberCandidate[] cached;
|
|
347
|
+
if (SchemaMemberCache.TryGetValue(type, out cached))
|
|
348
|
+
{
|
|
349
|
+
if (!budget.TryConsumeScannedRecords(cached.Length) || !budget.TryConsumeReflectionCalls(cached.Length))
|
|
350
|
+
throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
351
|
+
return cached;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
var candidates = new Dictionary<string, SchemaMemberCandidate>(StringComparer.Ordinal);
|
|
355
|
+
var examined = 0;
|
|
356
|
+
var metadataBytes = 0;
|
|
357
|
+
var depth = 0;
|
|
358
|
+
for (var current = type; current != null && current != typeof(object); current = current.BaseType)
|
|
359
|
+
{
|
|
360
|
+
if (depth++ >= MaximumTypeHierarchyDepth) throw new UnityCliRequestBudgetExceededException("reflectionCalls");
|
|
361
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
362
|
+
foreach (var field in UnityCliReflectionSnapshot.DeclaredFields(current, budget, MaximumSchemaMemberCandidates))
|
|
363
|
+
{
|
|
364
|
+
ConsumeSchemaMemberMetadata(field.Name, field.FieldType, budget, ref examined, ref metadataBytes);
|
|
365
|
+
if (!field.IsPublic || field.IsStatic || candidates.ContainsKey(field.Name)) continue;
|
|
366
|
+
candidates[field.Name] = new SchemaMemberCandidate(field.Name, field.FieldType, depth, false);
|
|
367
|
+
}
|
|
368
|
+
foreach (var property in UnityCliReflectionSnapshot.DeclaredProperties(current, budget, MaximumSchemaMemberCandidates))
|
|
369
|
+
{
|
|
370
|
+
ConsumeSchemaMemberMetadata(property.Name, property.PropertyType, budget, ref examined, ref metadataBytes);
|
|
371
|
+
var getter = property.GetGetMethod(false);
|
|
372
|
+
if (getter == null || getter.IsStatic || property.GetIndexParameters().Length != 0) continue;
|
|
373
|
+
SchemaMemberCandidate existing;
|
|
374
|
+
if (candidates.TryGetValue(property.Name, out existing) && existing.Depth != depth) continue;
|
|
375
|
+
candidates[property.Name] = new SchemaMemberCandidate(property.Name, property.PropertyType, depth, true);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
var result = candidates.Values.OrderBy(candidate => candidate.Name, StringComparer.Ordinal).ToArray();
|
|
379
|
+
if (SchemaMemberCache.Count >= MaximumSchemaCachedTypes) SchemaMemberCache.Clear();
|
|
380
|
+
SchemaMemberCache[type] = result;
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private static void ConsumeSchemaMemberMetadata(string name, Type valueType, UnityCliRequestBudget budget, ref int examined, ref int metadataBytes)
|
|
385
|
+
{
|
|
386
|
+
if (examined++ >= MaximumSchemaMemberCandidates) throw new UnityCliRequestBudgetExceededException("scannedRecords");
|
|
387
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
388
|
+
metadataBytes += Encoding.UTF8.GetByteCount(name ?? string.Empty);
|
|
389
|
+
metadataBytes += Encoding.UTF8.GetByteCount(valueType == null ? string.Empty : valueType.AssemblyQualifiedName ?? valueType.Name);
|
|
390
|
+
if (metadataBytes > MaximumSchemaMemberMetadataUtf8Bytes) throw new UnityCliRequestBudgetExceededException("serializedUtf8Bytes");
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private static string SchemaMemberFingerprint(IEnumerable<SchemaMemberCandidate> members)
|
|
394
|
+
{
|
|
395
|
+
var builder = new StringBuilder();
|
|
396
|
+
foreach (var member in members) builder.Append(member.Name).Append('\0').Append(member.ValueType == null ? string.Empty : member.ValueType.AssemblyQualifiedName).Append('\0');
|
|
397
|
+
return UnityCliContinuationToken.Fingerprint(builder.ToString());
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private sealed class SchemaMemberCandidate
|
|
401
|
+
{
|
|
402
|
+
internal readonly string Name;
|
|
403
|
+
internal readonly Type ValueType;
|
|
404
|
+
internal readonly int Depth;
|
|
405
|
+
internal readonly bool IsProperty;
|
|
406
|
+
|
|
407
|
+
internal SchemaMemberCandidate(string name, Type valueType, int depth, bool isProperty)
|
|
408
|
+
{
|
|
409
|
+
Name = name;
|
|
410
|
+
ValueType = valueType;
|
|
411
|
+
Depth = depth;
|
|
412
|
+
IsProperty = isProperty;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private static string FriendlyTypeName(Type type, SchemaContext context, int depth = 0)
|
|
186
417
|
{
|
|
187
418
|
if (type == null) return null;
|
|
188
|
-
if (
|
|
189
|
-
if (!
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (
|
|
193
|
-
|
|
419
|
+
if (depth >= MaximumTypeHierarchyDepth) throw new UnityCliRequestBudgetExceededException("reflectionCalls");
|
|
420
|
+
if (!context.Budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(context.Budget.ExhaustedDimension);
|
|
421
|
+
string value;
|
|
422
|
+
if (type.IsArray) value = FriendlyTypeName(type.GetElementType(), context, depth + 1) + "[]";
|
|
423
|
+
else if (!type.IsGenericType) value = type.FullName ?? type.Name;
|
|
424
|
+
else
|
|
425
|
+
{
|
|
426
|
+
var definition = type.GetGenericTypeDefinition();
|
|
427
|
+
var baseName = definition.FullName ?? definition.Name;
|
|
428
|
+
var tick = baseName.IndexOf('`');
|
|
429
|
+
if (tick >= 0) baseName = baseName.Substring(0, tick);
|
|
430
|
+
var arguments = UnityCliReflectionSnapshot.GenericArguments(type, context.Budget, MaximumTypeHierarchyDepth);
|
|
431
|
+
var names = new string[arguments.Length];
|
|
432
|
+
for (var index = 0; index < arguments.Length; index++) names[index] = FriendlyTypeName(arguments[index], context, depth + 1);
|
|
433
|
+
value = baseName + "<" + string.Join(",", names) + ">";
|
|
434
|
+
}
|
|
435
|
+
if (!context.Budget.TryReserveSerializedUtf8(value)) throw new UnityCliRequestBudgetExceededException(context.Budget.ExhaustedDimension);
|
|
436
|
+
return value;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private static string DefinitionKey(Type type, SchemaContext context)
|
|
440
|
+
{
|
|
441
|
+
var value = FriendlyTypeName(type, context) ?? "Unknown";
|
|
442
|
+
var characters = value.ToCharArray();
|
|
443
|
+
for (var index = 0; index < characters.Length; index++) if (!char.IsLetterOrDigit(characters[index])) characters[index] = '_';
|
|
444
|
+
return new string(characters);
|
|
194
445
|
}
|
|
195
446
|
|
|
196
|
-
|
|
197
|
-
|
|
447
|
+
internal static Type ResolveType(string fullName)
|
|
448
|
+
{
|
|
449
|
+
return FindType(fullName);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/// <summary>assembly generation 改变时整体失效;命中缓存不再重复扫描 AppDomain。</summary>
|
|
453
|
+
internal static Type ResolveType(string fullName, UnityCliRequestBudget budget)
|
|
454
|
+
{
|
|
455
|
+
if (string.IsNullOrEmpty(fullName)) return null;
|
|
456
|
+
var generation = UnityCliReadGeneration.Reflection();
|
|
457
|
+
if (!string.Equals(cacheGeneration, generation, StringComparison.Ordinal))
|
|
458
|
+
{
|
|
459
|
+
ResolvedTypeCache.Clear();
|
|
460
|
+
SchemaMemberCache.Clear();
|
|
461
|
+
cacheGeneration = generation;
|
|
462
|
+
}
|
|
463
|
+
Type cached;
|
|
464
|
+
if (ResolvedTypeCache.TryGetValue(fullName, out cached)) return cached;
|
|
465
|
+
if (!budget.TryConsumeReflectionCall()) return null;
|
|
466
|
+
try { cached = Type.GetType(fullName, false); } catch { cached = null; }
|
|
467
|
+
if (cached == null)
|
|
468
|
+
{
|
|
469
|
+
foreach (var assembly in UnityCliAssemblySnapshot.Get(budget))
|
|
470
|
+
{
|
|
471
|
+
if (!budget.TryConsumeReflectionCall()) return null;
|
|
472
|
+
try { cached = assembly.GetType(fullName, false); } catch { cached = null; }
|
|
473
|
+
if (cached != null) break;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (cached != null) ResolvedTypeCache[fullName] = cached;
|
|
477
|
+
return cached;
|
|
478
|
+
}
|
|
198
479
|
|
|
199
480
|
private sealed class SchemaContext
|
|
200
481
|
{
|
|
201
482
|
public readonly Type RootType;
|
|
202
483
|
public readonly int MaxDepth;
|
|
484
|
+
public readonly int MaxMembers;
|
|
485
|
+
public readonly int MaxDefinitions;
|
|
486
|
+
public readonly UnityCliRequestBudget Budget;
|
|
203
487
|
public readonly Dictionary<string, object> Definitions = new Dictionary<string, object>();
|
|
204
488
|
public readonly HashSet<string> BuildingDefinitions = new HashSet<string>();
|
|
205
|
-
public
|
|
489
|
+
public int MemberCount;
|
|
490
|
+
public bool Truncated;
|
|
491
|
+
|
|
492
|
+
public SchemaContext(Type rootType, int maxDepth, int maxMembers, int maxDefinitions, UnityCliRequestBudget budget)
|
|
493
|
+
{
|
|
494
|
+
RootType = rootType; MaxDepth = maxDepth; MaxMembers = maxMembers; MaxDefinitions = maxDefinitions; Budget = budget;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
public bool TryMember()
|
|
498
|
+
{
|
|
499
|
+
if (MemberCount >= MaxMembers) { Truncated = true; return false; }
|
|
500
|
+
MemberCount++;
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
206
503
|
}
|
|
207
504
|
}
|
|
208
505
|
|
|
209
506
|
/// <summary>反射方法查找与调用:不限制 public/private/static/instance/namespace/assembly/Editor/Runtime 范围。</summary>
|
|
210
507
|
internal static class ReflectionInvoker
|
|
211
508
|
{
|
|
212
|
-
|
|
509
|
+
private const int MaximumExaminedCallMethods = 4096;
|
|
510
|
+
private const int MaximumMatchingCallMethods = 128;
|
|
511
|
+
private const int MaximumCallParameters = 256;
|
|
512
|
+
private const int MaximumCallSignatureUtf8Bytes = 64 * 1024;
|
|
513
|
+
private const int MaximumCallTypeHierarchyDepth = 32;
|
|
514
|
+
|
|
515
|
+
internal sealed class MethodPage
|
|
516
|
+
{
|
|
517
|
+
internal List<ReflectionMethodDescriptor> Methods;
|
|
518
|
+
internal int Total;
|
|
519
|
+
internal string NextCursor;
|
|
520
|
+
internal string Generation;
|
|
521
|
+
internal bool Truncated;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/// <summary>MethodInfo array 是唯一 runtime reflection snapshot;过滤和 descriptor 从 raw ordinal 流式推进。</summary>
|
|
525
|
+
public static MethodPage FindMethods(string typeName, string methodName, BindingFlags bindings, int pageSize, string cursor, UnityCliRequestBudget budget)
|
|
213
526
|
{
|
|
214
|
-
var type = TypeSchemaGenerator.ResolveType(typeName);
|
|
215
|
-
if (type == null)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
527
|
+
var type = TypeSchemaGenerator.ResolveType(typeName, budget);
|
|
528
|
+
if (type == null)
|
|
529
|
+
{
|
|
530
|
+
if (budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
531
|
+
throw new BridgeCommandException("E_TYPE_NOT_FOUND", "Type not found: " + typeName, "Pass a full type name such as UnityEngine.Transform.");
|
|
532
|
+
}
|
|
533
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
534
|
+
var methods = UnityCliReflectionSnapshot.Methods(type, bindings, budget, MaximumExaminedCallMethods);
|
|
535
|
+
var generation = UnityCliContinuationToken.Fingerprint(UnityCliReadGeneration.Reflection() + "\0" + type.AssemblyQualifiedName + "\0"
|
|
536
|
+
+ ((int)bindings).ToString(CultureInfo.InvariantCulture) + "\0" + methodName + "\0" + methods.Length.ToString(CultureInfo.InvariantCulture));
|
|
537
|
+
var index = 0;
|
|
538
|
+
if (!string.IsNullOrEmpty(cursor))
|
|
539
|
+
{
|
|
540
|
+
string position;
|
|
541
|
+
if (!UnityCliContinuationToken.TryParse(cursor, "reflection.method.find", generation, out position)
|
|
542
|
+
|| !int.TryParse(position, NumberStyles.Integer, CultureInfo.InvariantCulture, out index) || index < 0 || index > methods.Length)
|
|
543
|
+
throw new BridgeCommandException("E_CONTINUATION_STALE", "The reflection method continuation does not match the current assembly generation and selector.", "Start a new reflection.method.find read without cursor.");
|
|
544
|
+
}
|
|
545
|
+
var pageStartIndex = index;
|
|
546
|
+
var result = new List<ReflectionMethodDescriptor>();
|
|
547
|
+
while (index < methods.Length && result.Count < pageSize)
|
|
548
|
+
{
|
|
549
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeReflectionCall()) break;
|
|
550
|
+
var method = methods[index];
|
|
551
|
+
var name = method.Name;
|
|
552
|
+
if (!string.IsNullOrEmpty(methodName) && !string.Equals(name, methodName, StringComparison.Ordinal)) { index++; continue; }
|
|
553
|
+
if (!budget.TryConsumeNode() || !budget.TryConsumeReflectionCall()) break;
|
|
554
|
+
var parameters = method.GetParameters();
|
|
555
|
+
var returnType = method.ReturnType == null ? null : method.ReturnType.FullName;
|
|
556
|
+
var declaringType = method.DeclaringType == null ? null : method.DeclaringType.FullName;
|
|
557
|
+
if (!budget.TryReserveSerializedUtf8(name) || !budget.TryReserveSerializedUtf8(returnType) || !budget.TryReserveSerializedUtf8(declaringType)) break;
|
|
558
|
+
var parameterResults = new List<ReflectionParameterDescriptor>();
|
|
559
|
+
var parametersComplete = true;
|
|
560
|
+
foreach (var parameter in parameters)
|
|
219
561
|
{
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
562
|
+
if (!budget.TryConsumeNode() || !budget.TryConsumeReflectionCall()) { parametersComplete = false; break; }
|
|
563
|
+
var parameterName = parameter.Name;
|
|
564
|
+
var parameterType = parameter.ParameterType == null ? null : parameter.ParameterType.FullName;
|
|
565
|
+
if (!budget.TryReserveSerializedUtf8(parameterName) || !budget.TryReserveSerializedUtf8(parameterType)) { parametersComplete = false; break; }
|
|
566
|
+
parameterResults.Add(new ReflectionParameterDescriptor { Name = parameterName, ParameterType = parameterType, HasDefaultValue = parameter.HasDefaultValue });
|
|
567
|
+
}
|
|
568
|
+
result.Add(new ReflectionMethodDescriptor
|
|
569
|
+
{
|
|
570
|
+
Name = name, IsStatic = method.IsStatic, IsPublic = method.IsPublic, IsPrivate = method.IsPrivate,
|
|
571
|
+
ReturnType = returnType, DeclaringType = declaringType, ParameterCount = parameters.Length,
|
|
572
|
+
ParametersTruncated = !parametersComplete, Parameters = parameterResults
|
|
573
|
+
});
|
|
574
|
+
index++;
|
|
575
|
+
if (!parametersComplete) break;
|
|
576
|
+
}
|
|
577
|
+
if (index == pageStartIndex && index < methods.Length)
|
|
578
|
+
throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension ?? "scannedRecords");
|
|
579
|
+
var next = index < methods.Length ? UnityCliContinuationToken.Create("reflection.method.find", generation, index.ToString(CultureInfo.InvariantCulture)) : null;
|
|
580
|
+
return new MethodPage { Methods = result, Total = methods.Length, NextCursor = next, Generation = generation, Truncated = next != null || budget.IsExhausted };
|
|
233
581
|
}
|
|
234
582
|
|
|
583
|
+
|
|
235
584
|
internal sealed class PreparedMethodCall
|
|
236
585
|
{
|
|
237
586
|
internal Type Type;
|
|
@@ -241,28 +590,50 @@ namespace UnityCli
|
|
|
241
590
|
internal object Instance;
|
|
242
591
|
}
|
|
243
592
|
|
|
244
|
-
/// <summary>effect
|
|
245
|
-
public static PreparedMethodCall PrepareCall(string typeName, string methodName, object argsValue, List<string> parameterTypes, Dictionary<string, object> instanceRef, BindingFlags bindings)
|
|
593
|
+
/// <summary>effect 前在同一 request budget 下解析 type、overload、参数与 instance;不会调用目标方法。</summary>
|
|
594
|
+
public static PreparedMethodCall PrepareCall(string typeName, string methodName, object argsValue, List<string> parameterTypes, Dictionary<string, object> instanceRef, BindingFlags bindings, UnityCliRequestBudget budget)
|
|
246
595
|
{
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
596
|
+
if (budget == null) throw new ArgumentNullException("budget");
|
|
597
|
+
var type = TypeSchemaGenerator.ResolveType(typeName, budget);
|
|
598
|
+
if (type == null)
|
|
599
|
+
{
|
|
600
|
+
if (budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
601
|
+
throw new BridgeCommandException("E_TYPE_NOT_FOUND", "Type not found: " + typeName, "Pass a full type name.");
|
|
602
|
+
}
|
|
603
|
+
var candidate = ResolveCallMethod(type, methodName, argsValue, parameterTypes, bindings, budget);
|
|
604
|
+
RequireSynchronousResult(candidate.Method, budget);
|
|
605
|
+
var arguments = ResolveCallArguments(argsValue, candidate.Parameters, budget);
|
|
253
606
|
object instance = null;
|
|
254
|
-
if (!
|
|
607
|
+
if (!candidate.Method.IsStatic)
|
|
255
608
|
{
|
|
256
|
-
instance = ResolveCallInstance(instanceRef, type);
|
|
609
|
+
instance = ResolveCallInstance(instanceRef, type, budget);
|
|
257
610
|
if (instance == null) throw new BridgeCommandException("E_METHOD_INSTANCE_REQUIRED", "Instance method " + methodName + " requires an instance reference.", "Pass instanceRef with instanceId/assetPath/path.");
|
|
258
611
|
}
|
|
259
|
-
|
|
612
|
+
PrebudgetInvocationResult(type, candidate.Method, candidate.Parameters, budget);
|
|
613
|
+
return new PreparedMethodCall { Type = type, Method = candidate.Method, Parameters = candidate.Parameters, Arguments = arguments, Instance = instance };
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/// <summary>effect 前为固定审计外壳和参数回读保留最低容量,避免确定可知的 post-effect 预算失败。</summary>
|
|
617
|
+
private static void PrebudgetInvocationResult(Type type, MethodInfo method, ParameterInfo[] parameters, UnityCliRequestBudget budget)
|
|
618
|
+
{
|
|
619
|
+
budget.CheckpointOrThrow();
|
|
620
|
+
var minimumNodes = checked(1L + parameters.Length);
|
|
621
|
+
if (budget.RemainingNodes < minimumNodes) throw new UnityCliRequestBudgetExceededException("nodes");
|
|
622
|
+
if (budget.RemainingGetters < parameters.Length) throw new UnityCliRequestBudgetExceededException("getters");
|
|
623
|
+
if (budget.RemainingReflectionCalls < parameters.Length) throw new UnityCliRequestBudgetExceededException("reflectionCalls");
|
|
624
|
+
var fixedBytes = 512L + checked((long)parameters.Length * 256L);
|
|
625
|
+
if (!budget.TryReserveSerializedUtf8(type.FullName)
|
|
626
|
+
|| !budget.TryReserveSerializedUtf8(method.Name)
|
|
627
|
+
|| !budget.TryReserveSerializedUtf8(method.ReturnType.FullName)
|
|
628
|
+
|| !budget.TryReserveSerializedUtf8Bytes(fixedBytes))
|
|
629
|
+
throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension ?? "serializedUtf8Bytes");
|
|
260
630
|
}
|
|
261
631
|
|
|
262
632
|
/// <summary>跨 effect barrier 后只执行一次已准备的方法并返回审计值树。</summary>
|
|
263
|
-
public static Dictionary<string, object> InvokePrepared(PreparedMethodCall call)
|
|
633
|
+
public static Dictionary<string, object> InvokePrepared(PreparedMethodCall call, UnityCliRequestBudget budget)
|
|
264
634
|
{
|
|
265
635
|
if (call == null) throw new ArgumentNullException("call");
|
|
636
|
+
if (budget == null) throw new ArgumentNullException("budget");
|
|
266
637
|
var data = new Dictionary<string, object>
|
|
267
638
|
{
|
|
268
639
|
{ "typeName", call.Type.FullName }, { "methodName", call.Method.Name },
|
|
@@ -273,8 +644,8 @@ namespace UnityCli
|
|
|
273
644
|
var result = call.Method.Invoke(call.Instance, call.Arguments);
|
|
274
645
|
if (result is System.Threading.Tasks.Task || result is IEnumerator || result is AsyncOperation || result is CustomYieldInstruction)
|
|
275
646
|
throw new BridgeCommandException("E_METHOD_COMPLETION_UNPROVABLE", "The method returned an asynchronous/yield operation that has no immediate completion proof.", "Use a dedicated Tool with an explicit asynchronous completion predicate.");
|
|
276
|
-
data["result"] = BuildCallResult(result);
|
|
277
|
-
data["parameters"] = call.Parameters.Select((parameter, index) => (object)new Dictionary<string, object> { { "name", parameter.Name }, { "value", BuildCallResult(call.Arguments[index]) } }).ToList();
|
|
647
|
+
data["result"] = BuildCallResult(result, budget);
|
|
648
|
+
data["parameters"] = call.Parameters.Select((parameter, index) => (object)new Dictionary<string, object> { { "name", parameter.Name }, { "value", BuildCallResult(call.Arguments[index], budget) } }).ToList();
|
|
278
649
|
}
|
|
279
650
|
catch (TargetInvocationException tie)
|
|
280
651
|
{
|
|
@@ -286,6 +657,8 @@ namespace UnityCli
|
|
|
286
657
|
new[] { "Inspect the method contract and arguments before submitting a new request." });
|
|
287
658
|
}
|
|
288
659
|
catch (BridgeCommandException) { throw; }
|
|
660
|
+
catch (UnityCliRequestBudgetExceededException) { throw; }
|
|
661
|
+
catch (OperationCanceledException) { throw; }
|
|
289
662
|
catch (Exception exception)
|
|
290
663
|
{
|
|
291
664
|
throw new BridgeCommandException(
|
|
@@ -298,8 +671,9 @@ namespace UnityCli
|
|
|
298
671
|
}
|
|
299
672
|
|
|
300
673
|
/// <summary>completionProbe 只允许同步方法;void 由内部 observer 的 fresh after proof 覆盖。</summary>
|
|
301
|
-
private static void RequireSynchronousResult(MethodInfo method)
|
|
674
|
+
private static void RequireSynchronousResult(MethodInfo method, UnityCliRequestBudget budget)
|
|
302
675
|
{
|
|
676
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
303
677
|
var returnType = method.ReturnType;
|
|
304
678
|
var fullName = returnType.FullName ?? string.Empty;
|
|
305
679
|
if (typeof(System.Threading.Tasks.Task).IsAssignableFrom(returnType)
|
|
@@ -315,39 +689,49 @@ namespace UnityCli
|
|
|
315
689
|
}
|
|
316
690
|
|
|
317
691
|
// 参数可为位置数组或按参数名索引的对象;值转换复用 ObjectPatch 的 typed conversion。
|
|
318
|
-
/// <summary
|
|
319
|
-
private static
|
|
692
|
+
/// <summary>按 raw declared-method ordinal 流式筛选;候选、参数和签名都有硬上限。</summary>
|
|
693
|
+
private static CallCandidate ResolveCallMethod(Type type, string methodName, object argsValue, List<string> parameterTypeNames, BindingFlags bindings, UnityCliRequestBudget budget)
|
|
320
694
|
{
|
|
321
|
-
var
|
|
322
|
-
|
|
323
|
-
.ToList();
|
|
324
|
-
if (candidates.Count == 0)
|
|
325
|
-
{
|
|
326
|
-
throw new BridgeCommandException("E_METHOD_NOT_FOUND", "Method not found: " + type.FullName + "." + methodName,
|
|
327
|
-
"Run reflection.method.find to discover available methods.");
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if (parameterTypeNames != null && parameterTypeNames.Count > 0)
|
|
695
|
+
var selectedParameterTypes = new List<Type>();
|
|
696
|
+
if (parameterTypeNames != null)
|
|
331
697
|
{
|
|
332
|
-
var parameterTypes = new List<Type>();
|
|
333
698
|
foreach (var parameterTypeName in parameterTypeNames)
|
|
334
699
|
{
|
|
335
|
-
var parameterType = TypeSchemaGenerator.ResolveType(parameterTypeName);
|
|
700
|
+
var parameterType = TypeSchemaGenerator.ResolveType(parameterTypeName, budget);
|
|
336
701
|
if (parameterType == null)
|
|
337
702
|
{
|
|
338
|
-
throw new
|
|
339
|
-
|
|
703
|
+
if (budget.IsExhausted) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
704
|
+
throw new BridgeCommandException("E_TYPE_NOT_FOUND", "Parameter type not found: " + parameterTypeName, "Use the full parameterType returned by reflection.method.find.");
|
|
340
705
|
}
|
|
341
|
-
|
|
706
|
+
selectedParameterTypes.Add(parameterType);
|
|
342
707
|
}
|
|
343
|
-
candidates = candidates.Where(method => method.GetParameters().Select(parameter => parameter.ParameterType).SequenceEqual(parameterTypes)).ToList();
|
|
344
708
|
}
|
|
345
|
-
|
|
709
|
+
var argumentCount = argsValue is List<object> positional ? positional.Count : argsValue is Dictionary<string, object> named ? named.Count : 0;
|
|
710
|
+
var candidates = new List<CallCandidate>();
|
|
711
|
+
var examinedMethods = 0;
|
|
712
|
+
var depth = 0;
|
|
713
|
+
for (var current = type; current != null; current = current.BaseType)
|
|
346
714
|
{
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
715
|
+
if (depth++ >= MaximumCallTypeHierarchyDepth) throw new UnityCliRequestBudgetExceededException("reflectionCalls");
|
|
716
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
717
|
+
foreach (var method in UnityCliReflectionSnapshot.DeclaredMethods(current, budget, MaximumExaminedCallMethods))
|
|
718
|
+
{
|
|
719
|
+
if (examinedMethods++ >= MaximumExaminedCallMethods) throw new UnityCliRequestBudgetExceededException("scannedRecords");
|
|
720
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
721
|
+
if (!MethodMatchesBindings(method, bindings, current == type) || !string.Equals(method.Name, methodName, StringComparison.Ordinal) || method.ContainsGenericParameters) continue;
|
|
722
|
+
if (!budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
723
|
+
var parameters = method.GetParameters();
|
|
724
|
+
if (parameters.Length > MaximumCallParameters) throw new UnityCliRequestBudgetExceededException("reflectionCalls");
|
|
725
|
+
var matches = selectedParameterTypes.Count > 0 ? parameters.Length == selectedParameterTypes.Count : parameters.Length == argumentCount;
|
|
726
|
+
for (var index = 0; index < parameters.Length; index++)
|
|
727
|
+
{
|
|
728
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
729
|
+
if (selectedParameterTypes.Count > 0 && parameters[index].ParameterType != selectedParameterTypes[index]) matches = false;
|
|
730
|
+
}
|
|
731
|
+
if (!matches) continue;
|
|
732
|
+
if (candidates.Count >= MaximumMatchingCallMethods) throw new UnityCliRequestBudgetExceededException("scannedRecords");
|
|
733
|
+
candidates.Add(new CallCandidate(method, parameters));
|
|
734
|
+
}
|
|
351
735
|
}
|
|
352
736
|
|
|
353
737
|
if (candidates.Count == 1) return candidates[0];
|
|
@@ -358,13 +742,30 @@ namespace UnityCli
|
|
|
358
742
|
new[] { "Run reflection.method.find and pass the returned parameterType values as parameterTypes." });
|
|
359
743
|
}
|
|
360
744
|
|
|
361
|
-
var signatures =
|
|
745
|
+
var signatures = new List<string>();
|
|
746
|
+
var signatureBytes = 0;
|
|
747
|
+
foreach (var candidate in candidates)
|
|
748
|
+
{
|
|
749
|
+
var parameterNames = new string[candidate.Parameters.Length];
|
|
750
|
+
for (var index = 0; index < candidate.Parameters.Length; index++) parameterNames[index] = candidate.Parameters[index].ParameterType.FullName;
|
|
751
|
+
var signature = candidate.Method.Name + "(" + string.Join(",", parameterNames) + ")";
|
|
752
|
+
signatureBytes += Encoding.UTF8.GetByteCount(signature);
|
|
753
|
+
if (signatureBytes > MaximumCallSignatureUtf8Bytes || !budget.TryReserveSerializedUtf8(signature)) throw new UnityCliRequestBudgetExceededException("serializedUtf8Bytes");
|
|
754
|
+
signatures.Add(signature);
|
|
755
|
+
}
|
|
362
756
|
throw new BridgeCommandException("E_METHOD_AMBIGUOUS", "Multiple overloads match: " + type.FullName + "." + methodName,
|
|
363
757
|
new Dictionary<string, object> { { "typeName", type.FullName }, { "methodName", methodName }, { "candidateSignatures", signatures } },
|
|
364
758
|
new[] { "Run reflection.method.find and pass one returned signature's parameterType values as parameterTypes." });
|
|
365
759
|
}
|
|
366
760
|
|
|
367
|
-
private static
|
|
761
|
+
private static bool MethodMatchesBindings(MethodInfo method, BindingFlags bindings, bool declaredOnTarget)
|
|
762
|
+
{
|
|
763
|
+
if (method.IsStatic && (bindings & BindingFlags.Static) == 0 || !method.IsStatic && (bindings & BindingFlags.Instance) == 0) return false;
|
|
764
|
+
if (method.IsPublic && (bindings & BindingFlags.Public) == 0 || !method.IsPublic && (bindings & BindingFlags.NonPublic) == 0) return false;
|
|
765
|
+
return declaredOnTarget || !method.IsPrivate;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
private static object[] ResolveCallArguments(object argsValue, ParameterInfo[] parameters, UnityCliRequestBudget budget)
|
|
368
769
|
{
|
|
369
770
|
if (parameters.Length == 0) return new object[0];
|
|
370
771
|
var parsed = argsValue as List<object> ?? new List<object>();
|
|
@@ -372,6 +773,7 @@ namespace UnityCli
|
|
|
372
773
|
var result = new object[parameters.Length];
|
|
373
774
|
for (var i = 0; i < parameters.Length; i++)
|
|
374
775
|
{
|
|
776
|
+
if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeReflectionCall()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
375
777
|
var parameter = parameters[i];
|
|
376
778
|
object value = null;
|
|
377
779
|
if (objForm != null && objForm.ContainsKey(parameter.Name)) value = objForm[parameter.Name];
|
|
@@ -383,7 +785,7 @@ namespace UnityCli
|
|
|
383
785
|
return result;
|
|
384
786
|
}
|
|
385
787
|
|
|
386
|
-
private static object ResolveCallInstance(Dictionary<string, object> instanceRef, Type expectedType)
|
|
788
|
+
private static object ResolveCallInstance(Dictionary<string, object> instanceRef, Type expectedType, UnityCliRequestBudget budget)
|
|
387
789
|
{
|
|
388
790
|
if (instanceRef == null) return null;
|
|
389
791
|
if (instanceRef.TryGetValue("instanceId", out var iid))
|
|
@@ -391,30 +793,65 @@ namespace UnityCli
|
|
|
391
793
|
var id = Convert.ToInt32(iid, CultureInfo.InvariantCulture);
|
|
392
794
|
if (id != 0)
|
|
393
795
|
{
|
|
796
|
+
if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
394
797
|
var obj = EditorUtility.InstanceIDToObject(id);
|
|
395
798
|
if (obj != null && expectedType.IsInstanceOfType(obj)) return obj;
|
|
396
799
|
}
|
|
397
800
|
}
|
|
398
801
|
if (instanceRef.TryGetValue("assetPath", out var ap) && ap is string path)
|
|
399
802
|
{
|
|
803
|
+
if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
400
804
|
var obj = AssetDatabase.LoadMainAssetAtPath(path);
|
|
401
805
|
if (obj != null && expectedType.IsInstanceOfType(obj)) return obj;
|
|
402
806
|
}
|
|
403
807
|
if (instanceRef.TryGetValue("path", out var p) && p is string goPath && typeof(Component).IsAssignableFrom(expectedType))
|
|
404
808
|
{
|
|
405
|
-
var
|
|
406
|
-
|
|
809
|
+
var reference = new ReflectionInstanceReference { Path = goPath };
|
|
810
|
+
var go = ObjectRefResolver.ResolveGameObject(reference, budget);
|
|
811
|
+
if (go != null)
|
|
812
|
+
{
|
|
813
|
+
if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
|
|
814
|
+
return go.GetComponent(expectedType);
|
|
815
|
+
}
|
|
407
816
|
}
|
|
408
817
|
return null;
|
|
409
818
|
}
|
|
410
819
|
|
|
411
|
-
private
|
|
820
|
+
private sealed class CallCandidate
|
|
821
|
+
{
|
|
822
|
+
internal readonly MethodInfo Method;
|
|
823
|
+
internal readonly ParameterInfo[] Parameters;
|
|
824
|
+
|
|
825
|
+
internal CallCandidate(MethodInfo method, ParameterInfo[] parameters)
|
|
826
|
+
{
|
|
827
|
+
Method = method;
|
|
828
|
+
Parameters = parameters;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
private sealed class ReflectionInstanceReference : IUnityCliObjectReferenceInput
|
|
833
|
+
{
|
|
834
|
+
public int? InstanceId { get { return null; } }
|
|
835
|
+
public string AssetPath { get { return null; } }
|
|
836
|
+
public string Guid { get { return null; } }
|
|
837
|
+
public string Path { get; set; }
|
|
838
|
+
public string Name { get { return null; } }
|
|
839
|
+
public string Target { get { return null; } }
|
|
840
|
+
public int? ComponentInstanceId { get { return null; } }
|
|
841
|
+
public int? ComponentIndex { get { return null; } }
|
|
842
|
+
public string Component { get { return null; } }
|
|
843
|
+
public string ComponentType { get { return null; } }
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
private static object BuildCallResult(object result, UnityCliRequestBudget budget)
|
|
412
847
|
{
|
|
413
848
|
if (result == null) return null;
|
|
414
849
|
try
|
|
415
850
|
{
|
|
416
|
-
return ObjectSerializer.Serialize(result, new ObjectSerializer.Options { MaxDepth = 2, IncludeFields = false, IncludeProperties = true, DeepSerialization = false });
|
|
851
|
+
return ObjectSerializer.Serialize(result, new ObjectSerializer.Options { MaxDepth = 2, IncludeFields = false, IncludeProperties = true, DeepSerialization = false }, budget);
|
|
417
852
|
}
|
|
853
|
+
catch (UnityCliRequestBudgetExceededException) { throw; }
|
|
854
|
+
catch (OperationCanceledException) { throw; }
|
|
418
855
|
catch (Exception exception)
|
|
419
856
|
{
|
|
420
857
|
// 反射返回值不可投影时显式暴露原因,不能 ToString() 制造不稳定业务数据。
|
|
@@ -431,6 +868,8 @@ namespace UnityCli
|
|
|
431
868
|
public bool IsPrivate { get; set; }
|
|
432
869
|
public string ReturnType { get; set; }
|
|
433
870
|
public string DeclaringType { get; set; }
|
|
871
|
+
public long ParameterCount { get; set; }
|
|
872
|
+
public bool ParametersTruncated { get; set; }
|
|
434
873
|
public List<ReflectionParameterDescriptor> Parameters { get; set; }
|
|
435
874
|
}
|
|
436
875
|
|
|
@@ -473,5 +912,77 @@ namespace UnityCli
|
|
|
473
912
|
return null;
|
|
474
913
|
}
|
|
475
914
|
}
|
|
915
|
+
|
|
916
|
+
/// <summary>先冻结带硬上限的反射集合,再允许调用方逐项计费或分页。</summary>
|
|
917
|
+
internal static class UnityCliReflectionSnapshot
|
|
918
|
+
{
|
|
919
|
+
internal static FieldInfo[] DeclaredFields(Type type, UnityCliRequestBudget budget, int maximum)
|
|
920
|
+
{
|
|
921
|
+
if (type == null) throw new ArgumentNullException("type");
|
|
922
|
+
budget.CheckpointOrThrow();
|
|
923
|
+
var items = type.GetTypeInfo().DeclaredFields.ToArray();
|
|
924
|
+
EnsureBounded(items.Length, maximum);
|
|
925
|
+
return items;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
internal static PropertyInfo[] DeclaredProperties(Type type, UnityCliRequestBudget budget, int maximum)
|
|
929
|
+
{
|
|
930
|
+
if (type == null) throw new ArgumentNullException("type");
|
|
931
|
+
budget.CheckpointOrThrow();
|
|
932
|
+
var items = type.GetTypeInfo().DeclaredProperties.ToArray();
|
|
933
|
+
EnsureBounded(items.Length, maximum);
|
|
934
|
+
return items;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
internal static MethodInfo[] DeclaredMethods(Type type, UnityCliRequestBudget budget, int maximum)
|
|
938
|
+
{
|
|
939
|
+
if (type == null) throw new ArgumentNullException("type");
|
|
940
|
+
budget.CheckpointOrThrow();
|
|
941
|
+
var items = type.GetTypeInfo().DeclaredMethods.ToArray();
|
|
942
|
+
EnsureBounded(items.Length, maximum);
|
|
943
|
+
return items;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
internal static MethodInfo[] Methods(Type type, BindingFlags bindings, UnityCliRequestBudget budget, int maximum)
|
|
947
|
+
{
|
|
948
|
+
if (type == null) throw new ArgumentNullException("type");
|
|
949
|
+
budget.CheckpointOrThrow();
|
|
950
|
+
var items = type.GetMethods(bindings);
|
|
951
|
+
EnsureBounded(items.Length, maximum);
|
|
952
|
+
return items;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
internal static Type[] Interfaces(Type type, UnityCliRequestBudget budget, int maximum)
|
|
956
|
+
{
|
|
957
|
+
if (type == null) throw new ArgumentNullException("type");
|
|
958
|
+
budget.CheckpointOrThrow();
|
|
959
|
+
var items = type.GetInterfaces();
|
|
960
|
+
EnsureBounded(items.Length, maximum);
|
|
961
|
+
return items;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
internal static Type[] GenericArguments(Type type, UnityCliRequestBudget budget, int maximum)
|
|
965
|
+
{
|
|
966
|
+
if (type == null) throw new ArgumentNullException("type");
|
|
967
|
+
budget.CheckpointOrThrow();
|
|
968
|
+
var items = type.GetGenericArguments();
|
|
969
|
+
EnsureBounded(items.Length, maximum);
|
|
970
|
+
return items;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
internal static string[] EnumNames(Type type, UnityCliRequestBudget budget, int maximum)
|
|
974
|
+
{
|
|
975
|
+
if (type == null) throw new ArgumentNullException("type");
|
|
976
|
+
budget.CheckpointOrThrow();
|
|
977
|
+
var items = Enum.GetNames(type);
|
|
978
|
+
EnsureBounded(items.Length, maximum);
|
|
979
|
+
return items;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
private static void EnsureBounded(int count, int maximum)
|
|
983
|
+
{
|
|
984
|
+
if (maximum < 0 || count > maximum) throw new UnityCliRequestBudgetExceededException("nodes");
|
|
985
|
+
}
|
|
986
|
+
}
|
|
476
987
|
}
|
|
477
988
|
#endif
|